winform实现托盘语音提醒

发布于:2024-10-11 ⋅ 阅读:(13) ⋅ 点赞:(0)

测试环境:

visual studio 2022

window 10

.net framework 4.6

本文实现的功能有:

1   托盘最小化

2   语音定时播放

3   检测到操作系统被客户点静音后,需要程序控制开启音量(在运行过程中,由于语音重复播放,客户很烦,就会点静音,后面搞了一个在客户点静音后,如果客户一直没处理问题,就在10分钟后重新开启音量播放音频)

4  连接sql server数据库,如果不需要可以把代码注释掉

步骤如下:

1 新增名为DrawerAudio的winfrom程序,默认带出的窗体重新命名为:DrawerAudio

2 nuget安装NAudio,版本选择1.9.0,如下图:

3 网上找一张icon的图片,重新命名为ico_audio.ico,并放到debug目录,接着网上找一个要播放的mp3音频,并重新命名为"发生药槽错误,请盘点变红的药槽.mp3"

4  App.config配置文件编辑如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
    </startup>
	<connectionStrings>
		<add name="Sql" connectionString="server=127.0.0.1;uid=sa;pwd=密码;database=sql server数据库名称"/>
	</connectionStrings>
	<appSettings>
		<add key="IsTest" value="0" />
		<add key="SetAudioVolume" value="60" />
		<add key="MuteMinute" value="10" />
	</appSettings>
</configuration>

IsTest为1为测试模式,0为正式运行模式

SetAudioValume是设置音量

MuteMinute为最小音量,为了客户把音量调得过小,小于该音量后,程序自动把音量调大

5 新建名为SqlHelper的类并编辑如下(需要添加System.Configuration.dll引用):

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DrawerAudio
{
    // Token: 0x02000003 RID: 3
    internal class SqlHelper
    {
        // Token: 0x06000004 RID: 4 RVA: 0x00002124 File Offset: 0x00000324
        public static string GetSqlConnectionString()
        {
            return System.Configuration.ConfigurationManager.ConnectionStrings["Sql"].ConnectionString;
        }

        // Token: 0x06000005 RID: 5 RVA: 0x0000214C File Offset: 0x0000034C
        public static IList<T> ExecuteDataTable<T>(string sqlText, params SqlParameter[] parameters) where T : class, new()
        {
            IList<T> result;
            using (SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlText, SqlHelper.GetSqlConnectionString()))
            {
                DataTable dataTable = new DataTable();
                sqlDataAdapter.SelectCommand.Parameters.AddRange(parameters);
                sqlDataAdapter.Fill(dataTable);
                IList<T> list = new List<T>();
                PropertyInfo[] properties = typeof(T).GetProperties();
                for (int i = 0; i < dataTable.Rows.Count; i++)
                {
                    T t = Activator.CreateInstance<T>();
                    foreach (PropertyInfo propertyInfo in properties)
                    {
                        propertyInfo.SetValue(t, dataTable.Rows[i][propertyInfo.Name], null);
                    }
                    list.Add(t);
                }
                result = list;
            }
            return result;
        }
    }
}

6  新建名为AudioHelper的类并编辑如下:

using NAudio.CoreAudioApi;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DrawerAudio
{
    public class AudioHelper
    {
        private static bool IsPlaying = false;
        private static WaveOut waveOut;
        private static Mp3FileReader reader;
        private static string audioName;
        private static object lockobj = new object();

        public static bool Init(string audioName)
        {
            AudioHelper.audioName = audioName;
            AudioHelper.IsPlaying = true;
            return true;
        }

        public static bool GetIsPalying()
        {    
            return IsPlaying;
        }

        public static bool CheckCanStart()
        {
            if (waveOut!=null&&waveOut.PlaybackState == PlaybackState.Playing)
            {
                return false;
            }
            return true;
        }

        public static void PlayAudio()
        {
            try
            {
                lock (lockobj)
                {
                    using (var ms = File.OpenRead(audioName))
                    {
                        using (reader = new Mp3FileReader(ms))
                        using (var wavStream = WaveFormatConversionStream.CreatePcmStream(reader))
                        using (var baStream = new BlockAlignReductionStream(wavStream))
                        using (waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
                        {
                            waveOut.Init(baStream);
                            waveOut.Play();
                            while (waveOut.PlaybackState == PlaybackState.Playing&& AudioHelper.GetIsPalying())
                            {
                                Thread.Sleep(100);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("异常信息:"+ex.Message);
            }
        }

        public static bool StopPlay()
        {
            try
            {
                if (waveOut != null)
                {
                    IsPlaying = false;
                    waveOut.Stop();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("停止错误:"+ex.Message);
            }
            return true;
        }

        /// <summary>
        /// 获取当前音量
        /// </summary>
        /// <returns></returns>
        public  static int GetCurrentSpeakerVolume()
        {
            int volume = 0;
            var enumerator = new MMDeviceEnumerator();

            //获取音频输出设备
            IEnumerable<MMDevice> speakDevices = enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active).ToArray();
            if (speakDevices.Count() > 0)
            {
                MMDevice mMDevice = speakDevices.ToList()[0];
                volume = Convert.ToInt16(mMDevice.AudioEndpointVolume.MasterVolumeLevelScalar * 100);
            }
            return volume;
        }

        public static void  SetCurrentSpeakerVolume(int volume)
        {
            var enumerator = new MMDeviceEnumerator();
            IEnumerable<MMDevice> speakDevices = enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active).ToArray();
            if (speakDevices.Count() > 0)
            {
                MMDevice mMDevice = speakDevices.ToList()[0];
                mMDevice.AudioEndpointVolume.MasterVolumeLevelScalar = volume / 100.0f;
            }
        }

        /// <summary>
        /// 检测是否是静音
        /// </summary>
        /// <returns></returns>
        public static bool CheckIsNoNoise()
        {
            var enumerator = new MMDeviceEnumerator();
            IEnumerable<MMDevice> speakDevices = enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active).ToArray();
            MMDevice mMDevice = speakDevices.ToList()[0];
            return mMDevice.AudioEndpointVolume.Mute;
        }
        /// <summary>
        /// 关闭静音
        /// </summary>
        public static void CloseNoNoise()
        {
            var enumerator = new MMDeviceEnumerator();
            IEnumerable<MMDevice> speakDevices = enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active).ToArray();
            MMDevice mMDevice = speakDevices.ToList()[0];
            mMDevice.AudioEndpointVolume.Mute = false;
        }
    }
}

7  新建Model目录,并新建名为DrawerModel的类,并编辑如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DrawerAudio.Model
{
    // Token: 0x02000004 RID: 4
    public class DrawerModel
    {
        // Token: 0x17000001 RID: 1
        // (get) Token: 0x06000007 RID: 7 RVA: 0x00002245 File Offset: 0x00000445
        // (set) Token: 0x06000006 RID: 6 RVA: 0x0000223C File Offset: 0x0000043C
        public int IdDrawer { get; set; }

        // Token: 0x17000002 RID: 2
        // (get) Token: 0x06000009 RID: 9 RVA: 0x00002256 File Offset: 0x00000456
        // (set) Token: 0x06000008 RID: 8 RVA: 0x0000224D File Offset: 0x0000044D
        public int IdProduct { get; set; }
    }
}

8 编辑FrmMain如下:

using DrawerAudio.Model;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DrawerAudio
{
    public partial class FrmMain : Form
    {
        bool isTest = ConfigurationManager.AppSettings["IsTest"].Equals("1");
        int audioVolume = Convert.ToInt32(ConfigurationManager.AppSettings["SetAudioVolume"]);
        //静音的分钟数
        int muteMinute= Convert.ToInt32(ConfigurationManager.AppSettings["MuteMinute"]);
        const int WM_SYSCOMMAND = 0x112;
        const int SC_MINIMIZE = 0xF020;
        Thread audioThread = null;
        int secondCount = 0;
        public FrmMain()
        {
            InitializeComponent();
            this.WindowState = FormWindowState.Minimized;
            this.ShowInTaskbar = false;
            this.Load += FrmMain_Load;
            audioThread = new Thread(StartAudio);
            audioThread.IsBackground=true;
            AudioHelper.Init("发生药槽错误,请盘点变红的药槽.mp3");
            audioThread.Start();
            System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
            timer.Interval = 1000;
            timer.Tick += Timer_Tick;
            timer.Start();
        }
        private const int CP_NOCLOSE_BUTTON = 0x200;
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams myCp = base.CreateParams;
                myCp.ClassStyle = myCp.ClassStyle | CP_NOCLOSE_BUTTON;
                return myCp;
            }
        }
        private void Timer_Tick(object sender, EventArgs e)
        {
            int currentVlume=AudioHelper.GetCurrentSpeakerVolume();
            if (currentVlume < 20)
            {
                AudioHelper.SetCurrentSpeakerVolume(audioVolume);
                
            }
            if (AudioHelper.CheckIsNoNoise())
            {
                secondCount++;
                if (secondCount > (60 * muteMinute))
                {
                    secondCount = 0;
                    AudioHelper.CloseNoNoise();
                }
            }
            else
            {
                secondCount = 0;
            }

        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_SYSCOMMAND)
            {
                if (m.WParam.ToInt32() == SC_MINIMIZE)
                {
                    this.ShowInTaskbar = false;
                    this.WindowState= FormWindowState.Minimized;
                }
            }
            base.WndProc(ref m);
        }
        private void FrmMain_Load(object sender, EventArgs e)
        {
            //实例化一个NotifyIcon对象

            NotifyIcon notifyIcon = new NotifyIcon();

            //设置图标
            notifyIcon.Icon = new Icon("ico_audio.ico");
            //设置提示文本
            notifyIcon.Text = "药槽错误语音提醒";
            //设置双击托盘图标后显示窗体
            notifyIcon.DoubleClick += NotifyIcon_DoubleClick;
            //显示托盘
            notifyIcon.Visible = true;
        }

        private void NotifyIcon_DoubleClick(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Normal;
            this.ShowInTaskbar = true;
            this.Activate();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            AudioHelper.Init("发生药槽错误,请盘点变红的药槽.mp3");
            if (audioThread.ThreadState == (ThreadState.Background|ThreadState.Suspended))
            {
                audioThread.Resume();
            }
            else if(audioThread.ThreadState==(ThreadState.Background|ThreadState.Unstarted))
            {
                audioThread.Start();
            }
            MessageBox.Show("开始成功");
        }


        private void StartAudio()
        {
            while (true)
            {
                Thread.Sleep(500);
                if (!isTest)
                {
                    if (GetDrawerError())
                    {
                        if (AudioHelper.GetIsPalying() && AudioHelper.CheckCanStart())
                        {
                            AudioHelper.PlayAudio();
                        }
                    }
                }
                else
                {
                    if (AudioHelper.GetIsPalying() && AudioHelper.CheckCanStart())
                    {
                        AudioHelper.PlayAudio();
                    }
                }

            }
        }
        private bool GetDrawerError()
        {
            string sqlText = "select IdDrawer,IdProduct from 表名 where 条件";
            try
            {
                IList<DrawerModel> list = SqlHelper.ExecuteDataTable<DrawerModel>(sqlText, Array.Empty<SqlParameter>());
                if (list.Count > 0)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("查询失败,错误信息:" + ex.Message);
            }
            return false;
        }
        /// <summary>
        /// 停止按钮的逻辑,根据需要进行加入
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStop_Click(object sender, EventArgs e)
        {
            audioThread.Suspend();
            AudioHelper.StopPlay();
        }
    }
}

要上班了,代码就不解释了