【问题标题】:Handling changed audio device event in c#在 C# 中处理更改的音频设备事件
【发布时间】:2011-09-04 00:31:55
【问题描述】:

我想知道当我将耳机或其他输出设备插入(或拔出)到声卡插孔时如何处理事件。

在此处和在 google 上搜索为我提供了有关“naudio”库的信息,但它的文档非常差,而且该项目的一位协调员告诉我,他甚至不确定在他们的库中是否有可能。

我的最终目的是自动控制不同设备的音量,例如当耳机处于活动状态时 - 设置为 10% 的音量,当扬声器处于活动状态时 - 设置为 100%。

【问题讨论】:

    标签: c# .net events audio device


    【解决方案1】:

    您将能够确定何时将设备插入系统,您必须通过 COM 互操作实现 IMMNotificationClient。基本上,您必须定义以下方法的实现:

    请注意,在上述内容中,您最感兴趣的是:

    • OnDefaultDeviceChanged
    • OnDeviceAdded
    • OnDeviceStateChanged

    但是,您应该知道底层硬件必须支持此功能,并且仅在 Windows Vista 和 Windows Server 2008 上可用。

    【讨论】:

    • 好的,我收到关于“某物”插入或拔出的消息就足够了。这怎么可能?我还尝试了另一种方法 - 在 Windows 事件查看器中搜索此事件,但我什么都没有 - 可能是我搜索得不太好,或者可能是这个事件没有记录在那里。
    • @xapon:不幸的是,我说“充其量”您将能够获得该信息。如果这样做,它将特定于声卡或主板(如果集成了插孔);我不确定是否有硬件抽象层公开的标准事件可供您了解。
    • 我认为可以在底层解决;例如,这里是用于跟踪音频事件的 Windows 界面msdn.microsoft.com/en-us/library/dd371417(v=vs.85).aspx。因此,如果我更深入,我会找到方法来做到这一点。但我希望已经有一些像库或类这样的抽象可以帮助我。无论如何感谢您的解释。
    • @xapon - 扩展了我的答案,最终,你必须使用 COM 互操作来实现这个设备,然后注册你的实现。
    【解决方案2】:

    我很确定插入/拔出耳机或声卡中的其他任何东西都不会产生任何系统事件

    【讨论】:

      【解决方案3】:

      您可以使用 NAudio 的 MMDeviceEnumerator 和 IMMNotificationClient 来完成。但是,您将 RegisterEndpointNotificationCallbackUnRegisterEndpointNotificationCallback 的实现添加到 MMDeviceEnumerator 类

      实现是

       /// <summary>
             /// Registers a call back for Device Events
             /// </summary>
              /// <param name="client">Object implementing IMMNotificationClient type casted as IMMNotificationClient interface</param>
             /// <returns></returns>
              public int RegisterEndpointNotificationCallback([In] [MarshalAs(UnmanagedType.Interface)] IMMNotificationClient client)
              {
                  //DeviceEnum declared below
                  return deviceEnum.RegisterEndpointNotificationCallback(client);
              }
      
              /// <summary>
              /// UnRegisters a call back for Device Events
              /// </summary>
              /// <param name="client">Object implementing IMMNotificationClient type casted as IMMNotificationClient interface </param>
              /// <returns></returns>
              public int UnRegisterEndpointNotificationCallback([In] [MarshalAs(UnmanagedType.Interface)] IMMNotificationClient client)
              {
                  //DeviceEnum declared below
                  return deviceEnum.UnregisterEndpointNotificationCallback(client);
              } 
      

      然后创建一个实现IMMNotificationClient的类

      样本:

      class NotificationClientImplementation : NAudio.CoreAudioApi.Interfaces.IMMNotificationClient
          {
      
              public void OnDefaultDeviceChanged(DataFlow dataFlow, Role deviceRole, string defaultDeviceId)
              {
                  //Do some Work
                  Console.WriteLine("OnDefaultDeviceChanged --> {0}", dataFlow.ToString());
              }
      
              public void OnDeviceAdded(string deviceId)
              {
                   //Do some Work
                  Console.WriteLine("OnDeviceAdded -->");
              }
      
              public void OnDeviceRemoved(string deviceId)
              {
      
                  Console.WriteLine("OnDeviceRemoved -->");
                   //Do some Work
              }
      
              public void OnDeviceStateChanged(string deviceId, DeviceState newState)
              {
                  Console.WriteLine("OnDeviceStateChanged\n Device Id -->{0} : Device State {1}", deviceId, newState);
                   //Do some Work
              }
      
              public NotificationClientImplementation()
              {
                  //_realEnumerator.RegisterEndpointNotificationCallback();
                  if (System.Environment.OSVersion.Version.Major < 6)
                  {
                      throw new NotSupportedException("This functionality is only supported on Windows Vista or newer.");
                  }
              }
      
              public void OnPropertyValueChanged(string deviceId, PropertyKey propertyKey)
              {
                   //Do some Work
                   //fmtid & pid are changed to formatId and propertyId in the latest version NAudio
                  Console.WriteLine("OnPropertyValueChanged: formatId --> {0}  propertyId --> {1}", propertyKey.formatId.ToString(), propertyKey.propertyId.ToString());
              }
      
          }
      

      那么你要做的就是

      1. 声明以下 NAudio 对象和您的 IMMNotificationClient 实现

      示例:

      private NAudio.CoreAudioApi.MMDeviceEnumerator deviceEnum = new NAudio.CoreAudioApi.MMDeviceEnumerator();
      private NotificationClientImplementation notificationClient;
      private NAudio.CoreAudioApi.Interfaces.IMMNotificationClient notifyClient;
      
      1. 然后键入 cast notificationClient 作为 IMMNotificationClient 并将其作为参数传递给 MMDeviceEnumerator

      示例:

      notificationClient = new NotificationClientImplementation();
      notifyClient = (NAudio.CoreAudioApi.Interfaces.IMMNotificationClient)notificationClient;
      deviceEnum.RegisterEndpointNotificationCallback(notifyClient);
      

      希望这对身体有所帮助。感谢 MSDN 论坛,特别是 Michael Taylor http://msmvps.com/blogs/p3net 帮我解决了这个问题。

      感谢和干杯。

      【讨论】:

      • 非常感谢您的回答!不幸的是,自从我提出这个问题已经 3 年了,我很久以前就退出了这个主题的研究。但我希望它能帮助其他人解决同样的问题。
      • @Mohtashim 非常感谢!我一直在寻找几个小时的实现示例!我会竖起大拇指这 100 次,以获得样本的详细答案!
      • 我使用这里描述的相同方式,我只在插入耳机插孔时看到 onProperyChange 事件运行,当我拔掉它时我看不到任何东西是什么原因?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-11
      相关资源
      最近更新 更多