2009-09-19 9 views
9

Używam waveInGetDevCaps, aby uzyskać nazwy urządzeń waveIn, ale struktura WAVEINCAPS obsługuje tylko 31 znaków plus zero, co oznacza, że ​​na moim komputerze nazwy urządzeń, które otrzymuję, są obcinane :Pobierz pełną nazwę urządzenia waveIn

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

Jestem pewien, że musi istnieć sposób na uzyskanie pełnej nazwy urządzenia, ale czy ktoś wie, co to jest?

Odpowiedz

7

Tak, istnieje obejście. Rozwiązałem ten problem kilka razy w kodzie wysyłki.

Wylicz urządzenia audio z DirectSoundCapture. API to DirectSoundCaptureEnumerate. Zwróci ci pełną nazwę urządzeń.

Oczywiście, prawdopodobnie myślisz: "To świetnie, ale reszta mojego kodu jest skonfigurowana do korzystania z Wave API, a nie DirectSound. Nie chcę przełączać wszystkiego." Jak mogę odwzorować Identyfikatory GUID zwrócone przez DirectSoundCaptureEnumerate do liczb całkowitych używanych przez interfejs API WaveIn? "

Rozwiązaniem jest CoCreateInstance dla obiektu DirectSoundPrivate (lub wywołanie GetClassObject bezpośrednio z dsound.dll), aby uzyskać wskaźnik do interfejsu IKsPropertySet. Z tego interfejsu można uzyskać identyfikator GUID DSound do odwzorowania Wave ID. Więcej szczegółów można znaleźć tej strony internetowej:

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

chcesz użyć DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING jak opisano na stronie internetowej podanej powyżej.

+0

dzięki, to jest naprawdę pomocny (chociaż szkoda, że ​​musi być tak zawiłe) –

+1

że odwołuje wydaje się być uszkodzony . masz inny link lub przynajmniej tytuł artykułu na temat msdn? –

+2

Inną metodą uzyskania identyfikatora GUID jest wywołanie waveOutGetDevCaps ze strukturą WAVEOUTCAPS2 o numerze , a nie ze zwykłą strukturą WAVEOUTCAPS. http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382%28v=vs.85%29.aspx – leiflundgren

2

Wygląda na to, że DirectSoundPrivate ma pewne problemy. Próbuję uzyskać do niego dostęp z pustego projektu i działa dobrze. Jednak gdy próbuję uzyskać dostęp do niego z COM DLL lub z wątku DLL, zwraca E_NOTIMPL błąd z IKsPropertySet::Get.

Ale wymyśliłem kolejną sztuczkę. Wygląda na to, że DirectSound wylicza przechwytywanie i renderowanie urządzeń w kolejności falowej (z wyłączeniem pierwszej wartości domyślnej).

Nadal musimy wchodzić w interakcje ze starym interfejsem API Wave i nadal nie ma na to odpowiedniego sposobu. DirectShow udostępnia urządzenia wejściowe audio oparte na WaveIn i muszę uzyskać odpowiedni identyfikator WASAPI i odwrotnie.

3

Istnieje sposób obejmujący rejestr, który jest prostszy niż użycie DirectSound. Jeśli używasz struktury WAVEINCAPS2, ma ona nazwę GUID, która odwołuje się do klucza w HKLM \ System \ CurrentControlSet \ Control \ MediaCategories. Jeśli klucz nie istnieje, po prostu użyj nazwy w strukturze. Jest to udokumentowane na http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382%28v=vs.85%29.aspx. Oto przykład:

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

dzięki za zwrócenie mi tej uwagi. Wygląda obiecująco, ale niestety moje testy (w Win 7) wykazały, że chociaż struktura WAVEINCAPS2 ma Guidy, nie są one zawarte w rejestrze. Wygląda na to, że producenci sterowników urządzeń audio po prostu nie zadają sobie trudu modyfikacji tych wartości: http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.mmedia/2006-08/msg00102.html –

+0

Not wszystkie identyfikatory GUID będą istnieć w rejestrze, w takim przypadku należy użyć nazwy w strukturze. (Zwykle rejestr jest używany tylko wtedy, gdy nazwa jest dłuższa niż 31 znaków dostępnych w strukturze.) Jeśli nazwa jest obcięta do 31 znaków, ale klucz nie znajduje się w rejestrze, być może producenci byli leniwi. :-( –

3

Uzupełniłem nazwy urządzeń waveIn, eksplorując nazwy zwrócone przez MMDeviceEnumerator. Dla każdego urządzenia waveIn, gdy nazwa niekompletna jest częścią pełnej nazwy jednego z EnumerateAudioEndPoints, użyłem tej pełnej nazwy do zapełnienia combobox w tej samej kolejności urządzeń 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

Ulepszona/pełny C# kod WPF na podstawie @Andrea Bertucelli odpowiedź

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; 
     } 
    } 
} 
Powiązane problemy