【问题标题】:How to associate a USB headsets microphone and earphone/speaker如何关联 USB 耳机麦克风和耳机/扬声器
【发布时间】:2015-05-01 06:36:39
【问题描述】:

背景

我需要在软件电话应用程序中显示已连接耳机(组合麦克风和耳机)的列表。为了测试,我有以下设备:

  • Jabra PRO 9470
  • 缤特力 BT300M
  • 罗技 G430 游戏耳机

用户应该能够从ComboBox 中选择耳机,而无需单独选择麦克风和耳机。

信息

我知道在哪里可以找到有关麦克风和耳机的信息(在 Windows 中),但我无法使用 WMIMMDevice API 获得它。

要查找信息,请右键单击任务栏右侧的Sound(扬声器图标)并选择Playback devices

  1. 双击或点击Properties打开属性窗口。
  2. 单击属性窗口上的Properties 按钮。
  3. 单击Details 选项卡并在ComboBox 中找到Children 属性。

这将为我提供以下信息:

SWD\MMDEVAPI\{0.0.0.00000000}.{f2e09e37-8389-46c4-8b2b-53e08b874399}
SWD\MMDEVAPI\{0.0.1.00000000}.{3402ee6e-d862-47ca-8ab8-bb8254216032}

第一行匹配我的Headset Earphone (Jabra PRO 9470) 和第二行Headset Microphone (Jabra PRO 9470)

为了在 C# 中获得相同的信息,我循环通过 Win32_USBControllerDevice 类并输出包含“MMDEVAPI”的所有值。在我的 PC 上,它将返回 6 个值(3 个麦克风,3 个耳机)。

foreach (var device in new ManagementObjectSearcher("SELECT * FROM Win32_USBControllerDevice").Get())
{
    foreach (var property in device.Properties)
    {
        // Gets the value of the property on the device.
        var value = property.Value == null ? string.Empty : property.Value.ToString();

        if (value.IndexOf("mmdevapi", StringComparison.OrdinalIgnoreCase) > -1)
        {
            // Output connected USB microphones and earphones.
            Console.WriteLine(property.Value);
        }
    }
}

供参考,上面的代码会输出:

\\PC9018\root\cimv2:Win32_PnPEntity.DeviceID="SWD\\MMDEVAPI\\{0.0.0.00000000}.{F2E09E37-8389-46C4-8B2B-53E08B874399}"
\\PC9018\root\cimv2:Win32_PnPEntity.DeviceID="SWD\\MMDEVAPI\\{0.0.1.00000000}.{3402EE6E-D862-47CA-8AB8-BB8254216032}"
\\PC9018\root\cimv2:Win32_PnPEntity.DeviceID="SWD\\MMDEVAPI\\{0.0.0.00000000}.{985F2B5C-2EE2-4733-BBD6-48BFDE2D5582}"
\\PC9018\root\cimv2:Win32_PnPEntity.DeviceID="SWD\\MMDEVAPI\\{0.0.1.00000000}.{71D824EA-DAE9-4F0D-B673-4425385E3777}"
\\PC9018\root\cimv2:Win32_PnPEntity.DeviceID="SWD\\MMDEVAPI\\{0.0.0.00000000}.{D29C0970-D515-4F91-9924-F0063CF1A196}"
\\PC9018\root\cimv2:Win32_PnPEntity.DeviceID="SWD\\MMDEVAPI\\{0.0.1.00000000}.{C4B331E2-C56B-4D9B-A486-2ED6C11FDB8C}"

问题

我现在最大的问题是,如何将正确的耳机麦克风和耳机关联到Headset 对象?

尝试

我曾尝试在 Google 和 StackOverflow 上搜索答案或提示,但使用 WMIMMDevice API 找不到麦克风和耳机之间的任何共同点或关系。

如果有办法创建Dictionary<string, List<string>>,其中Key 是物理设备或USB 端口独有的,而Value 是关联Win32_PnPEntity.DeviceID 的列表,那么我找不到它。

本着几天后星球大战日的精神:“帮帮我,StackOverflow。你是我唯一的希望。

【问题讨论】:

    标签: c# .net wmi microphone headset


    【解决方案1】:

    NAudio 和 Windows 注册表的帮助下,我自己似乎找到了答案。问题中的代码仍然是正确的,但 NAudio 使它更容易一些。

    我在以下 Windows 注册表中找到了问题的关键:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render
    

    每个设备都有一个名为{b3f8fa53-0004-438e-9003-51a46e139bfc},2 的属性,其值类似于{1}.USB\VID_047F&PID_0416&MI_00\7&21995D75&0&0000

    这看起来是一个唯一的硬件 ID,由耳机麦克风和耳机共享(与问题中的 Children 属性相同)。

    解决方案

    使用单一方法定位和返回耳机列表的接口。

    public interface IHeadsetLocator
    {
        /// <summary>
        /// Locate all connected audio devices based on the given state.
        /// </summary>
        /// <param name="deviceState"></param>
        /// <returns></returns>
        IReadOnlyCollection<Headset> LocateConnectedAudioDevices(DeviceState deviceState = DeviceState.Active);
    }
    

    以及完整的实现。真正的魔法发生在GetHardwareToken 方法的帮助下。

    public class HeadsetLocator : IHeadsetLocator
    {
        /// <summary>
        /// Locate all connected audio devices based on the given state.
        /// </summary>
        /// <param name="deviceState"></param>
        /// <returns></returns>
        public IReadOnlyCollection<Headset> LocateConnectedAudioDevices(DeviceState deviceState = DeviceState.Active)
        {
            var enumerator = new MMDeviceEnumerator();
            var relatedAudioDevices = new ConcurrentDictionary<string, List<MMDevice>>();
            var headsets = new List<Headset>();
    
            // Locate all connected audio devices.
            foreach (var device in enumerator.EnumerateAudioEndPoints(DataFlow.All, deviceState))
            {
                // Gets the DataFlow and DeviceID from the connected audio device.
                var index = device.ID.LastIndexOf('.');
                var dataFlow = device.ID.Substring(0, index).Contains("0.0.0") ? DataFlow.Render : DataFlow.Capture;
                var deviceId = device.ID.Substring(index + 1);
    
                // Gets the unique hardware token.
                var hardwareToken = GetHardwareToken(dataFlow, deviceId);
    
                var audioDevice = relatedAudioDevices.GetOrAdd(hardwareToken, o => new List<MMDevice>());
                audioDevice.Add(device);
            }
    
            // Combines the related devices into a headset object.
            foreach (var devicePair in relatedAudioDevices)
            {
                var capture = devicePair.Value.FirstOrDefault(o => o.ID.Contains("0.0.1"));
                var render = devicePair.Value.FirstOrDefault(o => o.ID.Contains("0.0.0"));
    
                if (capture != null && render != null)
                {
                    headsets.Add(new Headset("Headset", render.DeviceFriendlyName, capture, render));
                }
            }
    
            return new ReadOnlyCollection<Headset>(headsets);
        }
    
        /// <summary>
        /// Gets the token of the USB device.
        /// </summary>
        /// <param name="dataFlow"></param>
        /// <param name="audioDeviceId"></param>
        /// <returns></returns>
        public string GetHardwareToken(DataFlow dataFlow, string audioDeviceId)
        {
            using (var registryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
            {
                var captureKey = registryKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\" + dataFlow + @"\" + audioDeviceId + @"\Properties");
                if (captureKey != null)
                {
                    return captureKey.GetValue("{b3f8fa53-0004-438e-9003-51a46e139bfc},2") as string;
                }
            }
    
            return null;
        }
    }
    

    我希望这可以帮助其他处于类似情况的人。

    编码愉快

    【讨论】:

      猜你喜欢
      • 2022-09-26
      • 1970-01-01
      • 1970-01-01
      • 2017-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-18
      • 1970-01-01
      相关资源
      最近更新 更多