概要
JBL GO2音响无音频十分钟左右时,自动关机。
情况基本就是下面第二点:
解决:制作音响巡检软件防关机,定期(目前设置5s)监测电脑扬声器状态,周期判断(周期可设置)内是否有声音在播放,若系统有在播放则工具不播放语音(音量可设置),反之工具播放语音。附加:扬声器日志输出,关闭时先隐藏到托盘图标。
代码实现
窗体类+三个工具类(语音、定时器、扬声器)
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
namespace 后台声音操作
{
public partial class Form1 : Form
{
Speech_Device _speechDevice;
System_Timers_Timer system_Timers_Timer;
DateTime _lastUpdateTime = DateTime.MinValue;
private bool _autoPlayFlag;
private int _perionSeconds;
public Form1()
{
InitializeComponent();
// 初始化托盘图标
InitializeTrayIcon();
// 初始化语音合成器
InitSpeech();
// 初始化定时器+监测扬声器状态
InitTimerWithStatus();
}
private void InitSpeech()
{
_speechDevice = new Speech_Device();
// 初始化周期
this._perionSeconds = (int)this.perionUpDown.Value * 60;
}
private void btnPlay_Click(object sender, EventArgs e)
{
// 将文本转换为语音并播放
_speechDevice.Play(this.richTextBox1.Text);
}
private void btnPlayAuto_Click(object sender, EventArgs e)
{
// 将文本转换为语音并定期判断播放
this.btnPalyAuto.Text = this.btnPalyAuto.Text.Equals("定期播放") ? "取消定期播放" : "定期播放";
this._autoPlayFlag = this._autoPlayFlag ? false : true;
this._lastUpdateTime = DateTime.Now;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
// 关闭
_speechDevice.Stop();
system_Timers_Timer.Stop();
base.OnFormClosing(e);
}
private void InitTimerWithStatus()
{
system_Timers_Timer = new System_Timers_Timer(new Action<object, ElapsedEventArgs>((s, e) =>
{
Task.Run(() =>
{
(bool, List<string>) statusAndText = Voice_Device.GetStatus();
//子线程才可以使用音量设备
List<string> audioInfos = statusAndText.Item2;
this.logBox?.Invoke(new Action(() =>
{
this.logBox.Items.Add(DateTime.Now.ToString("HH:mm:ss"));
this.logBox.Items.AddRange(audioInfos.ToArray());
//超过50条日志时 重新记录
if (this.logBox.Items.Count > 50) { this.logBox.Items.Clear(); }
//扬声器有声音时,刷新更新时间
this._lastUpdateTime = statusAndText.Item1 ? DateTime.Now : this._lastUpdateTime;
//扬声器周期内没声音,播报一次
if (_autoPlayFlag && Math.Abs((this._lastUpdateTime - DateTime.Now).TotalSeconds) > this._perionSeconds) { this._lastUpdateTime = DateTime.Now; _speechDevice.Play(this.richTextBox1.Text); }
}));
});
}));
system_Timers_Timer.Start(5000);
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
// 更新 NumericUpDown 控件的值
this.voiceUpDown.Value = this.voiceBar.Value;
_speechDevice.Edit_VolumeAndRate(this.voiceBar.Value);
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
// 更新 TrackBar 控件的位置
this.voiceBar.Value = (int)this.voiceUpDown.Value;
_speechDevice.Edit_VolumeAndRate(this.voiceBar.Value);
}
private void numericUpDown2_ValueChanged(object sender, EventArgs e)
{
// 更新周期
this._perionSeconds = (int)this.perionUpDown.Value * 60;
}
#region 隐藏到图标
//系统托盘图标
private NotifyIcon TrayIcon;
private void InitializeTrayIcon()
{
this.Text = "音响巡检工具";
this.Icon = Icon.ExtractAssociatedIcon("favicon.ico");
this.FormClosing += OnFormClosing;
TrayIcon = new NotifyIcon()
{
Icon = SystemIcons.Asterisk,
Visible = true,
ContextMenu = new ContextMenu(new MenuItem[] {
new MenuItem("退出", Exit) //右键小菜单
})
};
TrayIcon.Icon = Icon.ExtractAssociatedIcon("favicon.ico");
TrayIcon.Text = "音响巡检工具";
TrayIcon.Click += TrayIcon_Click;
}
protected void OnFormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
this.Hide();
}
}
private void TrayIcon_Click(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Normal;
this.Show();
}
private void Exit(object sender, EventArgs e)
{
TrayIcon.Visible = false;
System.Windows.Forms.Application.Exit();
}
#endregion
}
}
Speech_Device.cs
using System.Speech.Synthesis;
namespace 后台声音操作
{
/// <summary>
/// 语音播放工具
/// </summary>
public class Speech_Device
{
private SpeechSynthesizer _synthesizer;
int _volume = 10;
int _rate = 0;
public Speech_Device()
{
_synthesizer = new SpeechSynthesizer();
// 选择中文语音
_synthesizer.SelectVoiceByHints(VoiceGender.NotSet, VoiceAge.Adult, 0, new System.Globalization.CultureInfo("zh-CN"));
}
public void Edit_VolumeAndRate(int volume, int rate = 0)
{
this._volume = volume;
this._rate = rate;
}
public void Play(string text)
{
// 设置音量和语速
_synthesizer.Volume = this._volume;
_synthesizer.Rate = this._rate;
// 将文本转换为语音并播放
_synthesizer.SpeakAsync(text);
}
public void Stop()
{
// 关闭语音合成器
_synthesizer?.Dispose();
}
}
}
System_Timers_Timer.cs
using System;
using System.Timers;
namespace 后台声音操作
{
/// <summary>
/// 定时器工具
/// </summary>
internal class System_Timers_Timer
{
Timer _timer = new Timer();
public System_Timers_Timer(Action<object,ElapsedEventArgs> action)
{
//定时执行的任务
ElapsedEventHandler elapsedEventHandler = new ElapsedEventHandler(action);
_timer.Elapsed += elapsedEventHandler;
}
public void Start(double Interval)
{
_timer.Interval = Interval;
_timer.Start();
}
public void Stop()
{
_timer?.Stop();
_timer?.Dispose();
}
}
}
Voice_Device.cs
using CSCore.CoreAudioAPI;
using System;
using System.Collections.Generic;
namespace 后台声音操作
{
/// <summary>
/// 扬声器工具
/// </summary>
class Voice_Device
{
public static (bool, List<string>) GetStatus()
{
bool hasVoice = false;
List<string> audioInfos = new List<string>();
using (var sessionManager = GetDefaultAudioSessionManager2(DataFlow.Render))
{
using (var sessionEnumerator = sessionManager.GetSessionEnumerator())
{
foreach (var session in sessionEnumerator)
{
using (var audioSessionControl2 = session.QueryInterface<AudioSessionControl2>())
{
var process = audioSessionControl2.Process;
using (var audioMeterInformation = session.QueryInterface<AudioMeterInformation>())
{
var value = audioMeterInformation.GetPeakValue();
if (process != null)
{
var val = audioMeterInformation.GetPeakValue();
/*//打印应用音量
Console.WriteLine("Pid:{0},应用: {1},播放信息:{2},音量:{3}",
audioSessionControl2.ProcessID,
process.ProcessName,
process.MainWindowTitle,
val);*/
string audioInfo = string.Format("Pid:{0},应用: {1},播放信息:{2},音量:{3}",
audioSessionControl2.ProcessID,
process.ProcessName,
process.MainWindowTitle,
val);
audioInfos.Add(audioInfo);
if (val != 0) { hasVoice = true; }
}
}
}
}
}
}
return (hasVoice, audioInfos);
}
private static AudioSessionManager2 GetDefaultAudioSessionManager2(DataFlow dataFlow)
{
using (var enumerator = new MMDeviceEnumerator())
{
using (var device = enumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia))
{
Console.WriteLine("默认设备: " + device.FriendlyName);
var sessionManager = AudioSessionManager2.FromMMDevice(device);
return sessionManager;
}
}
}
}
}
效果
执行文件:
V1.1 修复隐藏到托盘再打开播放会报错的bug