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 PSOUND_DEVICE SoundDevice; 780 MMDEVICE_TYPE DeviceType; 781 MIXER_STATUS Status; 782 MMRESULT Result; 783 DWORD Position; 784 785 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 786 if (!MMSUCCESS(Result)) 787 return TranslateInternalMmResult(Result); 788 789 Result = GetSoundDeviceType(SoundDevice, &DeviceType); 790 SND_ASSERT(Result == MMSYSERR_NOERROR); 791 792 if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE) 793 { 794 Status = MMixerGetWavePosition(&MixerContext, SoundDeviceInstance->Handle, &Position); 795 if (Status == MM_STATUS_SUCCESS) 796 { 797 /* Store position */ 798 Time->wType = TIME_BYTES; 799 Time->u.cb = Position; 800 801 /* Completed successfully */ 802 return MMSYSERR_NOERROR; 803 } 804 } 805 return MMSYSERR_NOTSUPPORTED; 806 } 807 808 MMRESULT 809 WdmAudGetVolumeByMMixer( 810 _In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 811 _In_ DWORD DeviceId, 812 _Out_ PDWORD pdwVolume) 813 { 814 MMRESULT Result; 815 MIXERLINE MixLine; 816 MIXERCONTROL MixControl; 817 MIXERLINECONTROLS MixLineControls; 818 MIXERCONTROLDETAILS MixControlDetails; 819 MIXERCONTROLDETAILS_UNSIGNED MixControlDetailsU[2]; // For 2 (stereo) channels 820 821 MixLine.cbStruct = sizeof(MixLine); 822 MixLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; 823 824 /* Get line info */ 825 Result = WdmAudGetLineInfo(SoundDeviceInstance->Handle, 826 DeviceId, 827 &MixLine, 828 MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_COMPONENTTYPE); 829 if (!MMSUCCESS(Result)) 830 return TranslateInternalMmResult(Result); 831 832 MixLineControls.cbStruct = sizeof(MixLineControls); 833 MixLineControls.dwLineID = MixLine.dwLineID; 834 MixLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; 835 MixLineControls.cControls = 1; 836 MixLineControls.cbmxctrl = sizeof(MixControl); 837 MixLineControls.pamxctrl = &MixControl; 838 839 /* Get line controls */ 840 Result = WdmAudGetLineControls(SoundDeviceInstance->Handle, 841 DeviceId, 842 &MixLineControls, 843 MIXER_OBJECTF_MIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE); 844 if (!MMSUCCESS(Result)) 845 return TranslateInternalMmResult(Result); 846 847 MixControlDetails.cbStruct = sizeof(MixControlDetails); 848 MixControlDetails.dwControlID = MixControl.dwControlID; 849 MixControlDetails.cChannels = MixLine.cChannels; 850 MixControlDetails.cMultipleItems = 0; 851 MixControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 852 MixControlDetails.paDetails = MixControlDetailsU; 853 854 /* Get volume control details */ 855 Result = WdmAudGetControlDetails(SoundDeviceInstance->Handle, 856 DeviceId, 857 &MixControlDetails, 858 MIXER_OBJECTF_MIXER); 859 if (MMSUCCESS(Result)) 860 *pdwVolume = MAKELONG(LOWORD(MixControlDetailsU[0].dwValue), HIWORD(MixControlDetailsU[1].dwValue)); 861 862 return Result; 863 } 864 865 MMRESULT 866 WdmAudSetVolumeByMMixer( 867 _In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 868 _In_ DWORD DeviceId, 869 _In_ DWORD dwVolume) 870 { 871 MMRESULT Result; 872 MIXERLINE MixLine; 873 MIXERCONTROL MixControl; 874 MIXERLINECONTROLS MixLineControls; 875 MIXERCONTROLDETAILS MixControlDetails; 876 MIXERCONTROLDETAILS_UNSIGNED MixControlDetailsU[2]; // For 2 (stereo) channels 877 878 MixLine.cbStruct = sizeof(MixLine); 879 MixLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; 880 881 /* Get line info */ 882 Result = WdmAudGetLineInfo(SoundDeviceInstance->Handle, 883 DeviceId, 884 &MixLine, 885 MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_COMPONENTTYPE); 886 if (!MMSUCCESS(Result)) 887 return TranslateInternalMmResult(Result); 888 889 MixLineControls.cbStruct = sizeof(MixLineControls); 890 MixLineControls.dwLineID = MixLine.dwLineID; 891 MixLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; 892 MixLineControls.cControls = 1; 893 MixLineControls.cbmxctrl = sizeof(MixControl); 894 MixLineControls.pamxctrl = &MixControl; 895 896 /* Get line controls */ 897 Result = WdmAudGetLineControls(SoundDeviceInstance->Handle, 898 DeviceId, 899 &MixLineControls, 900 MIXER_OBJECTF_MIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE); 901 if (!MMSUCCESS(Result)) 902 return TranslateInternalMmResult(Result); 903 904 /* Convert volume level to be set */ 905 MixControlDetailsU[0].dwValue = LOWORD(dwVolume); // Left channel 906 MixControlDetailsU[1].dwValue = HIWORD(dwVolume); // Right channel 907 908 MixControlDetails.cbStruct = sizeof(MixControlDetails); 909 MixControlDetails.dwControlID = MixControl.dwControlID; 910 MixControlDetails.cChannels = MixLine.cChannels; 911 MixControlDetails.cMultipleItems = 0; 912 MixControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 913 MixControlDetails.paDetails = MixControlDetailsU; 914 915 /* Set volume control details */ 916 Result = WdmAudSetControlDetails(SoundDeviceInstance->Handle, 917 DeviceId, 918 &MixControlDetails, 919 MIXER_OBJECTF_MIXER); 920 return Result; 921 } 922 923 static 924 VOID WINAPI 925 CommitWaveBufferApc(PVOID ApcContext, 926 PIO_STATUS_BLOCK IoStatusBlock, 927 ULONG Reserved) 928 { 929 DWORD dwErrorCode; 930 PSOUND_OVERLAPPED Overlap; 931 KSSTREAM_HEADER* lpHeader; 932 933 dwErrorCode = RtlNtStatusToDosError(IoStatusBlock->Status); 934 Overlap = (PSOUND_OVERLAPPED)IoStatusBlock; 935 lpHeader = Overlap->CompletionContext; 936 937 /* Call mmebuddy overlap routine */ 938 Overlap->OriginalCompletionRoutine(dwErrorCode, 939 lpHeader->DataUsed, &Overlap->Standard); 940 941 HeapFree(GetProcessHeap(), 0, lpHeader); 942 } 943 944 MMRESULT 945 WdmAudCommitWaveBufferByMMixer( 946 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 947 IN PVOID OffsetPtr, 948 IN DWORD Length, 949 IN PSOUND_OVERLAPPED Overlap, 950 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine) 951 { 952 PSOUND_DEVICE SoundDevice; 953 MMDEVICE_TYPE DeviceType; 954 MMRESULT Result; 955 ULONG IoCtl; 956 KSSTREAM_HEADER* lpHeader; 957 NTSTATUS Status; 958 959 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 960 961 if ( ! MMSUCCESS(Result) ) 962 { 963 return TranslateInternalMmResult(Result); 964 } 965 966 Result = GetSoundDeviceType(SoundDevice, &DeviceType); 967 SND_ASSERT( Result == MMSYSERR_NOERROR ); 968 969 lpHeader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KSSTREAM_HEADER)); 970 if ( ! lpHeader ) 971 { 972 /* no memory */ 973 return MMSYSERR_NOMEM; 974 } 975 976 /* setup stream packet */ 977 lpHeader->Size = sizeof(KSSTREAM_HEADER); 978 lpHeader->PresentationTime.Numerator = 1; 979 lpHeader->PresentationTime.Denominator = 1; 980 lpHeader->Data = OffsetPtr; 981 lpHeader->FrameExtent = Length; 982 Overlap->CompletionContext = lpHeader; 983 Overlap->OriginalCompletionRoutine = CompletionRoutine; 984 IoCtl = (DeviceType == WAVE_OUT_DEVICE_TYPE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM); 985 986 if (DeviceType == WAVE_OUT_DEVICE_TYPE) 987 { 988 lpHeader->DataUsed = Length; 989 } 990 991 Status = NtDeviceIoControlFile(SoundDeviceInstance->Handle, 992 NULL, 993 CommitWaveBufferApc, 994 NULL, 995 (PIO_STATUS_BLOCK)Overlap, 996 IoCtl, 997 NULL, 998 0, 999 lpHeader, 1000 sizeof(KSSTREAM_HEADER)); 1001 1002 if (!NT_SUCCESS(Status)) 1003 { 1004 DPRINT1("NtDeviceIoControlFile() failed with status %08lx\n", Status); 1005 return MMSYSERR_ERROR; 1006 } 1007 1008 return MMSYSERR_NOERROR; 1009 } 1010