如何通过ISimpleAudioVolume::SetMasterVolume调节特定应用音量及获取混音器应用列表
实现特定应用音量调节与混音器应用列表获取(Windows平台)
要实现调节特定应用音量、获取系统音量混音器中的应用列表,需要用到Windows核心音频API(Core Audio APIs),以下是基于C#的实现方案:
一、定义COM互操作接口
首先需要定义Core Audio相关的COM接口,用于和系统音频服务交互:
using System; using System.Runtime.InteropServices; [Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IAudioSessionManager2 { int GetSessionEnumerator(out IAudioSessionEnumerator SessionEnum); // 省略其他未用到的方法 } [Guid("E2F5BB11-0570-40CA-ACDD-3AA01277DEE8")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IAudioSessionEnumerator { int GetCount(out int SessionCount); int GetSession(int SessionIndex, out IAudioSessionControl2 Session); } [Guid("87CE5498-68D6-44E5-9215-6DA47EF883D8")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IAudioSessionControl2 { int GetDisplayName(out string pRetVal); int GetProcessId(out uint pRetVal); // 省略其他未用到的方法 } [Guid("87CE5498-68D6-44E5-9215-6DA47EF883D8")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface ISimpleAudioVolume { int SetMasterVolume(float fLevel, Guid EventContext); int GetMasterVolume(out float pfLevel); // 省略其他未用到的方法 } [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IMMDeviceEnumerator { int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice ppDevice); // 省略其他未用到的方法 } [Guid("D666063F-1587-4E43-81F1-B948E807363F")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IMMDevice { int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, out object ppInterface); // 省略其他未用到的方法 } internal enum EDataFlow { eRender, eCapture, eAll } internal enum ERole { eConsole, eMultimedia, eCommunications } [ComImport] [Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] internal class MMDeviceEnumeratorComObject { }
二、获取音量混音器中的应用列表
通过枚举音频会话,获取每个应用的名称、进程ID、当前音量等信息:
using System.Collections.Generic; public static List<AppAudioSession> GetAudioSessions() { var sessions = new List<AppAudioSession>(); IMMDeviceEnumerator enumerator = new MMDeviceEnumeratorComObject(); enumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out IMMDevice device); Guid sessionManagerGuid = typeof(IAudioSessionManager2).GUID; device.Activate(ref sessionManagerGuid, 0, IntPtr.Zero, out object obj); IAudioSessionManager2 sessionManager = (IAudioSessionManager2)obj; sessionManager.GetSessionEnumerator(out IAudioSessionEnumerator sessionEnum); sessionEnum.GetCount(out int count); for (int i = 0; i < count; i++) { sessionEnum.GetSession(i, out IAudioSessionControl2 sessionControl); sessionControl.GetDisplayName(out string appName); sessionControl.GetProcessId(out uint pid); // 获取当前音量 sessionControl.QueryInterface(typeof(ISimpleAudioVolume).GUID, out IntPtr volPtr); ISimpleAudioVolume volume = (ISimpleAudioVolume)Marshal.GetObjectForIUnknown(volPtr); volume.GetMasterVolume(out float currentVol); sessions.Add(new AppAudioSession { AppName = string.IsNullOrEmpty(appName) ? $"进程ID: {pid}" : appName, ProcessId = pid, CurrentVolume = currentVol * 100 }); Marshal.ReleaseComObject(sessionControl); Marshal.ReleaseComObject(volume); } Marshal.ReleaseComObject(sessionEnum); Marshal.ReleaseComObject(sessionManager); Marshal.ReleaseComObject(device); Marshal.ReleaseComObject(enumerator); return sessions; } public class AppAudioSession { public string AppName { get; set; } public uint ProcessId { get; set; } public float CurrentVolume { get; set; } }
三、调节特定应用的音量
根据进程ID找到对应的音频会话,设置其音量:
public static bool SetAppVolume(uint processId, float volumePercent) { if (volumePercent < 0 || volumePercent > 100) return false; float normalizedVol = volumePercent / 100f; IMMDeviceEnumerator enumerator = new MMDeviceEnumeratorComObject(); enumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out IMMDevice device); Guid sessionManagerGuid = typeof(IAudioSessionManager2).GUID; device.Activate(ref sessionManagerGuid, 0, IntPtr.Zero, out object obj); IAudioSessionManager2 sessionManager = (IAudioSessionManager2)obj; sessionManager.GetSessionEnumerator(out IAudioSessionEnumerator sessionEnum); sessionEnum.GetCount(out int count); bool success = false; for (int i = 0; i < count; i++) { sessionEnum.GetSession(i, out IAudioSessionControl2 sessionControl); sessionControl.GetProcessId(out uint pid); if (pid == processId) { sessionControl.QueryInterface(typeof(ISimpleAudioVolume).GUID, out IntPtr volPtr); ISimpleAudioVolume volume = (ISimpleAudioVolume)Marshal.GetObjectForIUnknown(volPtr); volume.SetMasterVolume(normalizedVol, Guid.Empty); success = true; Marshal.ReleaseComObject(volume); } Marshal.ReleaseComObject(sessionControl); if (success) break; } Marshal.ReleaseComObject(sessionEnum); Marshal.ReleaseComObject(sessionManager); Marshal.ReleaseComObject(device); Marshal.ReleaseComObject(enumerator); return success; }
四、使用示例
// 获取应用列表并打印 var appList = GetAudioSessions(); foreach (var app in appList) { Console.WriteLine($"应用名: {app.AppName}, 进程ID: {app.ProcessId}, 当前音量: {app.CurrentVolume:F1}%"); } // 将进程ID为1234的应用音量设置为50% SetAppVolume(1234, 50);
注意事项
- 部分应用可能会隐藏自身音频会话信息,或同时使用多个会话
- 普通用户权限即可运行,无需管理员权限
- 若需处理音频输入设备(麦克风),只需将
EDataFlow.eRender改为EDataFlow.eCapture
内容的提问来源于stack exchange,提问作者ilw
相关产品推荐
相关产品推荐

