Получить полное имя устройства waveIn - PullRequest
11 голосов
/ 19 сентября 2009

Я использовал waveInGetDevCaps для получения имени устройств waveIn, но структура WAVEINCAPS поддерживает только 31 символ плюс ноль, что означает, что на моем компьютере имена устройств I получить обратно усечены:

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

Я уверен, что должен быть способ получить полное имя устройства, но кто-нибудь знает, что это такое?

Ответы [ 6 ]

7 голосов
/ 20 сентября 2009

Да, есть обходной путь. Я решил эту проблему несколько раз в коде доставки.

Перечисление устройств захвата звука с DirectSoundCapture. API является DirectSoundCaptureEnumerate. Он вернет вам полное имя устройства.

Конечно, вы, вероятно, думаете: «Это здорово, но остальная часть моего кода настроена на использование Wave API, а не DirectSound. Я не хочу все это переключать. Так как я могу отобразить GUID? Идентификаторы, возвращаемые DirectSoundCaptureEnumerate целочисленным идентификаторам, используемым API-интерфейсом WaveIn? "

Решением является CoCreateInstance для объекта DirectSoundPrivate (или вызов GetClassObject непосредственно из dsound.dll) для получения указателя на интерфейс IKsPropertySet. Из этого интерфейса вы можете получить DSound GUID для сопоставления Wave ID. Для более подробной информации смотрите эту веб-страницу:

http://msdn.microsoft.com/en-us/library/bb206182(VS.85).aspx

Вы хотите использовать DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING, как описано на веб-странице, указанной выше.

5 голосов
/ 13 апреля 2017

Улучшенный / полный C # WPF-код на основе ответа @Andrea Bertucelli

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;
        }
    }
}
5 голосов
/ 09 февраля 2017

Я заполнил имена устройств waveIn, изучая имена, возвращенные из MMDeviceEnumerator. Для каждого устройства waveIn, когда неполное имя является частью полного имени одного из EnumerateAudioEndPoints, я использовал это полное имя для заполнения комбинированного списка в том же порядке устройств 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
3 голосов
/ 04 июля 2013

Есть способ задействовать реестр, который проще, чем использование DirectSound. Если вы используете структуру WAVEINCAPS2, она имеет имя GUID, которое ссылается на ключ в HKLM \ System \ CurrentControlSet \ Control \ MediaCategories. Если ключ не существует, просто используйте имя в структуре. Это задокументировано на http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382%28v=vs.85%29.aspx. Вот пример:

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();
3 голосов
/ 28 января 2012

Похоже, у DirectSoundPrivate есть некоторые проблемы. Я пытаюсь получить доступ к нему из пустого проекта, и он работает нормально. Тем не менее, когда я пытаюсь получить доступ к нему из COM DLL или из потока DLL, он возвращает E_NOTIMPL ошибка из IKsPropertySet::Get.

Но я понял еще одну хитрость. Кажется, DirectSound перечисляет устройства захвата и рендеринга в порядке идентификатора волны (исключая первое значение по умолчанию).

Нам все еще нужно взаимодействовать со старым Wave API, и у него все еще нет надлежащего способа сделать это. DirectShow предоставляет устройства ввода звука на основе WaveIn, и мне нужно получить соответствующий идентификатор WASAPI и наоборот.

0 голосов
/ 20 октября 2018

Я нашел другой способ, используя реестр, чтобы найти полное имя аудиоустройства, как Вход, так и Выход.

Работает в Windows 7 и Windows 10.

Этот метод в первую очередь пробует подход Адама М. Его метод не работает для меня, но на всякий случай, если он работает для вас, я добавил в качестве предпочтительного метода.

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...