2009-09-19 18 views
9

He estado utilizando waveInGetDevCaps para obtener el nombre de los dispositivos WaveIn, pero la estructura WAVEINCAPS solo admite 31 caracteres más un nulo, lo que significa que en mi computadora, los nombres de los dispositivos que recibo se truncan :Obtener el nombre completo de un dispositivo WaveIn

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

estoy seguro de que debe haber una manera de conseguir el nombre del dispositivo completo, pero ¿alguien sabe lo que es?

Respuesta

7

Sí, hay una solución. He resuelto este problema varias veces en el código de envío.

Enumerar dispositivos de captura de audio con DirectSoundCapture. La API es DirectSoundCaptureEnumerate. Le devolverá el nombre completo de los dispositivos.

Por supuesto, probablemente esté pensando: "Eso es genial, pero el resto de mi código está configurado para usar Wave API, no DirectSound. No quiero cambiarlo todo. Entonces, ¿cómo puedo mapear el ID de GUID devuelto por DirectSoundCaptureEnumerate a los ID enteros utilizados por la API de WaveIn? "

La solución es CoCreateInstance para el objeto DirectSoundPrivate (o llame a GetClassObject directamente desde dsound.dll) para obtener un puntero a una interfaz IKsPropertySet. Desde esta interfaz, puede obtener el GUID de DSound para la asignación de ID de onda. Para más detalles ver esta página web:

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

Usted desea utilizar el DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING como se describe en la página web que aparece arriba.

+0

gracias, esto es realmente útil (aunque es una pena que tiene que ser tan complicado) –

+1

que vinculan parece estar roto . ¿Tienes otro enlace o al menos el título del artículo sobre msdn? –

+2

Otro método para obtener el GUID es llamar a waveOutGetDevCaps con una estructura WAVEOUTCAPS2, en lugar de la estructura WAVEOUTCAPS regular. http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382%28v=vs.85%29.aspx – leiflundgren

2

Parece que DirectSoundPrivate tiene algunos problemas. Estoy intentando acceder desde un proyecto vacío y funciona bien. Sin embargo, cuando intento acceder desde COM DLL o desde un hilo DLL devuelve E_NOTIMPL error de IKsPropertySet::Get.

Pero descubrí otro truco. Parece que DirectSound enumera los dispositivos de captura y renderizado en orden de identificación de onda (excluyendo el primer valor predeterminado).

Todavía tenemos que interactuar con la antigua API de Wave y todavía carece de una forma adecuada de hacerlo. DirectShow proporciona dispositivos de entrada de audio basados ​​en WaveIn y necesito obtener un ID de WASAPI correspondiente y viceversa.

3

Hay una manera que implica el registro que es más simple que usar DirectSound. Si usa la estructura WAVEINCAPS2, tiene un nombre GUID que hace referencia a una clave en HKLM \ System \ CurrentControlSet \ Control \ MediaCategories. Si la clave no existe, simplemente usa el nombre en la estructura. Esto está documentado en http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382%28v=vs.85%29.aspx. He aquí un ejemplo:

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

gracias por llamar mi atención sobre esto. Parece prometedor, pero lamentablemente mis pruebas (en Win 7) han demostrado que, aunque la estructura WAVEINCAPS2 tiene Guids presente, no están incluidas en el registro. Parece que los fabricantes de controladores de dispositivos de audio simplemente no se molestan en modificar estos valores: http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.mmedia/2006-08/msg00102.html –

+0

No todos los GUID existirán en el registro, en cuyo caso se supone que debe usar el nombre dentro de la estructura. (Por lo general, el registro solo se usa si el nombre es más largo que los 31 caracteres disponibles en la estructura). Si el nombre se trunca en 31 caracteres pero la clave no está en el registro, entonces tal vez los fabricantes eran flojos. :-( –

3

que completaron los nombres de los dispositivos WaveIn, la exploración de los nombres de regresar de MMDeviceEnumerator. Para cada dispositivo WaveIn, cuando el nombre incompleto forma parte del nombre completo de uno de EnumerateAudioEndPoints, utilicé este nombre completo para rellenar el cuadro combinado en el mismo orden que los dispositivos 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 
2

completa de código C# Mejora/WPF basado en respuesta @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; 
     } 
    } 
} 
Cuestiones relacionadas