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