- Add a few sanity checks
[reactos.git] / reactos / dll / directx / dsound_new / devicelist.c
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 (janderwald@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 }