1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: lib/drivers/sound/mmixer/wave.c 5 * PURPOSE: Wave Handling Functions 6 * PROGRAMMER: Johannes Anderwald 7 */ 8 9 #include "precomp.h" 10 11 // #define NDEBUG 12 #include <debug.h> 13 14 const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; 15 const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}}; 16 const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; 17 const GUID KSDATAFORMAT_TYPE_AUDIO = {0x73647561L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; 18 const GUID KSINTERFACESETID_Standard = {0x1A8766A0L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; 19 const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; 20 21 typedef struct 22 { 23 ULONG SampleRate; 24 ULONG Bit8Mono; 25 ULONG Bit8Stereo; 26 ULONG Bit16Mono; 27 ULONG Bit16Stereo; 28 }AUDIO_RANGE; 29 30 #define AUDIO_TEST_RANGE (5) 31 32 static AUDIO_RANGE TestRange[AUDIO_TEST_RANGE] = 33 { 34 { 35 11025, 36 WAVE_FORMAT_1M08, 37 WAVE_FORMAT_1S08, 38 WAVE_FORMAT_1M16, 39 WAVE_FORMAT_1S16 40 }, 41 { 42 22050, 43 WAVE_FORMAT_2M08, 44 WAVE_FORMAT_2S08, 45 WAVE_FORMAT_2M16, 46 WAVE_FORMAT_2S16 47 }, 48 { 49 44100, 50 WAVE_FORMAT_4M08, 51 WAVE_FORMAT_4S08, 52 WAVE_FORMAT_4M16, 53 WAVE_FORMAT_4S16 54 }, 55 { 56 48000, 57 WAVE_FORMAT_48M08, 58 WAVE_FORMAT_48S08, 59 WAVE_FORMAT_48M16, 60 WAVE_FORMAT_48S16 61 }, 62 { 63 96000, 64 WAVE_FORMAT_96M08, 65 WAVE_FORMAT_96S08, 66 WAVE_FORMAT_96M16, 67 WAVE_FORMAT_96S16 68 } 69 }; 70 71 PKSPIN_CONNECT 72 MMixerAllocatePinConnect( 73 IN PMIXER_CONTEXT MixerContext, 74 ULONG DataFormatSize) 75 { 76 return MixerContext->Alloc(sizeof(KSPIN_CONNECT) + DataFormatSize); 77 } 78 79 MIXER_STATUS 80 MMixerGetWaveInfoByIndexAndType( 81 IN PMIXER_LIST MixerList, 82 IN ULONG DeviceIndex, 83 IN ULONG bWaveInType, 84 OUT LPWAVE_INFO *OutWaveInfo) 85 { 86 ULONG Index = 0; 87 PLIST_ENTRY Entry, ListHead; 88 LPWAVE_INFO WaveInfo; 89 90 if (bWaveInType) 91 ListHead = &MixerList->WaveInList; 92 else 93 ListHead = &MixerList->WaveOutList; 94 95 /* get first entry */ 96 Entry = ListHead->Flink; 97 98 while(Entry != ListHead) 99 { 100 WaveInfo = (LPWAVE_INFO)CONTAINING_RECORD(Entry, WAVE_INFO, Entry); 101 102 if (Index == DeviceIndex) 103 { 104 *OutWaveInfo = WaveInfo; 105 return MM_STATUS_SUCCESS; 106 } 107 Index++; 108 Entry = Entry->Flink; 109 } 110 111 return MM_STATUS_INVALID_PARAMETER; 112 } 113 114 VOID 115 MMixerInitializeDataFormat( 116 _Inout_ PKSDATAFORMAT_WAVEFORMATEX DataFormat, 117 _In_ LPWAVEFORMATEX WaveFormatEx, 118 _In_ DWORD cbSize) 119 { 120 DataFormat->WaveFormatEx.wFormatTag = WaveFormatEx->wFormatTag; 121 DataFormat->WaveFormatEx.nChannels = WaveFormatEx->nChannels; 122 DataFormat->WaveFormatEx.nSamplesPerSec = WaveFormatEx->nSamplesPerSec; 123 DataFormat->WaveFormatEx.nBlockAlign = WaveFormatEx->nBlockAlign; 124 DataFormat->WaveFormatEx.nAvgBytesPerSec = WaveFormatEx->nAvgBytesPerSec; 125 DataFormat->WaveFormatEx.wBitsPerSample = WaveFormatEx->wBitsPerSample; 126 DataFormat->WaveFormatEx.cbSize = cbSize; 127 DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX) + cbSize; 128 DataFormat->DataFormat.Flags = 0; 129 DataFormat->DataFormat.Reserved = 0; 130 DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO; 131 DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; 132 DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX; 133 DataFormat->DataFormat.SampleSize = 4; 134 135 /* Write additional fields for Extensible audio format */ 136 if (WaveFormatEx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) 137 { 138 PWAVEFORMATEXTENSIBLE WaveFormatExt = (PWAVEFORMATEXTENSIBLE)&DataFormat->WaveFormatEx; 139 WaveFormatExt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; 140 WaveFormatExt->Samples.wValidBitsPerSample = WaveFormatEx->wBitsPerSample; 141 if (WaveFormatEx->nChannels == 0) 142 WaveFormatExt->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT; 143 else if (WaveFormatEx->nChannels == 1) 144 WaveFormatExt->dwChannelMask = KSAUDIO_SPEAKER_MONO; 145 else if (WaveFormatEx->nChannels == 2) 146 WaveFormatExt->dwChannelMask = KSAUDIO_SPEAKER_STEREO; 147 else if (WaveFormatEx->nChannels == 4) 148 WaveFormatExt->dwChannelMask = KSAUDIO_SPEAKER_QUAD; 149 else if (WaveFormatEx->nChannels == 5) 150 WaveFormatExt->dwChannelMask = KSAUDIO_SPEAKER_5POINT1; 151 else if (WaveFormatEx->nChannels == 7) 152 WaveFormatExt->dwChannelMask = KSAUDIO_SPEAKER_7POINT1; 153 } 154 } 155 156 MIXER_STATUS 157 MMixerGetAudioPinDataRanges( 158 IN PMIXER_CONTEXT MixerContext, 159 IN HANDLE hDevice, 160 IN ULONG PinId, 161 IN OUT PKSMULTIPLE_ITEM * OutMultipleItem) 162 { 163 KSP_PIN PinProperty; 164 ULONG BytesReturned = 0; 165 MIXER_STATUS Status; 166 PKSMULTIPLE_ITEM MultipleItem; 167 168 /* retrieve size of data ranges buffer */ 169 PinProperty.Reserved = 0; 170 PinProperty.PinId = PinId; 171 PinProperty.Property.Set = KSPROPSETID_Pin; 172 PinProperty.Property.Id = KSPROPERTY_PIN_DATARANGES; 173 PinProperty.Property.Flags = KSPROPERTY_TYPE_GET; 174 175 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)NULL, 0, &BytesReturned); 176 if (Status != MM_STATUS_MORE_ENTRIES) 177 { 178 return Status; 179 } 180 181 MultipleItem = MixerContext->Alloc(BytesReturned); 182 if (!MultipleItem) 183 { 184 /* not enough memory */ 185 return MM_STATUS_NO_MEMORY; 186 } 187 188 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned); 189 if (Status != MM_STATUS_SUCCESS) 190 { 191 /* failed */ 192 MixerContext->Free(MultipleItem); 193 return Status; 194 } 195 196 /* save result */ 197 *OutMultipleItem = MultipleItem; 198 return Status; 199 } 200 201 MIXER_STATUS 202 MMixerFindAudioDataRange( 203 PKSMULTIPLE_ITEM MultipleItem, 204 PKSDATARANGE_AUDIO * OutDataRangeAudio) 205 { 206 ULONG Index; 207 PKSDATARANGE_AUDIO DataRangeAudio; 208 PKSDATARANGE DataRange; 209 210 DataRange = (PKSDATARANGE) (MultipleItem + 1); 211 for(Index = 0; Index < MultipleItem->Count; Index++) 212 { 213 if (DataRange->FormatSize == sizeof(KSDATARANGE_AUDIO)) 214 { 215 DataRangeAudio = (PKSDATARANGE_AUDIO)DataRange; 216 if (IsEqualGUIDAligned(&DataRangeAudio->DataRange.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) && 217 IsEqualGUIDAligned(&DataRangeAudio->DataRange.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) && 218 IsEqualGUIDAligned(&DataRangeAudio->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)) 219 { 220 DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio->MinimumSampleFrequency, DataRangeAudio->MaximumSampleFrequency, 221 DataRangeAudio->MinimumBitsPerSample, DataRangeAudio->MaximumBitsPerSample, DataRangeAudio->MaximumChannels); 222 *OutDataRangeAudio = DataRangeAudio; 223 return MM_STATUS_SUCCESS; 224 } 225 } 226 DataRange = (PKSDATARANGE)((ULONG_PTR)DataRange + DataRange->FormatSize); 227 } 228 return MM_STATUS_UNSUCCESSFUL; 229 } 230 231 MIXER_STATUS 232 MMixerOpenWavePin( 233 IN PMIXER_CONTEXT MixerContext, 234 IN PMIXER_LIST MixerList, 235 IN ULONG DeviceId, 236 IN ULONG PinId, 237 IN LPWAVEFORMATEX WaveFormatEx, 238 IN ACCESS_MASK DesiredAccess, 239 IN PIN_CREATE_CALLBACK CreateCallback, 240 IN PVOID Context, 241 OUT PHANDLE PinHandle) 242 { 243 PKSPIN_CONNECT PinConnect; 244 PKSDATAFORMAT_WAVEFORMATEX DataFormat; 245 LPMIXER_DATA MixerData; 246 NTSTATUS Status; 247 MIXER_STATUS MixerStatus; 248 DWORD cbSize; 249 250 MixerData = MMixerGetDataByDeviceId(MixerList, DeviceId); 251 if (!MixerData) 252 return MM_STATUS_INVALID_PARAMETER; 253 254 /* Enforce 0 for WAVE_FORMAT_PCM, which ignores extra information size */ 255 cbSize = WaveFormatEx->wFormatTag == WAVE_FORMAT_PCM ? 0 : WaveFormatEx->cbSize; 256 257 /* allocate pin connect */ 258 PinConnect = MMixerAllocatePinConnect(MixerContext, sizeof(KSDATAFORMAT_WAVEFORMATEX) + cbSize); 259 if (!PinConnect) 260 { 261 /* no memory */ 262 return MM_STATUS_NO_MEMORY; 263 } 264 265 /* initialize pin connect struct */ 266 MMixerInitializePinConnect(PinConnect, PinId); 267 268 /* get offset to dataformat */ 269 DataFormat = (PKSDATAFORMAT_WAVEFORMATEX) (PinConnect + 1); 270 /* initialize with requested wave format */ 271 MMixerInitializeDataFormat(DataFormat, WaveFormatEx, cbSize); 272 273 if (CreateCallback) 274 { 275 /* let the callback handle the creation */ 276 MixerStatus = CreateCallback(Context, DeviceId, PinId, MixerData->hDevice, PinConnect, DesiredAccess, PinHandle); 277 } 278 else 279 { 280 /* now create the pin */ 281 Status = KsCreatePin(MixerData->hDevice, PinConnect, DesiredAccess, PinHandle); 282 283 /* normalize status */ 284 if (Status == STATUS_SUCCESS) 285 MixerStatus = MM_STATUS_SUCCESS; 286 else 287 MixerStatus = MM_STATUS_UNSUCCESSFUL; 288 } 289 290 /* free create info */ 291 MixerContext->Free(PinConnect); 292 293 /* done */ 294 return MixerStatus; 295 } 296 297 VOID 298 MMixerCheckFormat( 299 IN PKSDATARANGE_AUDIO DataRangeAudio, 300 IN LPWAVE_INFO WaveInfo, 301 IN ULONG bInput) 302 { 303 ULONG Index, SampleFrequency; 304 ULONG Result = 0; 305 306 for(Index = 0; Index < AUDIO_TEST_RANGE; Index++) 307 { 308 SampleFrequency = TestRange[Index].SampleRate; 309 310 if (DataRangeAudio->MinimumSampleFrequency <= SampleFrequency && DataRangeAudio->MaximumSampleFrequency >= SampleFrequency) 311 { 312 /* the audio adapter supports the sample frequency */ 313 if (DataRangeAudio->MinimumBitsPerSample <= 8 && DataRangeAudio->MaximumBitsPerSample >= 8) 314 { 315 Result |= TestRange[Index].Bit8Mono; 316 317 if (DataRangeAudio->MaximumChannels > 1) 318 { 319 /* check if pin supports the sample rate in 8-Bit Stereo */ 320 Result |= TestRange[Index].Bit8Stereo; 321 } 322 } 323 324 if (DataRangeAudio->MinimumBitsPerSample <= 16 && DataRangeAudio->MaximumBitsPerSample >= 16) 325 { 326 /* check if pin supports the sample rate in 16-Bit Mono */ 327 Result |= TestRange[Index].Bit16Mono; 328 329 if (DataRangeAudio->MaximumChannels > 1) 330 { 331 /* check if pin supports the sample rate in 16-Bit Stereo */ 332 Result |= TestRange[Index].Bit16Stereo; 333 } 334 } 335 } 336 } 337 338 if (bInput) 339 WaveInfo->u.InCaps.dwFormats = Result; 340 else 341 WaveInfo->u.OutCaps.dwFormats = Result; 342 343 DPRINT("Format %lx bInput %u\n", Result, bInput); 344 } 345 346 MIXER_STATUS 347 MMixerInitializeWaveInfo( 348 IN PMIXER_CONTEXT MixerContext, 349 IN PMIXER_LIST MixerList, 350 IN LPMIXER_DATA MixerData, 351 IN LPWSTR DeviceName, 352 IN ULONG bWaveIn, 353 IN ULONG PinCount, 354 IN PULONG Pins) 355 { 356 MIXER_STATUS Status; 357 PKSMULTIPLE_ITEM MultipleItem; 358 PKSDATARANGE_AUDIO DataRangeAudio; 359 LPWAVE_INFO WaveInfo; 360 361 WaveInfo = (LPWAVE_INFO)MixerContext->Alloc(sizeof(WAVE_INFO)); 362 if (!WaveInfo) 363 return MM_STATUS_NO_MEMORY; 364 365 if (PinCount > 1) 366 { 367 /* FIXME support multiple pins for wave device */ 368 DPRINT1("Implement support for multiple pins\n"); 369 //ASSERT(PinCount == 1); 370 } 371 372 /* initialize wave info */ 373 WaveInfo->DeviceId = MixerData->DeviceId; 374 WaveInfo->PinId = Pins[0]; 375 376 /* sanity check */ 377 ASSERT(wcslen(DeviceName) < MAXPNAMELEN); 378 379 /* copy device name */ 380 if (bWaveIn) 381 { 382 wcscpy(WaveInfo->u.InCaps.szPname, DeviceName); 383 } 384 else 385 { 386 wcscpy(WaveInfo->u.OutCaps.szPname, DeviceName); 387 } 388 389 /* FIXME determine manufacturer / product id */ 390 if (bWaveIn) 391 { 392 WaveInfo->u.InCaps.wMid = MM_MICROSOFT; 393 WaveInfo->u.InCaps.wPid = MM_PID_UNMAPPED; 394 WaveInfo->u.InCaps.vDriverVersion = 1; 395 } 396 else 397 { 398 WaveInfo->u.OutCaps.wMid = MM_MICROSOFT; 399 WaveInfo->u.OutCaps.wPid = MM_PID_UNMAPPED; 400 WaveInfo->u.OutCaps.vDriverVersion = 1; 401 } 402 403 /* get audio pin data ranges */ 404 Status = MMixerGetAudioPinDataRanges(MixerContext, MixerData->hDevice, Pins[0], &MultipleItem); 405 if (Status != MM_STATUS_SUCCESS) 406 { 407 /* failed to get audio pin data ranges */ 408 MixerContext->Free(WaveInfo); 409 return MM_STATUS_UNSUCCESSFUL; 410 } 411 412 /* find an KSDATARANGE_AUDIO range */ 413 Status = MMixerFindAudioDataRange(MultipleItem, &DataRangeAudio); 414 if (Status != MM_STATUS_SUCCESS) 415 { 416 /* failed to find audio pin data range */ 417 MixerContext->Free(MultipleItem); 418 MixerContext->Free(WaveInfo); 419 return MM_STATUS_UNSUCCESSFUL; 420 } 421 422 /* store channel count */ 423 if (bWaveIn) 424 { 425 WaveInfo->u.InCaps.wChannels = DataRangeAudio->MaximumChannels; 426 } 427 else 428 { 429 WaveInfo->u.OutCaps.wChannels = DataRangeAudio->MaximumChannels; 430 } 431 432 /* get all supported formats */ 433 MMixerCheckFormat(DataRangeAudio, WaveInfo, bWaveIn); 434 435 /* free dataranges buffer */ 436 MixerContext->Free(MultipleItem); 437 438 if (bWaveIn) 439 { 440 InsertTailList(&MixerList->WaveInList, &WaveInfo->Entry); 441 MixerList->WaveInListCount++; 442 } 443 else 444 { 445 InsertTailList(&MixerList->WaveOutList, &WaveInfo->Entry); 446 MixerList->WaveOutListCount++; 447 } 448 449 return MM_STATUS_SUCCESS; 450 } 451 452 MIXER_STATUS 453 MMixerOpenWave( 454 IN PMIXER_CONTEXT MixerContext, 455 IN ULONG DeviceIndex, 456 IN ULONG bWaveIn, 457 IN LPWAVEFORMATEX WaveFormat, 458 IN PIN_CREATE_CALLBACK CreateCallback, 459 IN PVOID Context, 460 OUT PHANDLE PinHandle) 461 { 462 PMIXER_LIST MixerList; 463 MIXER_STATUS Status; 464 LPWAVE_INFO WaveInfo; 465 ACCESS_MASK DesiredAccess = 0; 466 467 /* verify mixer context */ 468 Status = MMixerVerifyContext(MixerContext); 469 470 if (Status != MM_STATUS_SUCCESS) 471 { 472 /* invalid context passed */ 473 return Status; 474 } 475 476 /* grab mixer list */ 477 MixerList = (PMIXER_LIST)MixerContext->MixerContext; 478 479 /* find destination wave */ 480 Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, bWaveIn, &WaveInfo); 481 if (Status != MM_STATUS_SUCCESS) 482 { 483 /* failed to find wave info */ 484 return MM_STATUS_INVALID_PARAMETER; 485 } 486 487 /* get desired access */ 488 if (bWaveIn) 489 { 490 DesiredAccess |= GENERIC_READ; 491 } 492 else 493 { 494 DesiredAccess |= GENERIC_WRITE; 495 } 496 497 /* now try open the pin */ 498 return MMixerOpenWavePin(MixerContext, MixerList, WaveInfo->DeviceId, WaveInfo->PinId, WaveFormat, DesiredAccess, CreateCallback, Context, PinHandle); 499 } 500 501 MIXER_STATUS 502 MMixerWaveInCapabilities( 503 IN PMIXER_CONTEXT MixerContext, 504 IN ULONG DeviceIndex, 505 OUT LPWAVEINCAPSW Caps) 506 { 507 PMIXER_LIST MixerList; 508 MIXER_STATUS Status; 509 LPWAVE_INFO WaveInfo; 510 511 /* verify mixer context */ 512 Status = MMixerVerifyContext(MixerContext); 513 514 if (Status != MM_STATUS_SUCCESS) 515 { 516 /* invalid context passed */ 517 return Status; 518 } 519 520 /* grab mixer list */ 521 MixerList = (PMIXER_LIST)MixerContext->MixerContext; 522 523 /* find destination wave */ 524 Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, TRUE, &WaveInfo); 525 if (Status != MM_STATUS_SUCCESS) 526 { 527 /* failed to find wave info */ 528 return MM_STATUS_UNSUCCESSFUL; 529 } 530 531 /* copy capabilities */ 532 MixerContext->Copy(Caps, &WaveInfo->u.InCaps, sizeof(WAVEINCAPSW)); 533 534 return MM_STATUS_SUCCESS; 535 } 536 537 MIXER_STATUS 538 MMixerWaveOutCapabilities( 539 IN PMIXER_CONTEXT MixerContext, 540 IN ULONG DeviceIndex, 541 OUT LPWAVEOUTCAPSW Caps) 542 { 543 PMIXER_LIST MixerList; 544 MIXER_STATUS Status; 545 LPWAVE_INFO WaveInfo; 546 547 /* verify mixer context */ 548 Status = MMixerVerifyContext(MixerContext); 549 550 if (Status != MM_STATUS_SUCCESS) 551 { 552 /* invalid context passed */ 553 return Status; 554 } 555 556 /* grab mixer list */ 557 MixerList = (PMIXER_LIST)MixerContext->MixerContext; 558 559 /* find destination wave */ 560 Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, FALSE, &WaveInfo); 561 if (Status != MM_STATUS_SUCCESS) 562 { 563 /* failed to find wave info */ 564 return MM_STATUS_UNSUCCESSFUL; 565 } 566 567 /* copy capabilities */ 568 MixerContext->Copy(Caps, &WaveInfo->u.OutCaps, sizeof(WAVEOUTCAPSW)); 569 570 return MM_STATUS_SUCCESS; 571 } 572 573 ULONG 574 MMixerGetWaveInCount( 575 IN PMIXER_CONTEXT MixerContext) 576 { 577 PMIXER_LIST MixerList; 578 MIXER_STATUS Status; 579 580 /* verify mixer context */ 581 Status = MMixerVerifyContext(MixerContext); 582 583 if (Status != MM_STATUS_SUCCESS) 584 { 585 /* invalid context passed */ 586 return Status; 587 } 588 589 /* grab mixer list */ 590 MixerList = (PMIXER_LIST)MixerContext->MixerContext; 591 592 return MixerList->WaveInListCount; 593 } 594 595 ULONG 596 MMixerGetWaveOutCount( 597 IN PMIXER_CONTEXT MixerContext) 598 { 599 PMIXER_LIST MixerList; 600 MIXER_STATUS Status; 601 602 /* verify mixer context */ 603 Status = MMixerVerifyContext(MixerContext); 604 605 if (Status != MM_STATUS_SUCCESS) 606 { 607 /* invalid context passed */ 608 return Status; 609 } 610 611 /* grab mixer list */ 612 MixerList = (PMIXER_LIST)MixerContext->MixerContext; 613 614 return MixerList->WaveOutListCount; 615 } 616 617 MIXER_STATUS 618 MMixerGetWavePosition( 619 _In_ PMIXER_CONTEXT MixerContext, 620 _In_ HANDLE PinHandle, 621 _Out_ PDWORD Position) 622 { 623 KSAUDIO_POSITION AudioPosition; 624 KSPROPERTY Property; 625 MIXER_STATUS Status; 626 ULONG Length; 627 628 /* Validate mixer context */ 629 Status = MMixerVerifyContext(MixerContext); 630 631 if (Status != MM_STATUS_SUCCESS) 632 return Status; 633 634 Property.Id = KSPROPERTY_AUDIO_POSITION; 635 Property.Set = KSPROPSETID_Audio; 636 Property.Flags = KSPROPERTY_TYPE_GET; 637 638 Status = MixerContext->Control(PinHandle, IOCTL_KS_PROPERTY, 639 &Property, sizeof(Property), 640 &AudioPosition, sizeof(AudioPosition), 641 &Length); 642 if (Status == MM_STATUS_SUCCESS) 643 { 644 /* store audio position */ 645 *Position = (DWORD)AudioPosition.PlayOffset; 646 } 647 648 return Status; 649 } 650 651 MIXER_STATUS 652 MMixerSetWaveStatus( 653 IN PMIXER_CONTEXT MixerContext, 654 IN HANDLE PinHandle, 655 IN KSSTATE State) 656 { 657 KSPROPERTY Property; 658 ULONG Length; 659 MIXER_STATUS Status; 660 661 /* verify mixer context */ 662 Status = MMixerVerifyContext(MixerContext); 663 664 if (Status != MM_STATUS_SUCCESS) 665 { 666 /* invalid context passed */ 667 return Status; 668 } 669 670 /* setup property request */ 671 Property.Set = KSPROPSETID_Connection; 672 Property.Id = KSPROPERTY_CONNECTION_STATE; 673 Property.Flags = KSPROPERTY_TYPE_SET; 674 675 return MixerContext->Control(PinHandle, IOCTL_KS_PROPERTY, &Property, sizeof(KSPROPERTY), &State, sizeof(KSSTATE), &Length); 676 } 677 678 MIXER_STATUS 679 MMixerSetWaveResetState( 680 IN PMIXER_CONTEXT MixerContext, 681 IN HANDLE PinHandle, 682 IN ULONG bBegin) 683 { 684 ULONG Length; 685 MIXER_STATUS Status; 686 KSRESET Reset; 687 688 /* verify mixer context */ 689 Status = MMixerVerifyContext(MixerContext); 690 691 if (Status != MM_STATUS_SUCCESS) 692 { 693 /* invalid context passed */ 694 return Status; 695 } 696 697 /* begin / stop reset */ 698 Reset = (bBegin ? KSRESET_BEGIN : KSRESET_END); 699 700 return MixerContext->Control(PinHandle, IOCTL_KS_RESET_STATE, &Reset, sizeof(KSRESET), NULL, 0, &Length); 701 } 702 703 MIXER_STATUS 704 MMixerGetWaveDevicePath( 705 IN PMIXER_CONTEXT MixerContext, 706 IN ULONG bWaveIn, 707 IN ULONG DeviceId, 708 OUT LPWSTR * DevicePath) 709 { 710 PMIXER_LIST MixerList; 711 LPMIXER_DATA MixerData; 712 LPWAVE_INFO WaveInfo; 713 SIZE_T Length; 714 MIXER_STATUS Status; 715 716 /* verify mixer context */ 717 Status = MMixerVerifyContext(MixerContext); 718 719 if (Status != MM_STATUS_SUCCESS) 720 { 721 /* invalid context passed */ 722 return Status; 723 } 724 725 /* grab mixer list */ 726 MixerList = (PMIXER_LIST)MixerContext->MixerContext; 727 728 /* find destination wave */ 729 Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceId, bWaveIn, &WaveInfo); 730 if (Status != MM_STATUS_SUCCESS) 731 { 732 /* failed to find wave info */ 733 return MM_STATUS_INVALID_PARAMETER; 734 } 735 736 /* get associated device id */ 737 MixerData = MMixerGetDataByDeviceId(MixerList, WaveInfo->DeviceId); 738 if (!MixerData) 739 return MM_STATUS_INVALID_PARAMETER; 740 741 /* calculate length */ 742 Length = wcslen(MixerData->DeviceName)+1; 743 744 /* allocate destination buffer */ 745 *DevicePath = MixerContext->Alloc(Length * sizeof(WCHAR)); 746 747 if (!*DevicePath) 748 { 749 /* no memory */ 750 return MM_STATUS_NO_MEMORY; 751 } 752 753 /* copy device path */ 754 MixerContext->Copy(*DevicePath, MixerData->DeviceName, Length * sizeof(WCHAR)); 755 756 /* done */ 757 return MM_STATUS_SUCCESS; 758 } 759