控制音量混合器

Posted

技术标签:

【中文标题】控制音量混合器【英文标题】:Controlling Volume Mixer 【发布时间】:2018-01-06 13:17:32 【问题描述】:

我想控制其他应用程序的音量(firefox)。

我可以用Volume Mixer做到这一点

Volume Mixer的库是什么?

【问题讨论】:

一点谷歌回馈这个:dreamincode.net/forums/topic/… 这是由 WASAPI,Windows 音频会话 API 在 Windows 中实现的。你需要一个包装器,通过搜索“c# wasapi”找到谷歌点击 @Simon Mourier 我认为这段代码控制系统音量。我只想控制 firefox 音量。 我一直在处理CoreAudio library for .NET。该库是免费和开源的。商业版MixerProNET Library 上提供了更强大的实现 【参考方案1】:

这是一个示例 C# 控制台应用程序。它基于Windows Core Audio Library。它仅适用于 Windows 7 及更高版本。

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;

namespace SetAppVolumne

    class Program
    
        static void Main(string[] args)
        
            const string app = "Mozilla Firefox";

            foreach (string name in EnumerateApplications())
            
                Console.WriteLine("name:" + name);
                if (name == app)
                
                    // display mute state & volume level (% of master)
                    Console.WriteLine("Mute:" + GetApplicationMute(app));
                    Console.WriteLine("Volume:" + GetApplicationVolume(app));

                    // mute the application
                    SetApplicationMute(app, true);

                    // set the volume to half of master volume (50%)
                    SetApplicationVolume(app, 50);
                
            
        

        public static float? GetApplicationVolume(string name)
        
            ISimpleAudioVolume volume = GetVolumeObject(name);
            if (volume == null)
                return null;

            float level;
            volume.GetMasterVolume(out level);
            return level * 100;
        

        public static bool? GetApplicationMute(string name)
        
            ISimpleAudioVolume volume = GetVolumeObject(name);
            if (volume == null)
                return null;

            bool mute;
            volume.GetMute(out mute);
            return mute;
        

        public static void SetApplicationVolume(string name, float level)
        
            ISimpleAudioVolume volume = GetVolumeObject(name);
            if (volume == null)
                return;

            Guid guid = Guid.Empty;
            volume.SetMasterVolume(level / 100, ref guid);
        

        public static void SetApplicationMute(string name, bool mute)
        
            ISimpleAudioVolume volume = GetVolumeObject(name);
            if (volume == null)
                return;

            Guid guid = Guid.Empty;
            volume.SetMute(mute, ref guid);
        

        public static IEnumerable<string> EnumerateApplications()
        
            // get the speakers (1st render + multimedia) device
            IMMDeviceEnumerator deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
            IMMDevice speakers;
            deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out speakers);

            // activate the session manager. we need the enumerator
            Guid IID_IAudiosessionManager2 = typeof(IAudioSessionManager2).GUID;
            object o;
            speakers.Activate(ref IID_IAudioSessionManager2, 0, IntPtr.Zero, out o);
            IAudioSessionManager2 mgr = (IAudioSessionManager2)o;

            // enumerate sessions for on this device
            IAudioSessionEnumerator sessionEnumerator;
            mgr.GetSessionEnumerator(out sessionEnumerator);
            int count;
            sessionEnumerator.GetCount(out count);

            for (int i = 0; i < count; i++)
            
                IAudioSessionControl ctl;
                sessionEnumerator.GetSession(i, out ctl);
                string dn;
                ctl.GetDisplayName(out dn);
                yield return dn;
                Marshal.ReleaseComObject(ctl);
            
            Marshal.ReleaseComObject(sessionEnumerator);
            Marshal.ReleaseComObject(mgr);
            Marshal.ReleaseComObject(speakers);
            Marshal.ReleaseComObject(deviceEnumerator);
        

        private static ISimpleAudioVolume GetVolumeObject(string name)
        
            // get the speakers (1st render + multimedia) device
            IMMDeviceEnumerator deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
            IMMDevice speakers;
            deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out speakers);

            // activate the session manager. we need the enumerator
            Guid IID_IAudioSessionManager2 = typeof(IAudioSessionManager2).GUID;
            object o;
            speakers.Activate(ref IID_IAudioSessionManager2, 0, IntPtr.Zero, out o);
            IAudioSessionManager2 mgr = (IAudioSessionManager2)o;

            // enumerate sessions for on this device
            IAudioSessionEnumerator sessionEnumerator;
            mgr.GetSessionEnumerator(out sessionEnumerator);
            int count;
            sessionEnumerator.GetCount(out count);

            // search for an audio session with the required name
            // NOTE: we could also use the process id instead of the app name (with IAudioSessionControl2)
            ISimpleAudioVolume volumeControl = null;
            for (int i = 0; i < count; i++)
            
                IAudioSessionControl ctl;
                sessionEnumerator.GetSession(i, out ctl);
                string dn;
                ctl.GetDisplayName(out dn);
                if (string.Compare(name, dn, StringComparison.OrdinalIgnoreCase) == 0)
                
                    volumeControl = ctl as ISimpleAudioVolume;
                    break;
                
                Marshal.ReleaseComObject(ctl);
            
            Marshal.ReleaseComObject(sessionEnumerator);
            Marshal.ReleaseComObject(mgr);
            Marshal.ReleaseComObject(speakers);
            Marshal.ReleaseComObject(deviceEnumerator);
            return volumeControl;
        
    

    [ComImport]
    [Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
    internal class MMDeviceEnumerator
    
    

    internal enum EDataFlow
    
        eRender,
        eCapture,
        eAll,
        EDataFlow_enum_count
    

    internal enum ERole
    
        eConsole,
        eMultimedia,
        eCommunications,
        ERole_enum_count
    

    [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IMMDeviceEnumerator
    
        int NotImpl1();

        [PreserveSig]
        int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice ppDevice);

        // the rest is not implemented
    

    [Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IMMDevice
    
        [PreserveSig]
        int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);

        // the rest is not implemented
    

    [Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IAudioSessionManager2
    
        int NotImpl1();
        int NotImpl2();

        [PreserveSig]
        int GetSessionEnumerator(out IAudioSessionEnumerator SessionEnum);

        // the rest is not implemented
    

    [Guid("E2F5BB11-0570-40CA-ACDD-3AA01277DEE8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IAudioSessionEnumerator
    
        [PreserveSig]
        int GetCount(out int SessionCount);

        [PreserveSig]
        int GetSession(int SessionCount, out IAudioSessionControl Session);
    

    [Guid("F4B1A599-7266-4319-A8CA-E70ACB11E8CD"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IAudioSessionControl
    
        int NotImpl1();

        [PreserveSig]
        int GetDisplayName([MarshalAs(UnmanagedType.LPWStr)] out string pRetVal);

        // the rest is not implemented
    

    [Guid("87CE5498-68D6-44E5-9215-6DA47EF883D8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface ISimpleAudioVolume
    
        [PreserveSig]
        int SetMasterVolume(float fLevel, ref Guid EventContext);

        [PreserveSig]
        int GetMasterVolume(out float pfLevel);

        [PreserveSig]
        int SetMute(bool bMute, ref Guid EventContext);

        [PreserveSig]
        int GetMute(out bool pbMute);
    

注意:我没有完全定义接口,只定义了代码工作所需要的。

【讨论】:

也许您可以尝试使用“Spotify”而不是“Mozilla Firefox” 已经尝试过了,但是音量混合器没有返回DisplayName for Spotify,它只适用于 Firefox 和某种 .dll 在 Windows 7 上,有一个 IAudioSessionControl2 接口可以获取进程 ID。从那里您可以确定它是否是 spotify。如果您不知道该怎么做,请再问一个问题。 @bliss - 这是另一个问题,所以,就像我说的,你应该问另一个问题 @Simon Mourier - 我在 EnumerateApplications() 函数中遇到了这个错误 - 这是屏幕截图:i.imgur.com/YzbgOKH.png你能帮忙吗?【参考方案2】:

我知道这为时已晚,但我最近需要这个,我尝试了 Simon 的答案,但无法让它发挥作用,尝试了 ElektroStudios 的评论和Simon's other answer 仍然没有,我不知道我做错了什么,但是我放弃了。

我后来找到了this asnwer,并使用CSCore让它工作

private static void Main(string[] args)

    using (var sessionManager = GetDefaultAudioSessionManager2(DataFlow.Render))
    
        using (var sessionEnumerator = sessionManager.GetSessionEnumerator())
        
            foreach (var session in sessionEnumerator)
            
                using (var simpleVolume = session.QueryInterface<SimpleAudioVolume>())
                using (var sessionControl = session.QueryInterface<AudioSessionControl2>())
                
                    if (sessionControl.ProcessID == 2436)
                        simpleVolume.MasterVolume = 0.5f;
                
            
        
    

    Console.ReadKey();


private static AudioSessionManager2 GetDefaultAudioSessionManager2(DataFlow dataFlow)

    using (var enumerator = new MMDeviceEnumerator())
    
        using (var device = enumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia))
        
            Debug.WriteLine("DefaultDevice: " + device.FriendlyName);
            var sessionManager = AudioSessionManager2.FromMMDevice(device);
            return sessionManager;
        
    

【讨论】:

以上是关于控制音量混合器的主要内容,如果未能解决你的问题,请参考以下文章

ASIO 中的 NAudio 音量

如何创建一个有边框但没有标题栏的表单? (如 Windows 7 上的音量控制)

win7音量合成器怎么添加设备

如何控制/强制 iOS 系统音量 [cordova]

背景 iPod 音乐音量与音效混合

音量问题 - AVAudioPlayer 与 AudioServices 系统声音混合