xref: /reactos/dll/directx/dsound_new/devicelist.c (revision 40462c92)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Configuration of network devices
4  * FILE:            dll/directx/dsound_new/devicelist.c
5  * PURPOSE:         Enumeration of audio devices
6  *
7  * PROGRAMMERS:     Johannes Anderwald (johannes.anderwald@reactos.org)
8  */
9 
10 #include "precomp.h"
11 
12 ULONG
13 GetPinIdFromFilter(
14     LPFILTERINFO Filter,
15     BOOL bCapture,
16     ULONG Offset)
17 {
18     ULONG Index;
19 
20     for(Index = Offset; Index < Filter->PinCount; Index++)
21     {
22         if (Filter->Pin[Index] == PIN_TYPE_PLAYBACK && !bCapture)
23             return Index;
24 
25         if (Filter->Pin[Index] == PIN_TYPE_RECORDING && bCapture)
26             return Index;
27     }
28     return ULONG_MAX;
29 }
30 
31 
32 DWORD
33 OpenDeviceList(
34     IN LPGUID InterfaceGuid,
35     OUT HDEVINFO * OutHandle)
36 {
37     HDEVINFO DeviceHandle;
38 
39     DeviceHandle = SetupDiGetClassDevs(InterfaceGuid,
40                                        NULL,
41                                        NULL,
42                                        DIGCF_DEVICEINTERFACE); //DIGCF_PRESENT
43 
44     /* check for success */
45     if (DeviceHandle == INVALID_HANDLE_VALUE)
46     {
47         /* failed to create device list */
48         return GetLastError();
49     }
50 
51     /* store result */
52     *OutHandle = DeviceHandle;
53 
54     return ERROR_SUCCESS;
55 }
56 
57 BOOL
58 CloseDeviceList(
59     HDEVINFO Handle)
60 {
61     return SetupDiDestroyDeviceInfoList(Handle);
62 }
63 
64 BOOL
65 GetDeviceListInterfaces(
66     HDEVINFO DeviceHandle,
67     IN LPGUID InterfaceGuid,
68     LPFILTERINFO *OutPath)
69 {
70     ULONG Length, Index = 0;
71     SP_DEVICE_INTERFACE_DATA InterfaceData;
72     PSP_DEVICE_INTERFACE_DETAIL_DATA_W DetailData;
73     SP_DEVINFO_DATA DeviceData;
74     LPFILTERINFO LastDevice = NULL, RootDevice = NULL, CurDevice;
75     BOOL Result;
76 
77 
78     do
79     {
80         InterfaceData.cbSize = sizeof(InterfaceData);
81         InterfaceData.Reserved = 0;
82 
83         /* query device interface */
84         Result = SetupDiEnumDeviceInterfaces(DeviceHandle,
85                                 NULL,
86                                 InterfaceGuid,
87                                 Index,
88                                 &InterfaceData);
89 
90         if (!Result)
91         {
92             /* failed */
93             DPRINT("SetupDiEnumDeviceInterfaces Index %u failed with %lx\n", Index, GetLastError());
94             break;
95         }
96 
97         /* allocate device interface struct */
98         Length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR);
99         DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(),
100                                                                  HEAP_ZERO_MEMORY,
101                                                                  Length);
102 
103         if (!DetailData)
104         {
105             /* insufficient memory */
106             break;
107         }
108 
109         /* initialize device interface detail struct */
110         DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
111 
112         DeviceData.cbSize = sizeof(DeviceData);
113         DeviceData.Reserved = 0;
114 
115         Result = SetupDiGetDeviceInterfaceDetailW(DeviceHandle,
116                                                   &InterfaceData,
117                                                   DetailData,
118                                                   Length,
119                                                   NULL,
120                                                   &DeviceData);
121 
122        if (!Result)
123        {
124            /* failed */
125            DPRINT("SetupDiGetDeviceInterfaceDetail failed with %x\n", GetLastError());
126            HeapFree(GetProcessHeap(), 0, DetailData);
127 
128            break;
129        }
130 
131        /* allocate device path struct */
132        CurDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILTERINFO));
133        if (!CurDevice)
134        {
135            /* no memory */
136            HeapFree(GetProcessHeap(), 0, DetailData);
137            break;
138        }
139 
140        /* store device path */
141        CopyMemory(&CurDevice->DeviceData, &DeviceData, sizeof(SP_DEVINFO_DATA));
142        wcscpy(CurDevice->DevicePath, DetailData->DevicePath);
143        CurDevice->MappedId[0] = ULONG_MAX;
144        CurDevice->MappedId[1] = ULONG_MAX;
145 
146        DPRINT("DevicePath %S\n", CurDevice->DevicePath);
147 
148        if (!RootDevice)
149            RootDevice = CurDevice;
150 
151        if (LastDevice)
152        {
153            LastDevice->lpNext = CurDevice;
154        }
155 
156        /* set as last device */
157        LastDevice = CurDevice;
158 
159         /* free device interface struct */
160         HeapFree(GetProcessHeap(), 0, DetailData);
161 
162        /* increment device interface index */
163        Index++;
164     }while(TRUE);
165 
166     /* store result */
167     *OutPath = RootDevice;
168 
169     if (!RootDevice)
170         return FALSE;
171 
172 
173     return TRUE;
174 }
175 
176 DWORD
177 OpenDeviceKey(
178     HDEVINFO Handle,
179     PSP_DEVINFO_DATA  FILTERINFOData,
180     DWORD KeyType,
181     REGSAM DesiredAccess,
182     OUT HKEY * OutKey)
183 {
184     HKEY hKey;
185 
186     /* try open device registry key */
187     hKey = SetupDiOpenDevRegKey(Handle, FILTERINFOData, DICS_FLAG_CONFIGSPECIFIC, 0, KeyType, DesiredAccess);
188 
189     if (hKey == INVALID_HANDLE_VALUE)
190         return GetLastError();
191 
192     /* store result */
193     *OutKey = hKey;
194 
195     return ERROR_SUCCESS;
196 }
197 
198 VOID
199 FindAudioFilterPins(
200     LPFILTERINFO CurInfo,
201     OUT PULONG WaveInPins,
202     OUT PULONG WaveOutPins)
203 {
204     ULONG Index;
205     KSPIN_COMMUNICATION Communication;
206     KSPIN_DATAFLOW DataFlow;
207 
208     *WaveInPins = 0;
209     *WaveOutPins = 0;
210 
211     /* traverse all pins */
212     for(Index = 0; Index < CurInfo->PinCount; Index++)
213     {
214         if (GetFilterPinCommunication(CurInfo->hFilter, Index, &Communication) == ERROR_SUCCESS &&
215             GetFilterPinDataFlow(CurInfo->hFilter, Index, &DataFlow) == ERROR_SUCCESS)
216         {
217             if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
218             {
219                 /* found a wave out device */
220                 CurInfo->Pin[Index] = PIN_TYPE_PLAYBACK;
221                 (*WaveOutPins)++;
222             }
223             else if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
224             {
225                 /* found a wave in device */
226                 CurInfo->Pin[Index] = PIN_TYPE_RECORDING;
227                 (*WaveInPins)++;
228             }
229             else
230             {
231                 /* bridge pin / topology pin etc */
232                 CurInfo->Pin[Index] = PIN_TYPE_NONE;
233             }
234         }
235         else
236         {
237             /* bridge pin / topology pin etc */
238             CurInfo->Pin[Index] = PIN_TYPE_NONE;
239         }
240     }
241 }
242 
243 BOOL
244 FindWinMMDeviceIndex(
245     LPFILTERINFO CurInfo,
246     BOOL bRecord)
247 {
248     ULONG DeviceCount, Index;
249     WCHAR Buffer[MAX_PATH];
250     DWORD Size, dwResult;
251 
252     if (bRecord)
253         DeviceCount = waveInGetNumDevs();
254     else
255         DeviceCount = waveOutGetNumDevs();
256 
257     /* sanity check */
258     //ASSERT(DeviceCount);
259 
260     for(Index = 0; Index < DeviceCount; Index++)
261     {
262         Size = 0;
263 
264         /* query device interface size */
265         if (bRecord)
266             dwResult = waveInMessage(UlongToHandle(Index), DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&Size, 0);
267         else
268             dwResult = waveOutMessage(UlongToHandle(Index), DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&Size, 0);
269 
270         if (dwResult != MMSYSERR_NOERROR)
271         {
272             DPRINT("Failed DRV_QUERYDEVICEINTERFACESIZE with %lx bRecord %u Index %u\n", dwResult, bRecord, Index);
273             continue;
274         }
275 
276         /* sanity check */
277         ASSERT(Size < MAX_PATH);
278 
279         /* now get the device interface string */
280         if (bRecord)
281             dwResult = waveInMessage(UlongToHandle(Index), DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)Buffer, MAX_PATH);
282         else
283             dwResult = waveOutMessage(UlongToHandle(Index), DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)Buffer, MAX_PATH);
284 
285         if (dwResult != MMSYSERR_NOERROR)
286         {
287             DPRINT("Failed DRV_QUERYDEVICEINTERFACE with %lx bRecord %u Index %u\n", dwResult, bRecord, Index);
288             continue;
289         }
290 
291         if (!wcsicmp(CurInfo->DevicePath, Buffer))
292         {
293             if (bRecord)
294                 CurInfo->MappedId[0] = Index;
295             else
296                 CurInfo->MappedId[1] = Index;
297 
298             return TRUE;
299         }
300     }
301 
302     DPRINT1("Failed to find device %ws bRecord %u Count %u\n", CurInfo->DevicePath, bRecord, DeviceCount);
303 
304     // HACK
305     if (bRecord)
306         CurInfo->MappedId[0] = 0;
307     else
308         CurInfo->MappedId[1] = 0;
309 
310 
311     return TRUE;
312 }
313 
314 HRESULT
315 EnumerateAudioFilter(
316     LPFILTERINFO CurInfo,
317     OUT PULONG WaveInCount,
318     OUT PULONG WaveOutCount)
319 {
320     DWORD Status;
321     ULONG PinCount, WaveInPins, WaveOutPins;
322 
323     /* first step open filter */
324     Status = OpenFilter((LPCWSTR)CurInfo->DevicePath, &CurInfo->hFilter);
325     if (Status != ERROR_SUCCESS)
326     {
327         DPRINT("Failed to open filter with %lx Path %ws\n", Status, CurInfo->DevicePath);
328         return E_FAIL;
329     }
330 
331     /* get filter pin count */
332     Status = GetFilterPinCount(CurInfo->hFilter, &PinCount);
333     if (Status != ERROR_SUCCESS)
334     {
335         DPRINT("Failed to get pin count with %lx\n", Status);
336         return E_FAIL;
337     }
338 
339     /* sanity check */
340     ASSERT(PinCount);
341 
342     /* store pin count */
343     CurInfo->PinCount = PinCount;
344 
345     /* now allocate an pin array */
346     CurInfo->Pin = HeapAlloc(GetProcessHeap(), 0, PinCount * sizeof(ULONG));
347     if (!CurInfo->Pin)
348     {
349         /* no memory */
350         return E_FAIL;
351     }
352 
353     /* no try to find playback / recording pins */
354     FindAudioFilterPins(CurInfo, &WaveInPins, &WaveOutPins);
355 
356     DPRINT("WaveInPins %u WaveOutPins %u %S\n", WaveInPins, WaveOutPins, CurInfo->DevicePath);
357 
358     if (WaveOutPins)
359     {
360         /* create a unique guid for this playback device */
361         if (FindWinMMDeviceIndex(CurInfo, TRUE))
362         {
363             (*WaveOutCount)++;
364             INIT_GUID(CurInfo->DeviceGuid[0], 0xbd6dd71a, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + *WaveInCount);
365         }
366     }
367 
368 
369     if (WaveInPins)
370     {
371         if (FindWinMMDeviceIndex(CurInfo, FALSE))
372         {
373             /* create a unique guid for this record device */
374             (*WaveInCount)++;
375             INIT_GUID(CurInfo->DeviceGuid[1], 0xbd6dd71b, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + *WaveOutCount);
376         }
377     }
378 
379     return S_OK;
380 }
381 
382 
383 HRESULT
384 EnumAudioDeviceInterfaces(
385     LPFILTERINFO *OutRootInfo)
386 {
387     HDEVINFO hList;
388     DWORD Status;
389     HRESULT hResult;
390     ULONG WaveOutCount, WaveInCount;
391     GUID AudioDeviceGuid = {STATIC_KSCATEGORY_AUDIO};
392     LPFILTERINFO CurInfo;
393 
394     /* try open the device list */
395     Status = OpenDeviceList(&AudioDeviceGuid, &hList);
396 
397     if (Status != ERROR_SUCCESS)
398     {
399         DPRINT1("OpenDeviceList failed with %lx\n", Status);
400         return E_FAIL;
401     }
402 
403     if (!GetDeviceListInterfaces(hList, &AudioDeviceGuid, OutRootInfo))
404     {
405         DPRINT1("No devices found\n");
406         CloseDeviceList(hList);
407         return S_FALSE;
408     }
409 
410     /* sanity check */
411     ASSERT(*OutRootInfo);
412 
413     CurInfo = *OutRootInfo;
414 
415     WaveOutCount = 0;
416     WaveInCount = 0;
417 
418     /* now check all audio filters */
419     while(CurInfo)
420     {
421         /* now check details of the audio filter */
422         hResult = EnumerateAudioFilter(CurInfo, &WaveInCount, &WaveOutCount);
423 
424         if (hResult != S_OK)
425         {
426            DPRINT1("EnumerateAudioFilter failed with %lx\n", Status);
427            break;
428         }
429 
430         /* move to next filter */
431         CurInfo = CurInfo->lpNext;
432     }
433 
434     /* close device list */
435     CloseDeviceList(hList);
436 
437     /* done */
438     return hResult;
439 }
440 
441 BOOL
442 FindDeviceByMappedId(
443     IN ULONG DeviceID,
444     LPFILTERINFO *Filter,
445     BOOL bPlayback)
446 {
447     LPFILTERINFO CurInfo;
448     if (!RootInfo)
449         return FALSE;
450 
451     /* get first entry */
452     CurInfo = RootInfo;
453 
454     while(CurInfo)
455     {
456         if ((bPlayback && CurInfo->MappedId[1] == DeviceID) ||
457             (!bPlayback && CurInfo->MappedId[0] == DeviceID))
458         {
459             /* found filter */
460             *Filter = CurInfo;
461             return TRUE;
462         }
463 
464         CurInfo = CurInfo->lpNext;
465     }
466     return FALSE;
467 }
468 
469 BOOL
470 FindDeviceByGuid(
471     LPCGUID pGuidSrc,
472     LPFILTERINFO *Filter)
473 {
474     LPFILTERINFO CurInfo;
475     if (!RootInfo)
476         return FALSE;
477 
478     /* get first entry */
479     CurInfo = RootInfo;
480 
481     while(CurInfo)
482     {
483         if (IsEqualGUID(&CurInfo->DeviceGuid[0], pGuidSrc) ||
484             IsEqualGUID(&CurInfo->DeviceGuid[1], pGuidSrc))
485         {
486             /* found filter */
487             *Filter = CurInfo;
488             return TRUE;
489         }
490 
491         CurInfo = CurInfo->lpNext;
492     }
493 
494     return FALSE;
495 }
496