2016-12-21 30 views
0

我正在尋找一種方法來更改Windows中不同應用程序的音頻混合(即Firefox音頻級別與Foobar音頻級別),而不會將焦點從遠處當前的應用程序。 Python是我最熟悉的語言,但如果能讓我更容易,我會使用另一種語言。該代碼將用於連接帶外部HID設備的音量旋鈕和按鈕。焦點需要保持在當前窗口中,因爲VR遊戲將會在音頻混音器之上運行,如果腳本不在,我不能重新關注。在後臺更改Windows 10應用程序音頻混合(最好使用Python)

我成功地將一些older code一起使用了comtypes模塊,但是從那裏我只能改變左/右平衡,而不是特定於應用的音頻電平。

我試圖把我的方式,通過MSDN上的有關Windows文檔(尤其是WASAPI),但它通常最終給我下了微軟的兔子洞,我在方式得到了我的頭(我充其量只是一個新手程序員)。

我是否完全用錯誤的方式去做這件事?

回答

0

因此,您提供的「舊代碼」在API中仍然與Windows 10聲音API的工作方式相關。

對於這種類型的代碼一個很好的例子是目前在C#中,它可以在這裏找到:

StackOverflow - c# - Controling Volume Mixer

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); 
    } 
} 

一個導入所有的Windows核心音頻API的COMTypes到Python中的庫我發現將是pycaw,如果您想了解如何將Windows API移植到Python中,那將是一個很好的開始。

+0

雖然這個鏈接可能回答這個問題,但最好在這裏包含答案的重要部分並提供參考鏈接。如果鏈接頁面更改,則僅鏈接答案可能會失效。 - [來自評論](/ review/low-quality-posts/14657382) – Mayur

+0

感謝您的回覆,我會嘗試將此示例合併到我現有的腳本中並回報。 – Platytude

+0

@Mack修改爲包含代碼,謝謝你的支持。 – Pandashire

相關問題