Winapi 获取waveIn设备的全名

Winapi 获取waveIn设备的全名,winapi,audio,Winapi,Audio,我一直在使用获取waveIn设备的名称,但该结构仅支持31个字符加上一个null,这意味着在我的计算机上,我获取的设备名称被截断: Microphone / Line In (SigmaTel Microphone Array (SigmaTel High, 我确信一定有办法获得设备的完整名称,但有人知道这是什么吗?是的,有一个解决办法。我已经在运输代码中多次解决了这个问题 使用DirectSoundCapture枚举音频捕获设备。API是DirectSoundCaptureEnumera

我一直在使用获取waveIn设备的名称,但该结构仅支持31个字符加上一个null,这意味着在我的计算机上,我获取的设备名称被截断:

Microphone / Line In (SigmaTel 
Microphone Array (SigmaTel High, 

我确信一定有办法获得设备的完整名称,但有人知道这是什么吗?

是的,有一个解决办法。我已经在运输代码中多次解决了这个问题

使用DirectSoundCapture枚举音频捕获设备。API是DirectSoundCaptureEnumerate。它将返回设备的完整名称

当然,您可能会想“那太好了,但是我的其余代码都设置为使用Wave API,而不是DirectSound。我不想将其全部切换。那么如何将DirectSoundCaptureEnumerate返回的GUID ID映射到WaveIn API使用的整数ID?”

解决方案是为DirectSoundPrivate对象共同创建实例(或直接从dsound.dll调用GetClassObject),以获取指向IKsPropertySet接口的指针。从这个接口,您可以获得DSound GUID到Wave ID的映射。有关详细信息,请参阅此网页:


您想使用上述网页上所述的DSPROPERTY\u DIRECTSOUNDDEVICE\u WAVEDEVICEMAPPING。

DirectSoundPrivate似乎有一些问题。我试图从一个空项目中访问它,它工作正常。但是,当我尝试从COM DLL或DLL线程访问它时,它会从
IKsPropertySet::Get
返回
E\u NOTIMPL
错误

但我想出了另一个窍门。DirectSound似乎按波id顺序枚举捕获和渲染设备(不包括第一个默认值)


我们仍然需要与旧的WaveAPI交互,而且它仍然缺乏一种正确的方式来实现这一点。DirectShow提供基于WaveIn的音频输入设备,我需要获得相应的WASAPI id,反之亦然。

有一种涉及注册表的方法比使用DirectSound更简单。如果使用WAVEINCAPS2结构,则其名称GUID引用HKLM\System\CurrentControlSet\Control\MediaCategories下的键。如果密钥不存在,则只需在结构中使用名称。这在上有记录。下面是一个例子:

public static ICollection<AudioInputDevice> GetDevices()
{
  RegistryKey namesKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\MediaCategories");

  List<AudioInputDevice> devices = new List<AudioInputDevice>();
  for(int i=0, deviceCount=waveInGetNumDevs(); i<deviceCount; i++)
  {
    WAVEINCAPS2 caps;
    if(waveInGetDevCaps(new IntPtr(i), out caps, Marshal.SizeOf(typeof(WAVEINCAPS2))) == 0 && caps.Formats != 0)
    {
      string name = null;
      if(namesKey != null)
      {
        RegistryKey nameKey = namesKey.OpenSubKey(caps.NameGuid.ToString("B"));
        if(nameKey != null) name = nameKey.GetValue("Name") as string;
      }
      devices.Add(new AudioInputDevice(name ?? caps.Name, caps.ProductGuid));
    }
  }
  return devices;
}

struct WAVEINCAPS2
{
  public short ManufacturerId, ProductId;
  public uint DriverVersion;
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)] public string Name;
  public uint Formats;
  public short Channels;
  ushort Reserved;
  public Guid ManufacturerGuid, ProductGuid, NameGuid;
}

[DllImport("winmm.dll")]
static extern int waveInGetDevCaps(IntPtr deviceId, out WAVEINCAPS2 caps, int capsSize);

[DllImport("winmm.dll", ExactSpelling=true)]
static extern int waveInGetNumDevs();
publicstaticicollection-GetDevices()
{
RegistryKey namesKey=Registry.LocalMachine.OpenSubKey(@“System\CurrentControlSet\Control\MediaCategories”);
列表设备=新列表();

对于(int i=0,deviceCount=waveInGetNumDevs();i我完成了waveIn设备的名称,探索了从MMDeviceEnumerator返回的名称。对于每个waveIn设备,当名称未完成是其中一个EnumerateAudioEndpoint的全名的一部分时,我将此全名按waveIn设备的相同顺序用于填充组合框

VisualBasic.NET:

   Dim wain = New WaveIn()
    Dim DeviceInfoI As WaveInCapabilities
    Dim nomedevice As String
    For de = 0 To wain.DeviceCount - 1
        DeviceInfoI = wain.GetCapabilities(de)
        nomedevice = DeviceInfoI.ProductName
        For deg = 0 To devices.Count - 1
            If InStr(devices.Item(deg).FriendlyName, nomedevice) Then
                nomedevice = devices.Item(deg).FriendlyName
                Exit For
            End If
        Next
        cmbMessaggiVocaliMIC.Items.Add(nomedevice)
    Next
    cmbMessaggiVocaliMIC.SelectedIndex = 0
    waveIn.DeviceNumber = cmbMessaggiVocaliMIC.SelectedIndex
基于@Andrea Bertucelli answer的改进/完整C#WPF代码

using NAudio.CoreAudioApi;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Windows;

namespace WpfApp2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            foreach (KeyValuePair<string, MMDevice> device in GetInputAudioDevices())
            {
                Console.WriteLine("Name: {0}, State: {1}", device.Key, device.Value.State);
            }
        }

        public Dictionary<string, MMDevice> GetInputAudioDevices()
        {
            Dictionary<string, MMDevice> retVal = new Dictionary<string, MMDevice>();
            MMDeviceEnumerator enumerator = new MMDeviceEnumerator();
            int waveInDevices = WaveIn.DeviceCount;
            for (int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
            {
                WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
                foreach (MMDevice device in enumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.All))
                {
                    if (device.FriendlyName.StartsWith(deviceInfo.ProductName))
                    {
                        retVal.Add(device.FriendlyName, device);
                        break;
                    }
                }
            }

            return retVal;
        }
    }
}
使用NAudio.CoreAudioApi;
使用NAudio.波;
使用制度;
使用System.Collections.Generic;
使用System.Windows;
命名空间WpfApp2
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
foreach(GetInputAudioDevices()中的KeyValuePair设备)
{
WriteLine(“名称:{0},状态:{1}”,device.Key,device.Value.State);
}
}
公共字典GetInputAudioDevices()
{
Dictionary retVal=新字典();
MMDeviceEnumerator枚举器=新的MMDeviceEnumerator();
int waveInDevices=WaveIn.DeviceCount;
对于(int-waveInDevice=0;waveInDevice
我找到了另一种使用注册表查找音频设备全名的方法,包括输入和输出

适用于Windows 7和Windows 10

这个方法首先尝试了Adam M.的方法。他的方法对我不起作用,但为了以防万一,我添加了作为首选方法

procedure TForm_Config.FormCreate(Sender: TObject);
type
  tagWAVEOUTCAPS2A = packed record
    wMid: WORD;
    wPid: WORD;
    vDriverVersion: MMVERSION;
    szPname: array[0..MAXPNAMELEN-1] of AnsiChar;
    dwFormats: DWORD;
    wChannels: WORD;
    wReserved1: WORD;
    dwSupport: DWORD;
    ManufacturerGuid: System.TGUID;
    ProductGuid: System.TGUID;
    NameGuid: System.TGUID;
  end;
var
  i,outdevs: Integer;
  woCaps: tagWAVEOUTCAPS2A;
  RegistryService: TRegistry;
  iClasses, iSubClasses, iNames: Integer;
  audioDeviceClasses, audioDeviceSubClasses, audioDeviceNames: TStringList;
  initialDeviceName, partialDeviceName, fullDeviceName: string;
begin
  audioDeviceClasses := TStringList.Create;
  audioDeviceSubClasses := TStringList.Create;
  audioDeviceNames := TStringList.Create;
  try
    RegistryService := TRegistry.Create;
    try
      RegistryService.RootKey := HKEY_LOCAL_MACHINE;
      if RegistryService.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Enum\HDAUDIO\') then begin
        RegistryService.GetKeyNames(audioDeviceClasses);
        RegistryService.CloseKey();
        for iClasses := 0 to audioDeviceClasses.Count - 1 do begin
          if RegistryService.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Enum\HDAUDIO\'+audioDeviceClasses[iClasses]) then begin
            RegistryService.GetKeyNames(audioDeviceSubClasses);
            RegistryService.CloseKey();
            for iSubClasses := 0 to audioDeviceSubClasses.Count - 1 do begin
              if RegistryService.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Enum\HDAUDIO\'+audioDeviceClasses[iClasses]+'\'+audioDeviceSubClasses[iSubClasses]) then begin
                if RegistryService.ValueExists('DeviceDesc') then begin
                  fullDeviceName := Trim(RegistryService.ReadString('DeviceDesc'));
                  if AnsiPos(';',fullDeviceName) > 0 then begin
                    fullDeviceName := Trim(AnsiMidStr(fullDeviceName, AnsiPos(';',fullDeviceName)+1, Length(fullDeviceName)));
                  end;
                  audioDeviceNames.Add(fullDeviceName);
                end;
                RegistryService.CloseKey();
              end;
            end;
          end;
        end;
      end;
    finally
      FreeAndNil(RegistryService);
    end;

    // WaveOutDevComboBox is a selection box (combo) placed in the form and will receive the list of output audio devices
    WaveOutDevComboBox.Clear;

    try
      outdevs := waveOutGetNumDevs;
      for i := 0 to outdevs - 1 do begin
        ZeroMemory(@woCaps, sizeof(woCaps));
        if waveOutGetDevCaps(i, @woCaps, sizeof(woCaps)) = MMSYSERR_NOERROR then begin
          RegistryService := TRegistry.Create;
          try
            RegistryService.RootKey := HKEY_LOCAL_MACHINE;
            if RegistryService.OpenKeyReadOnly('\System\CurrentControlSet\Control\MediaCategories\' + GUIDToString(woCaps.NameGuid)) then begin
              WaveOutDevComboBox.Items.Add(RegistryService.ReadString('Name'));
              RegistryService.CloseKey();
            end
            else begin
              initialDeviceName := '';
              partialDeviceName := Trim(woCaps.szPname);
              if AnsiPos('(',partialDeviceName) > 0 then begin
                initialDeviceName := Trim(AnsiLeftStr(partialDeviceName,AnsiPos('(',partialDeviceName)-1));
                partialDeviceName := Trim(AnsiMidStr(partialDeviceName,AnsiPos('(',partialDeviceName)+1,Length(partialDeviceName)));
                if AnsiPos(')',partialDeviceName) > 0 then begin
                  partialDeviceName := Trim(AnsiLeftStr(partialDeviceName,AnsiPos(')',partialDeviceName)-1));
                end;
              end;
              for iNames := 0 to audioDeviceNames.Count - 1 do begin
                fullDeviceName := audioDeviceNames[iNames];
                if AnsiStartsText(partialDeviceName,fullDeviceName) then begin
                  break;
                end
                else begin
                  fullDeviceName := partialDeviceName;
                end;
              end;
              WaveOutDevComboBox.Items.Add(initialDeviceName + IfThen(initialDeviceName<>EmptyStr,' (','') + fullDeviceName + IfThen(initialDeviceName<>EmptyStr,')',''));
            end;
          finally
            FreeAndNil(RegistryService);
          end;
        end;
      end;
    except
      WaveOutDevComboBox.Enabled := False;
    end;
  finally
    FreeAndNil(audioDeviceClasses);
    FreeAndNil(audioDeviceSubClasses);
    FreeAndNil(audioDeviceNames);
  end;
end;
过程TForm_Config.FormCreate(发送方:TObject);
类型
tagWAVEOUTCAPS2A=打包记录
wMid:WORD;
wPid:WORD;
VDR版本:MMV版本;
szPname:AnsiChar的数组[0..MAXPNAMELEN-1];
DWORD格式:DWORD;
频道:单词;
Wreserved 1:单词;
德沃德支持:德沃德;
ManufacturerGuid:System.TGUID;
ProductGuid:System.TGUID;
NameGuid:System.TGUID;
结束;
变量
i、 outdevs:整数;
woCaps:tagWAVEOUTCAPS2A;
注册服务:TRegistry;
iClass、iSubClass、iNames:整数;
音频设备类、音频设备子类、音频设备名称:TStringList;
initialDeviceName、partialDeviceName、fullDeviceName:string;
开始
audioDeviceClasses:=TStringList.Create;
audioDeviceSubClasses:=TStringList.Create;
audioDeviceNames:=TStringList.Create;
尝试
RegistryService:=TRegistry.Create;
尝试
RegistryService.RootKey:=HKEY\U LOCAL\U MACHINE;
如果RegistryService.OpenKeyReadOnly(“\SYSTEM\CurrentControlSet\Enum\HDAUDIO\”),则开始
RegistryService.GetKeyNames(AudioDeviceClass);
RegistryService.CloseKey();
对于iClass:=0到AudioDeviceClass。计数-1开始
如果RegistryService.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Enum\HDAUDIO\'+AudioDeviceClass[iClasses]),则开始
GetKeyNames(AudioDeviceSubclass);
RegistryService.CloseKey();
对于iSubclass:=0到AudioDeviceSubclass
using NAudio.CoreAudioApi;
using NAudio.Wave;
//create enumerator
var enumerator = new MMDeviceEnumerator();
//cycle through all audio devices
for (int i = 0; i < WaveIn.DeviceCount; i++)
    Console.WriteLine(enumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active)[i]);
//clean up
enumerator.Dispose();
//create enumerator
var enumerator = new MMDeviceEnumerator();
//cyckle trough all audio devices
for (int i = 0; i < WaveOut.DeviceCount; i++)
    Console.WriteLine(enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active)[i]);
//clean up
enumerator.Dispose();