测试环境:
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();
}
}
}
要上班了,代码就不解释了