Windows下监听音频对象增删:C#是否存在可挂钩事件?
当然有靠谱的解决方案!你之前靠检测进程来追踪音量对象的思路确实容易踩坑——毕竟音频会话(也就是你说的「音量对象」)往往比进程创建晚一步,时间差问题会导致漏检。在C#里,我们可以直接监听Windows原生的Core Audio事件,完美解决这个问题。
在C#中监听Windows音频对象的添加/移除事件
核心思路是借助Windows的Core Audio API,它原生提供了音频会话的生命周期事件监听能力。为了简化C#中的调用,推荐使用成熟的.NET音频库NAudio,它已经封装了Core Audio的底层接口,不用自己写复杂的COM互操作代码。
一、快速实现步骤
1. 安装NAudio库
通过NuGet包管理器安装,或者在Package Manager Console中执行:
Install-Package NAudio
它支持.NET Framework、.NET Core及后续版本,兼容性拉满。
2. 编写监听代码示例
下面的代码可以直接监听音频会话的创建(对应音量对象添加)、销毁(对应音量对象移除),还能一次性获取当前所有活跃的音量对象列表(和Windows音量混合器一致):
using NAudio.CoreAudioApi; using NAudio.CoreAudioApi.Interfaces; using System; public class AudioSessionMonitor : IAudioSessionNotification { private AudioSessionManager2 _sessionManager; // 启动监听 public void StartMonitoring() { var deviceEnumerator = new MMDeviceEnumerator(); // 获取系统默认的播放设备(也可以指定其他设备) var defaultPlaybackDevice = deviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia); // 激活音频会话管理器 _sessionManager = defaultPlaybackDevice.Activate( typeof(IAudioSessionManager2).GUID, CLSCTX.CLSCTX_ALL, null) as AudioSessionManager2; if (_sessionManager != null) { // 注册会话创建事件监听 _sessionManager.RegisterSessionNotification(this); Console.WriteLine("已启动音频会话监听..."); // 先获取当前所有活跃的音量对象 PrintCurrentSessions(); } } // 停止监听并释放资源 public void StopMonitoring() { _sessionManager?.UnregisterSessionNotification(this); _sessionManager?.Dispose(); Console.WriteLine("已停止音频会话监听"); } // 监听新音频会话创建(音量对象添加) public void OnSessionCreated(IAudioSessionControl newSession) { var sessionControl = newSession as AudioSessionControl2; if (sessionControl != null && !sessionControl.IsSystemSoundsSession) { Console.WriteLine($"[新增音量对象] 进程名: {sessionControl.ProcessName} | PID: {sessionControl.ProcessId}"); // 可以直接获取该会话的音量、静音状态 var currentVolume = sessionControl.SimpleAudioVolume.Volume; Console.WriteLine($" 当前音量: {currentVolume:P} | 静音状态: {sessionControl.SimpleAudioVolume.Mute}"); // 额外注册会话销毁事件 sessionControl.OnSessionDisconnected += Session_OnSessionDisconnected; } } // 监听音频会话销毁(音量对象移除) private void Session_OnSessionDisconnected(object sender, SessionDisconnectedEventArgs e) { var sessionControl = sender as AudioSessionControl2; if (sessionControl != null) { Console.WriteLine($"[移除音量对象] 进程名: {sessionControl.ProcessName} | 原因: {e.DisconnectReason}"); } } // 打印当前所有活跃的音量对象(对应音量混合器列表) private void PrintCurrentSessions() { Console.WriteLine("\n当前活跃音量对象列表:"); var sessionEnumerator = _sessionManager.GetSessionEnumerator(); foreach (var session in sessionEnumerator) { var sessionControl = session as AudioSessionControl2; if (sessionControl != null && !sessionControl.IsSystemSoundsSession) { Console.WriteLine($"- {sessionControl.ProcessName} (PID: {sessionControl.ProcessId})"); } } Console.WriteLine("------------------------"); } } // 调用示例 class Program { static void Main(string[] args) { var monitor = new AudioSessionMonitor(); monitor.StartMonitoring(); Console.WriteLine("\n按任意键退出监听..."); Console.ReadKey(); monitor.StopMonitoring(); } }
二、方案优势
- 无时间差问题:直接监听音频系统的原生事件,不会出现进程已创建但音频会话还未生成的漏检情况。
- 信息完整:能获取音量对象的所有关键信息(进程名、PID、音量、静音状态等),完全匹配音量混合器的展示内容。
- 覆盖全面:可以捕获所有类型的音频会话,包括那些没有独立进程的系统级音频(可通过
IsSystemSoundsSession过滤)。
注意事项
- 不需要管理员权限,普通用户权限即可获取大部分音频会话信息。
- 记得在程序退出时调用
StopMonitoring释放资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Albert MN.
相关产品推荐
相关产品推荐

