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