1 /* 2 * PROJECT: ReactOS Sound System 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/win32/wdmaud.drv/mmixer.c 5 * 6 * PURPOSE: WDM Audio Mixer API (User-mode part) 7 * PROGRAMMERS: Johannes Anderwald 8 */ 9 10 #include "wdmaud.h" 11 12 #include <winreg.h> 13 #include <setupapi.h> 14 #include <mmixer.h> 15 16 #define NDEBUG 17 #include <debug.h> 18 #include <mmebuddy_debug.h> 19 20 typedef struct 21 { 22 KSSTREAM_HEADER Header; 23 HANDLE hDevice; 24 PSOUND_OVERLAPPED Overlap; 25 LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine; 26 DWORD IoCtl; 27 }IO_PACKET, *LPIO_PACKET; 28 29 BOOL MMixerLibraryInitialized = FALSE; 30 31 32 33 PVOID Alloc(ULONG NumBytes); 34 MIXER_STATUS Close(HANDLE hDevice); 35 VOID Free(PVOID Block); 36 VOID Copy(PVOID Src, PVOID Dst, ULONG NumBytes); 37 MIXER_STATUS Open(IN LPWSTR DevicePath, OUT PHANDLE hDevice); 38 MIXER_STATUS Control(IN HANDLE hMixer, IN ULONG dwIoControlCode, IN PVOID lpInBuffer, IN ULONG nInBufferSize, OUT PVOID lpOutBuffer, ULONG nOutBufferSize, PULONG lpBytesReturned); 39 MIXER_STATUS Enum(IN PVOID EnumContext, IN ULONG DeviceIndex, OUT LPWSTR * DeviceName, OUT PHANDLE OutHandle, OUT PHANDLE OutKey); 40 MIXER_STATUS OpenKey(IN HANDLE hKey, IN LPWSTR SubKey, IN ULONG DesiredAccess, OUT PHANDLE OutKey); 41 MIXER_STATUS CloseKey(IN HANDLE hKey); 42 MIXER_STATUS QueryKeyValue(IN HANDLE hKey, IN LPWSTR KeyName, OUT PVOID * ResultBuffer, OUT PULONG ResultLength, OUT PULONG KeyType); 43 PVOID AllocEventData(IN ULONG ExtraSize); 44 VOID FreeEventData(IN PVOID EventData); 45 46 MIXER_CONTEXT MixerContext = 47 { 48 sizeof(MIXER_CONTEXT), 49 NULL, 50 Alloc, 51 Control, 52 Free, 53 Open, 54 Close, 55 Copy, 56 OpenKey, 57 QueryKeyValue, 58 CloseKey, 59 AllocEventData, 60 FreeEventData 61 }; 62 63 GUID CategoryGuid = {STATIC_KSCATEGORY_AUDIO}; 64 65 MIXER_STATUS 66 QueryKeyValue( 67 IN HANDLE hKey, 68 IN LPWSTR KeyName, 69 OUT PVOID * ResultBuffer, 70 OUT PULONG ResultLength, 71 OUT PULONG KeyType) 72 { 73 if (RegQueryValueExW((HKEY)hKey, KeyName, NULL, KeyType, NULL, ResultLength) == ERROR_FILE_NOT_FOUND) 74 return MM_STATUS_UNSUCCESSFUL; 75 76 *ResultBuffer = HeapAlloc(GetProcessHeap(), 0, *ResultLength); 77 if (*ResultBuffer == NULL) 78 return MM_STATUS_NO_MEMORY; 79 80 if (RegQueryValueExW((HKEY)hKey, KeyName, NULL, KeyType, *ResultBuffer, ResultLength) != ERROR_SUCCESS) 81 { 82 HeapFree(GetProcessHeap(), 0, *ResultBuffer); 83 return MM_STATUS_UNSUCCESSFUL; 84 } 85 return MM_STATUS_SUCCESS; 86 } 87 88 MIXER_STATUS 89 OpenKey( 90 IN HANDLE hKey, 91 IN LPWSTR SubKey, 92 IN ULONG DesiredAccess, 93 OUT PHANDLE OutKey) 94 { 95 if (RegOpenKeyExW((HKEY)hKey, SubKey, 0, DesiredAccess, (PHKEY)OutKey) == ERROR_SUCCESS) 96 return MM_STATUS_SUCCESS; 97 98 return MM_STATUS_UNSUCCESSFUL; 99 } 100 101 MIXER_STATUS 102 CloseKey( 103 IN HANDLE hKey) 104 { 105 RegCloseKey((HKEY)hKey); 106 return MM_STATUS_SUCCESS; 107 } 108 109 110 PVOID Alloc(ULONG NumBytes) 111 { 112 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, NumBytes); 113 } 114 115 MIXER_STATUS 116 Close(HANDLE hDevice) 117 { 118 if (CloseHandle(hDevice)) 119 return MM_STATUS_SUCCESS; 120 else 121 return MM_STATUS_UNSUCCESSFUL; 122 } 123 124 VOID 125 Free(PVOID Block) 126 { 127 HeapFree(GetProcessHeap(), 0, Block); 128 } 129 130 VOID 131 Copy(PVOID Src, PVOID Dst, ULONG NumBytes) 132 { 133 RtlMoveMemory(Src, Dst, NumBytes); 134 } 135 136 MIXER_STATUS 137 Open( 138 IN LPWSTR DevicePath, 139 OUT PHANDLE hDevice) 140 { 141 DevicePath[1] = L'\\'; 142 *hDevice = CreateFileW(DevicePath, 143 GENERIC_READ | GENERIC_WRITE, 144 0, 145 NULL, 146 OPEN_EXISTING, 147 FILE_FLAG_OVERLAPPED, 148 NULL); 149 if (*hDevice == INVALID_HANDLE_VALUE) 150 { 151 return MM_STATUS_UNSUCCESSFUL; 152 } 153 154 return MM_STATUS_SUCCESS; 155 } 156 157 MIXER_STATUS 158 Control( 159 IN HANDLE hMixer, 160 IN ULONG dwIoControlCode, 161 IN PVOID lpInBuffer, 162 IN ULONG nInBufferSize, 163 OUT PVOID lpOutBuffer, 164 ULONG nOutBufferSize, 165 PULONG lpBytesReturned) 166 { 167 OVERLAPPED Overlapped; 168 BOOLEAN IoResult; 169 DWORD Transferred = 0; 170 171 /* Overlapped I/O is done here - this is used for waiting for completion */ 172 ZeroMemory(&Overlapped, sizeof(OVERLAPPED)); 173 Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 174 175 if ( ! Overlapped.hEvent ) 176 return MM_STATUS_NO_MEMORY; 177 178 /* Talk to the device */ 179 IoResult = DeviceIoControl(hMixer, 180 dwIoControlCode, 181 lpInBuffer, 182 nInBufferSize, 183 lpOutBuffer, 184 nOutBufferSize, 185 &Transferred, 186 &Overlapped); 187 188 /* If failure occurs, make sure it's not just due to the overlapped I/O */ 189 if ( ! IoResult ) 190 { 191 if ( GetLastError() != ERROR_IO_PENDING ) 192 { 193 CloseHandle(Overlapped.hEvent); 194 195 if (GetLastError() == ERROR_MORE_DATA || GetLastError() == ERROR_INSUFFICIENT_BUFFER) 196 { 197 if ( lpBytesReturned ) 198 *lpBytesReturned = Transferred; 199 return MM_STATUS_MORE_ENTRIES; 200 } 201 202 return MM_STATUS_UNSUCCESSFUL; 203 } 204 } 205 206 /* Wait for the I/O to complete */ 207 IoResult = GetOverlappedResult(hMixer, 208 &Overlapped, 209 &Transferred, 210 TRUE); 211 212 /* Don't need this any more */ 213 CloseHandle(Overlapped.hEvent); 214 215 if ( ! IoResult ) 216 return MM_STATUS_UNSUCCESSFUL; 217 218 if ( lpBytesReturned ) 219 *lpBytesReturned = Transferred; 220 221 return MM_STATUS_SUCCESS; 222 } 223 224 MIXER_STATUS 225 Enum( 226 IN PVOID EnumContext, 227 IN ULONG DeviceIndex, 228 OUT LPWSTR * DeviceName, 229 OUT PHANDLE OutHandle, 230 OUT PHANDLE OutKey) 231 { 232 SP_DEVICE_INTERFACE_DATA InterfaceData; 233 SP_DEVINFO_DATA DeviceData; 234 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DetailData; 235 BOOL Result; 236 DWORD Length; 237 MIXER_STATUS Status; 238 239 //printf("Enum EnumContext %p DeviceIndex %lu OutHandle %p\n", EnumContext, DeviceIndex, OutHandle); 240 241 InterfaceData.cbSize = sizeof(InterfaceData); 242 InterfaceData.Reserved = 0; 243 244 Result = SetupDiEnumDeviceInterfaces(EnumContext, 245 NULL, 246 &CategoryGuid, 247 DeviceIndex, 248 &InterfaceData); 249 250 if (!Result) 251 { 252 if (GetLastError() == ERROR_NO_MORE_ITEMS) 253 { 254 return MM_STATUS_NO_MORE_DEVICES; 255 } 256 return MM_STATUS_UNSUCCESSFUL; 257 } 258 259 Length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR); 260 DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 261 0, 262 Length); 263 DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); 264 DeviceData.cbSize = sizeof(DeviceData); 265 DeviceData.Reserved = 0; 266 267 Result = SetupDiGetDeviceInterfaceDetailW(EnumContext, 268 &InterfaceData, 269 DetailData, 270 Length, 271 NULL, 272 &DeviceData); 273 274 if (!Result) 275 { 276 DPRINT("SetupDiGetDeviceInterfaceDetailW failed with %lu\n", GetLastError()); 277 return MM_STATUS_UNSUCCESSFUL; 278 } 279 280 281 *OutKey = SetupDiOpenDeviceInterfaceRegKey(EnumContext, &InterfaceData, 0, KEY_READ); 282 if ((HKEY)*OutKey == INVALID_HANDLE_VALUE) 283 { 284 HeapFree(GetProcessHeap(), 0, DetailData); 285 return MM_STATUS_UNSUCCESSFUL; 286 } 287 288 Status = Open(DetailData->DevicePath, OutHandle); 289 290 if (Status != MM_STATUS_SUCCESS) 291 { 292 RegCloseKey((HKEY)*OutKey); 293 HeapFree(GetProcessHeap(), 0, DetailData); 294 return Status; 295 } 296 297 *DeviceName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(DetailData->DevicePath)+1) * sizeof(WCHAR)); 298 if (*DeviceName == NULL) 299 { 300 CloseHandle(*OutHandle); 301 RegCloseKey((HKEY)*OutKey); 302 HeapFree(GetProcessHeap(), 0, DetailData); 303 return MM_STATUS_NO_MEMORY; 304 } 305 wcscpy(*DeviceName, DetailData->DevicePath); 306 HeapFree(GetProcessHeap(), 0, DetailData); 307 308 return Status; 309 } 310 311 PVOID 312 AllocEventData( 313 IN ULONG ExtraSize) 314 { 315 PKSEVENTDATA Data = (PKSEVENTDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KSEVENTDATA) + ExtraSize); 316 if (!Data) 317 return NULL; 318 319 Data->EventHandle.Event = CreateEventW(NULL, FALSE, FALSE, NULL); 320 if (!Data->EventHandle.Event) 321 { 322 HeapFree(GetProcessHeap(), 0, Data); 323 return NULL; 324 } 325 326 Data->NotificationType = KSEVENTF_EVENT_HANDLE; 327 return Data; 328 } 329 330 VOID 331 FreeEventData(IN PVOID EventData) 332 { 333 PKSEVENTDATA Data = (PKSEVENTDATA)EventData; 334 335 CloseHandle(Data->EventHandle.Event); 336 HeapFree(GetProcessHeap(), 0, Data); 337 } 338 339 340 BOOL 341 WdmAudInitUserModeMixer() 342 { 343 HDEVINFO DeviceHandle; 344 MIXER_STATUS Status; 345 346 if (MMixerLibraryInitialized) 347 { 348 /* library is already initialized */ 349 return TRUE; 350 } 351 352 353 /* create a device list */ 354 DeviceHandle = SetupDiGetClassDevs(&CategoryGuid, 355 NULL, 356 NULL, 357 DIGCF_DEVICEINTERFACE/* FIXME |DIGCF_PRESENT*/); 358 359 if (DeviceHandle == INVALID_HANDLE_VALUE) 360 { 361 /* failed to create a device list */ 362 return FALSE; 363 } 364 365 366 /* initialize the mixer library */ 367 Status = MMixerInitialize(&MixerContext, Enum, (PVOID)DeviceHandle); 368 369 /* free device list */ 370 SetupDiDestroyDeviceInfoList(DeviceHandle); 371 372 if (Status != MM_STATUS_SUCCESS) 373 { 374 /* failed to initialize mixer library */ 375 DPRINT1("Failed to initialize mixer library with %x\n", Status); 376 return FALSE; 377 } 378 379 /* library is now initialized */ 380 MMixerLibraryInitialized = TRUE; 381 382 /* completed successfully */ 383 return TRUE; 384 } 385 386 MMRESULT 387 WdmAudCleanupByMMixer() 388 { 389 /* TODO */ 390 return MMSYSERR_NOERROR; 391 } 392 393 MMRESULT 394 WdmAudGetMixerCapabilities( 395 IN ULONG DeviceId, 396 LPMIXERCAPSW Capabilities) 397 { 398 if (MMixerGetCapabilities(&MixerContext, DeviceId, Capabilities) == MM_STATUS_SUCCESS) 399 return MMSYSERR_NOERROR; 400 401 return MMSYSERR_BADDEVICEID; 402 } 403 404 MMRESULT 405 WdmAudGetLineInfo( 406 IN HANDLE hMixer, 407 IN DWORD MixerId, 408 IN LPMIXERLINEW MixLine, 409 IN ULONG Flags) 410 { 411 if (MMixerGetLineInfo(&MixerContext, hMixer, MixerId, Flags, MixLine) == MM_STATUS_SUCCESS) 412 return MMSYSERR_NOERROR; 413 414 return MMSYSERR_ERROR; 415 } 416 417 MMRESULT 418 WdmAudGetLineControls( 419 IN HANDLE hMixer, 420 IN DWORD MixerId, 421 IN LPMIXERLINECONTROLSW MixControls, 422 IN ULONG Flags) 423 { 424 if (MMixerGetLineControls(&MixerContext, hMixer, MixerId, Flags, MixControls) == MM_STATUS_SUCCESS) 425 return MMSYSERR_NOERROR; 426 427 return MMSYSERR_ERROR; 428 } 429 430 MMRESULT 431 WdmAudSetControlDetails( 432 IN HANDLE hMixer, 433 IN DWORD MixerId, 434 IN LPMIXERCONTROLDETAILS MixDetails, 435 IN ULONG Flags) 436 { 437 if (MMixerSetControlDetails(&MixerContext, hMixer, MixerId, Flags, MixDetails) == MM_STATUS_SUCCESS) 438 return MMSYSERR_NOERROR; 439 440 return MMSYSERR_ERROR; 441 442 } 443 444 MMRESULT 445 WdmAudGetControlDetails( 446 IN HANDLE hMixer, 447 IN DWORD MixerId, 448 IN LPMIXERCONTROLDETAILS MixDetails, 449 IN ULONG Flags) 450 { 451 if (MMixerGetControlDetails(&MixerContext, hMixer, MixerId, Flags, MixDetails) == MM_STATUS_SUCCESS) 452 return MMSYSERR_NOERROR; 453 454 return MMSYSERR_ERROR; 455 } 456 457 MMRESULT 458 WdmAudGetWaveOutCapabilities( 459 IN ULONG DeviceId, 460 LPWAVEOUTCAPSW Capabilities) 461 { 462 if (MMixerWaveOutCapabilities(&MixerContext, DeviceId, Capabilities) == MM_STATUS_SUCCESS) 463 return MMSYSERR_NOERROR; 464 465 return MMSYSERR_ERROR; 466 467 } 468 469 MMRESULT 470 WdmAudGetWaveInCapabilities( 471 IN ULONG DeviceId, 472 LPWAVEINCAPSW Capabilities) 473 { 474 if (MMixerWaveInCapabilities(&MixerContext, DeviceId, Capabilities) == MM_STATUS_SUCCESS) 475 return MMSYSERR_NOERROR; 476 477 return MMSYSERR_ERROR; 478 } 479 480 MMRESULT 481 WdmAudSetWaveDeviceFormatByMMixer( 482 IN PSOUND_DEVICE_INSTANCE Instance, 483 IN DWORD DeviceId, 484 IN PWAVEFORMATEX WaveFormat, 485 IN DWORD WaveFormatSize) 486 { 487 MMDEVICE_TYPE DeviceType; 488 PSOUND_DEVICE SoundDevice; 489 MMRESULT Result; 490 BOOL bWaveIn; 491 492 Result = GetSoundDeviceFromInstance(Instance, &SoundDevice); 493 494 if ( ! MMSUCCESS(Result) ) 495 { 496 return TranslateInternalMmResult(Result); 497 } 498 499 Result = GetSoundDeviceType(SoundDevice, &DeviceType); 500 SND_ASSERT( Result == MMSYSERR_NOERROR ); 501 502 bWaveIn = (DeviceType == WAVE_IN_DEVICE_TYPE ? TRUE : FALSE); 503 504 if (MMixerOpenWave(&MixerContext, DeviceId, bWaveIn, WaveFormat, NULL, NULL, &Instance->Handle) == MM_STATUS_SUCCESS) 505 { 506 if (DeviceType == WAVE_OUT_DEVICE_TYPE) 507 { 508 MMixerSetWaveStatus(&MixerContext, Instance->Handle, KSSTATE_ACQUIRE); 509 MMixerSetWaveStatus(&MixerContext, Instance->Handle, KSSTATE_PAUSE); 510 MMixerSetWaveStatus(&MixerContext, Instance->Handle, KSSTATE_RUN); 511 } 512 return MMSYSERR_NOERROR; 513 } 514 return MMSYSERR_ERROR; 515 } 516 517 518 MMRESULT 519 WdmAudGetCapabilitiesByMMixer( 520 IN PSOUND_DEVICE SoundDevice, 521 IN DWORD DeviceId, 522 OUT PVOID Capabilities, 523 IN DWORD CapabilitiesSize) 524 { 525 MMDEVICE_TYPE DeviceType; 526 MMRESULT Result; 527 528 Result = GetSoundDeviceType(SoundDevice, &DeviceType); 529 SND_ASSERT( Result == MMSYSERR_NOERROR ); 530 531 if (DeviceType == MIXER_DEVICE_TYPE) 532 { 533 return WdmAudGetMixerCapabilities(DeviceId, (LPMIXERCAPSW)Capabilities); 534 } 535 else if (DeviceType == WAVE_OUT_DEVICE_TYPE) 536 { 537 return WdmAudGetWaveOutCapabilities(DeviceId, (LPWAVEOUTCAPSW)Capabilities); 538 } 539 else if (DeviceType == WAVE_IN_DEVICE_TYPE) 540 { 541 return WdmAudGetWaveInCapabilities(DeviceId, (LPWAVEINCAPSW)Capabilities); 542 } 543 else 544 { 545 // not supported 546 return MMSYSERR_ERROR; 547 } 548 } 549 550 MMRESULT 551 WdmAudOpenSoundDeviceByMMixer( 552 IN struct _SOUND_DEVICE* SoundDevice, 553 OUT PVOID* Handle) 554 { 555 if (WdmAudInitUserModeMixer()) 556 return MMSYSERR_NOERROR; 557 else 558 return MMSYSERR_ERROR; 559 } 560 561 MMRESULT 562 WdmAudCloseSoundDeviceByMMixer( 563 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, 564 IN PVOID Handle) 565 { 566 MMDEVICE_TYPE DeviceType; 567 PSOUND_DEVICE SoundDevice; 568 MMRESULT Result; 569 570 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 571 572 if ( ! MMSUCCESS(Result) ) 573 { 574 return TranslateInternalMmResult(Result); 575 } 576 577 Result = GetSoundDeviceType(SoundDevice, &DeviceType); 578 SND_ASSERT( Result == MMSYSERR_NOERROR ); 579 580 if (DeviceType == MIXER_DEVICE_TYPE) 581 { 582 /* no op */ 583 return MMSYSERR_NOERROR; 584 } 585 else if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE) 586 { 587 /* make sure the pin is stopped */ 588 MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_PAUSE); 589 MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_ACQUIRE); 590 MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_STOP); 591 592 CloseHandle(Handle); 593 return MMSYSERR_NOERROR; 594 } 595 596 /* midi is not supported */ 597 return MMSYSERR_ERROR; 598 } 599 600 MMRESULT 601 WdmAudGetNumWdmDevsByMMixer( 602 IN MMDEVICE_TYPE DeviceType, 603 OUT DWORD* DeviceCount) 604 { 605 switch(DeviceType) 606 { 607 case MIXER_DEVICE_TYPE: 608 *DeviceCount = MMixerGetCount(&MixerContext); 609 break; 610 case WAVE_OUT_DEVICE_TYPE: 611 *DeviceCount = MMixerGetWaveOutCount(&MixerContext); 612 break; 613 case WAVE_IN_DEVICE_TYPE: 614 *DeviceCount = MMixerGetWaveInCount(&MixerContext); 615 break; 616 default: 617 *DeviceCount = 0; 618 } 619 return MMSYSERR_NOERROR; 620 } 621 622 MMRESULT 623 WdmAudQueryMixerInfoByMMixer( 624 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, 625 IN DWORD MixerId, 626 IN UINT uMsg, 627 IN LPVOID Parameter, 628 IN DWORD Flags) 629 { 630 LPMIXERLINEW MixLine; 631 LPMIXERLINECONTROLSW MixControls; 632 LPMIXERCONTROLDETAILS MixDetails; 633 HANDLE hMixer = NULL; 634 635 MixLine = (LPMIXERLINEW)Parameter; 636 MixControls = (LPMIXERLINECONTROLSW)Parameter; 637 MixDetails = (LPMIXERCONTROLDETAILS)Parameter; 638 639 /* FIXME param checks */ 640 641 if (SoundDeviceInstance) 642 { 643 hMixer = SoundDeviceInstance->Handle; 644 } 645 646 switch(uMsg) 647 { 648 case MXDM_GETLINEINFO: 649 return WdmAudGetLineInfo(hMixer, MixerId, MixLine, Flags); 650 case MXDM_GETLINECONTROLS: 651 return WdmAudGetLineControls(hMixer, MixerId, MixControls, Flags); 652 case MXDM_SETCONTROLDETAILS: 653 return WdmAudSetControlDetails(hMixer, MixerId, MixDetails, Flags); 654 case MXDM_GETCONTROLDETAILS: 655 return WdmAudGetControlDetails(hMixer, MixerId, MixDetails, Flags); 656 default: 657 DPRINT1("MixerId %lu, uMsg %lu, Parameter %p, Flags %lu\n", MixerId, uMsg, Parameter, Flags); 658 SND_ASSERT(0); 659 return MMSYSERR_NOTSUPPORTED; 660 } 661 } 662 663 MMRESULT 664 WdmAudGetDeviceInterfaceStringByMMixer( 665 IN MMDEVICE_TYPE DeviceType, 666 IN DWORD DeviceId, 667 IN LPWSTR Interface, 668 IN DWORD InterfaceLength, 669 OUT DWORD * InterfaceSize) 670 { 671 /* FIXME */ 672 return MMSYSERR_NOTSUPPORTED; 673 } 674 675 VOID 676 CALLBACK 677 MixerEventCallback( 678 IN PVOID MixerEventContext, 679 IN HANDLE hMixer, 680 IN ULONG NotificationType, 681 IN ULONG Value) 682 { 683 PSOUND_DEVICE_INSTANCE Instance = (PSOUND_DEVICE_INSTANCE)MixerEventContext; 684 685 DriverCallback(Instance->WinMM.ClientCallback, 686 HIWORD(Instance->WinMM.Flags), 687 Instance->WinMM.Handle, 688 NotificationType, 689 Instance->WinMM.ClientCallbackInstanceData, 690 (DWORD_PTR)Value, 691 0); 692 } 693 694 MMRESULT 695 WdmAudSetMixerDeviceFormatByMMixer( 696 IN PSOUND_DEVICE_INSTANCE Instance, 697 IN DWORD DeviceId, 698 IN PWAVEFORMATEX WaveFormat, 699 IN DWORD WaveFormatSize) 700 { 701 if (MMixerOpen(&MixerContext, DeviceId, (PVOID)Instance, MixerEventCallback, &Instance->Handle) == MM_STATUS_SUCCESS) 702 return MMSYSERR_NOERROR; 703 704 return MMSYSERR_BADDEVICEID; 705 } 706 707 MMRESULT 708 WdmAudSetWaveStateByMMixer( 709 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, 710 IN BOOL bStart) 711 { 712 MMDEVICE_TYPE DeviceType; 713 PSOUND_DEVICE SoundDevice; 714 MMRESULT Result; 715 716 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 717 SND_ASSERT( Result == MMSYSERR_NOERROR ); 718 719 720 Result = GetSoundDeviceType(SoundDevice, &DeviceType); 721 SND_ASSERT( Result == MMSYSERR_NOERROR ); 722 723 if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE) 724 { 725 if (bStart) 726 { 727 MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_ACQUIRE); 728 MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_PAUSE); 729 MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_RUN); 730 } 731 else 732 { 733 MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_PAUSE); 734 MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_ACQUIRE); 735 MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_STOP); 736 } 737 } 738 else if (DeviceType == MIDI_IN_DEVICE_TYPE || DeviceType == MIDI_OUT_DEVICE_TYPE) 739 { 740 if (bStart) 741 { 742 MMixerSetMidiStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_ACQUIRE); 743 MMixerSetMidiStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_PAUSE); 744 MMixerSetMidiStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_RUN); 745 } 746 else 747 { 748 MMixerSetMidiStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_PAUSE); 749 MMixerSetMidiStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_ACQUIRE); 750 MMixerSetMidiStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_STOP); 751 } 752 } 753 754 return MMSYSERR_NOERROR; 755 } 756 757 MMRESULT 758 WdmAudResetStreamByMMixer( 759 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, 760 IN MMDEVICE_TYPE DeviceType, 761 IN BOOLEAN bStartReset) 762 { 763 MIXER_STATUS Status; 764 765 if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE) 766 { 767 Status = MMixerSetWaveResetState(&MixerContext, SoundDeviceInstance->Handle, bStartReset); 768 if (Status == MM_STATUS_SUCCESS) 769 { 770 /* completed successfully */ 771 return MMSYSERR_NOERROR; 772 } 773 } 774 775 776 return MMSYSERR_NOTSUPPORTED; 777 } 778 779 MMRESULT 780 WdmAudGetWavePositionByMMixer( 781 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, 782 IN MMTIME* Time) 783 { 784 /* FIXME */ 785 return MMSYSERR_NOTSUPPORTED; 786 } 787 788 DWORD 789 WINAPI 790 IoStreamingThread( 791 LPVOID lpParameter) 792 { 793 DWORD Length; 794 //MMRESULT Result; 795 LPIO_PACKET Packet = (LPIO_PACKET)lpParameter; 796 797 /*Result = */ SyncOverlappedDeviceIoControl(Packet->hDevice, 798 Packet->IoCtl, 799 NULL, 800 0, 801 &Packet->Header, 802 sizeof(KSSTREAM_HEADER), 803 &Length); 804 805 Packet->CompletionRoutine(ERROR_SUCCESS, Packet->Header.DataUsed, (LPOVERLAPPED)Packet->Overlap); 806 807 HeapFree(GetProcessHeap(), 0, Packet); 808 return 0; 809 } 810 811 MMRESULT 812 WdmAudCommitWaveBufferByMMixer( 813 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 814 IN PVOID OffsetPtr, 815 IN DWORD Length, 816 IN PSOUND_OVERLAPPED Overlap, 817 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine) 818 { 819 PSOUND_DEVICE SoundDevice; 820 MMDEVICE_TYPE DeviceType; 821 MMRESULT Result; 822 LPIO_PACKET Packet; 823 HANDLE hThread; 824 825 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 826 827 if ( ! MMSUCCESS(Result) ) 828 { 829 return TranslateInternalMmResult(Result); 830 } 831 832 Result = GetSoundDeviceType(SoundDevice, &DeviceType); 833 SND_ASSERT( Result == MMSYSERR_NOERROR ); 834 835 Packet = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IO_PACKET)); 836 if ( ! Packet ) 837 { 838 /* no memory */ 839 return MMSYSERR_NOMEM; 840 } 841 842 /* setup stream packet */ 843 Packet->Header.Size = sizeof(KSSTREAM_HEADER); 844 Packet->Header.PresentationTime.Numerator = 1; 845 Packet->Header.PresentationTime.Denominator = 1; 846 Packet->Header.Data = OffsetPtr; 847 Packet->Header.FrameExtent = Length; 848 Packet->hDevice = SoundDeviceInstance->Handle; 849 Packet->Overlap = Overlap; 850 Packet->CompletionRoutine = CompletionRoutine; 851 Packet->IoCtl = (DeviceType == WAVE_OUT_DEVICE_TYPE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM); 852 853 if (DeviceType == WAVE_OUT_DEVICE_TYPE) 854 { 855 Packet->Header.DataUsed = Length; 856 } 857 858 hThread = CreateThread(NULL, 0, IoStreamingThread, (LPVOID)Packet, 0, NULL); 859 if (hThread == NULL) 860 { 861 /* error */ 862 return MMSYSERR_ERROR; 863 } 864 865 CloseHandle(hThread); 866 867 return MMSYSERR_NOERROR; 868 } 869