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
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}};
30 #define AUDIO_TEST_RANGE (5)
32 static AUDIO_RANGE TestRange
[AUDIO_TEST_RANGE
] =
72 MMixerAllocatePinConnect(
73 IN PMIXER_CONTEXT MixerContext
,
76 return MixerContext
->Alloc(sizeof(KSPIN_CONNECT
) + DataFormatSize
);
80 MMixerGetWaveInfoByIndexAndType(
81 IN PMIXER_LIST MixerList
,
84 OUT LPWAVE_INFO
*OutWaveInfo
)
87 PLIST_ENTRY Entry
, ListHead
;
91 ListHead
= &MixerList
->WaveInList
;
93 ListHead
= &MixerList
->WaveOutList
;
96 Entry
= ListHead
->Flink
;
98 while(Entry
!= ListHead
)
100 WaveInfo
= (LPWAVE_INFO
)CONTAINING_RECORD(Entry
, WAVE_INFO
, Entry
);
102 if (Index
== DeviceIndex
)
104 *OutWaveInfo
= WaveInfo
;
105 return MM_STATUS_SUCCESS
;
108 Entry
= Entry
->Flink
;
111 return MM_STATUS_INVALID_PARAMETER
;
118 MMixerInitializeDataFormat(
119 IN PKSDATAFORMAT_WAVEFORMATEX DataFormat
,
120 LPWAVEFORMATEX WaveFormatEx
)
123 DataFormat
->WaveFormatEx
.wFormatTag
= WaveFormatEx
->wFormatTag
;
124 DataFormat
->WaveFormatEx
.nChannels
= WaveFormatEx
->nChannels
;
125 DataFormat
->WaveFormatEx
.nSamplesPerSec
= WaveFormatEx
->nSamplesPerSec
;
126 DataFormat
->WaveFormatEx
.nBlockAlign
= WaveFormatEx
->nBlockAlign
;
127 DataFormat
->WaveFormatEx
.nAvgBytesPerSec
= WaveFormatEx
->nAvgBytesPerSec
;
128 DataFormat
->WaveFormatEx
.wBitsPerSample
= WaveFormatEx
->wBitsPerSample
;
129 DataFormat
->WaveFormatEx
.cbSize
= 0;
130 DataFormat
->DataFormat
.FormatSize
= sizeof(KSDATAFORMAT
) + sizeof(WAVEFORMATEX
);
131 DataFormat
->DataFormat
.Flags
= 0;
132 DataFormat
->DataFormat
.Reserved
= 0;
133 DataFormat
->DataFormat
.MajorFormat
= KSDATAFORMAT_TYPE_AUDIO
;
135 DataFormat
->DataFormat
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
136 DataFormat
->DataFormat
.Specifier
= KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
;
137 DataFormat
->DataFormat
.SampleSize
= 4;
142 MMixerGetAudioPinDataRanges(
143 IN PMIXER_CONTEXT MixerContext
,
146 IN OUT PKSMULTIPLE_ITEM
* OutMultipleItem
)
149 ULONG BytesReturned
= 0;
151 PKSMULTIPLE_ITEM MultipleItem
;
153 /* retrieve size of data ranges buffer */
154 PinProperty
.Reserved
= 0;
155 PinProperty
.PinId
= PinId
;
156 PinProperty
.Property
.Set
= KSPROPSETID_Pin
;
157 PinProperty
.Property
.Id
= KSPROPERTY_PIN_DATARANGES
;
158 PinProperty
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
160 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&PinProperty
, sizeof(KSP_PIN
), (PVOID
)NULL
, 0, &BytesReturned
);
161 if (Status
!= MM_STATUS_MORE_ENTRIES
)
166 MultipleItem
= MixerContext
->Alloc(BytesReturned
);
169 /* not enough memory */
170 return MM_STATUS_NO_MEMORY
;
173 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&PinProperty
, sizeof(KSP_PIN
), (PVOID
)MultipleItem
, BytesReturned
, &BytesReturned
);
174 if (Status
!= MM_STATUS_SUCCESS
)
177 MixerContext
->Free(MultipleItem
);
182 *OutMultipleItem
= MultipleItem
;
187 MMixerFindAudioDataRange(
188 PKSMULTIPLE_ITEM MultipleItem
,
189 PKSDATARANGE_AUDIO
* OutDataRangeAudio
)
192 PKSDATARANGE_AUDIO DataRangeAudio
;
193 PKSDATARANGE DataRange
;
195 DataRange
= (PKSDATARANGE
) (MultipleItem
+ 1);
196 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
198 if (DataRange
->FormatSize
== sizeof(KSDATARANGE_AUDIO
))
200 DataRangeAudio
= (PKSDATARANGE_AUDIO
)DataRange
;
201 if (IsEqualGUIDAligned(&DataRangeAudio
->DataRange
.MajorFormat
, &KSDATAFORMAT_TYPE_AUDIO
) &&
202 IsEqualGUIDAligned(&DataRangeAudio
->DataRange
.SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
) &&
203 IsEqualGUIDAligned(&DataRangeAudio
->DataRange
.Specifier
, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
))
205 DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio
->MinimumSampleFrequency
, DataRangeAudio
->MaximumSampleFrequency
,
206 DataRangeAudio
->MinimumBitsPerSample
, DataRangeAudio
->MaximumBitsPerSample
, DataRangeAudio
->MaximumChannels
);
207 *OutDataRangeAudio
= DataRangeAudio
;
208 return MM_STATUS_SUCCESS
;
211 DataRange
= (PKSDATARANGE
)((ULONG_PTR
)DataRange
+ DataRange
->FormatSize
);
213 return MM_STATUS_UNSUCCESSFUL
;
218 IN PMIXER_CONTEXT MixerContext
,
219 IN PMIXER_LIST MixerList
,
222 IN LPWAVEFORMATEX WaveFormatEx
,
223 IN ACCESS_MASK DesiredAccess
,
224 IN PIN_CREATE_CALLBACK CreateCallback
,
226 OUT PHANDLE PinHandle
)
228 PKSPIN_CONNECT PinConnect
;
229 PKSDATAFORMAT_WAVEFORMATEX DataFormat
;
230 LPMIXER_DATA MixerData
;
232 MIXER_STATUS MixerStatus
;
234 MixerData
= MMixerGetDataByDeviceId(MixerList
, DeviceId
);
236 return MM_STATUS_INVALID_PARAMETER
;
238 /* allocate pin connect */
239 PinConnect
= MMixerAllocatePinConnect(MixerContext
, sizeof(KSDATAFORMAT_WAVEFORMATEX
));
243 return MM_STATUS_NO_MEMORY
;
246 /* initialize pin connect struct */
247 MMixerInitializePinConnect(PinConnect
, PinId
);
249 /* get offset to dataformat */
250 DataFormat
= (PKSDATAFORMAT_WAVEFORMATEX
) (PinConnect
+ 1);
251 /* initialize with requested wave format */
252 MMixerInitializeDataFormat(DataFormat
, WaveFormatEx
);
256 /* let the callback handle the creation */
257 MixerStatus
= CreateCallback(Context
, DeviceId
, PinId
, MixerData
->hDevice
, PinConnect
, DesiredAccess
, PinHandle
);
261 /* now create the pin */
262 Status
= KsCreatePin(MixerData
->hDevice
, PinConnect
, DesiredAccess
, PinHandle
);
264 /* normalize status */
265 if (Status
== STATUS_SUCCESS
)
266 MixerStatus
= MM_STATUS_SUCCESS
;
268 MixerStatus
= MM_STATUS_UNSUCCESSFUL
;
271 /* free create info */
272 MixerContext
->Free(PinConnect
);
280 IN PKSDATARANGE_AUDIO DataRangeAudio
,
281 IN LPWAVE_INFO WaveInfo
,
284 ULONG Index
, SampleFrequency
;
287 for(Index
= 0; Index
< AUDIO_TEST_RANGE
; Index
++)
289 SampleFrequency
= TestRange
[Index
].SampleRate
;
291 if (DataRangeAudio
->MinimumSampleFrequency
<= SampleFrequency
&& DataRangeAudio
->MaximumSampleFrequency
>= SampleFrequency
)
293 /* the audio adapter supports the sample frequency */
294 if (DataRangeAudio
->MinimumBitsPerSample
<= 8 && DataRangeAudio
->MaximumBitsPerSample
>= 8)
296 Result
|= TestRange
[Index
].Bit8Mono
;
298 if (DataRangeAudio
->MaximumChannels
> 1)
300 /* check if pin supports the sample rate in 8-Bit Stereo */
301 Result
|= TestRange
[Index
].Bit8Stereo
;
305 if (DataRangeAudio
->MinimumBitsPerSample
<= 16 && DataRangeAudio
->MaximumBitsPerSample
>= 16)
307 /* check if pin supports the sample rate in 16-Bit Mono */
308 Result
|= TestRange
[Index
].Bit16Mono
;
311 if (DataRangeAudio
->MaximumChannels
> 1)
313 /* check if pin supports the sample rate in 16-Bit Stereo */
314 Result
|= TestRange
[Index
].Bit16Stereo
;
322 WaveInfo
->u
.InCaps
.dwFormats
= Result
;
324 WaveInfo
->u
.OutCaps
.dwFormats
= Result
;
326 DPRINT("Format %lx bInput %u\n", Result
, bInput
);
330 MMixerInitializeWaveInfo(
331 IN PMIXER_CONTEXT MixerContext
,
332 IN PMIXER_LIST MixerList
,
333 IN LPMIXER_DATA MixerData
,
334 IN LPWSTR DeviceName
,
340 PKSMULTIPLE_ITEM MultipleItem
;
341 PKSDATARANGE_AUDIO DataRangeAudio
;
342 LPWAVE_INFO WaveInfo
;
344 WaveInfo
= (LPWAVE_INFO
)MixerContext
->Alloc(sizeof(WAVE_INFO
));
346 return MM_STATUS_NO_MEMORY
;
350 /* FIXME support multiple pins for wave device */
351 DPRINT1("Implement support for multiple pins\n");
352 //ASSERT(PinCount == 1);
355 /* initialize wave info */
356 WaveInfo
->DeviceId
= MixerData
->DeviceId
;
357 WaveInfo
->PinId
= Pins
[0];
360 ASSERT(wcslen(DeviceName
) + 1 < MAXPNAMELEN
);
362 /* copy device name */
365 wcscpy(WaveInfo
->u
.InCaps
.szPname
, DeviceName
);
369 wcscpy(WaveInfo
->u
.OutCaps
.szPname
, DeviceName
);
372 /* FIXME determine manufacturer / product id */
375 WaveInfo
->u
.InCaps
.wMid
= MM_MICROSOFT
;
376 WaveInfo
->u
.InCaps
.wPid
= MM_PID_UNMAPPED
;
377 WaveInfo
->u
.InCaps
.vDriverVersion
= 1;
381 WaveInfo
->u
.OutCaps
.wMid
= MM_MICROSOFT
;
382 WaveInfo
->u
.OutCaps
.wPid
= MM_PID_UNMAPPED
;
383 WaveInfo
->u
.OutCaps
.vDriverVersion
= 1;
386 /* get audio pin data ranges */
387 Status
= MMixerGetAudioPinDataRanges(MixerContext
, MixerData
->hDevice
, Pins
[0], &MultipleItem
);
388 if (Status
!= MM_STATUS_SUCCESS
)
390 /* failed to get audio pin data ranges */
391 MixerContext
->Free(WaveInfo
);
392 return MM_STATUS_UNSUCCESSFUL
;
395 /* find an KSDATARANGE_AUDIO range */
396 Status
= MMixerFindAudioDataRange(MultipleItem
, &DataRangeAudio
);
397 if (Status
!= MM_STATUS_SUCCESS
)
399 /* failed to find audio pin data range */
400 MixerContext
->Free(MultipleItem
);
401 MixerContext
->Free(WaveInfo
);
402 return MM_STATUS_UNSUCCESSFUL
;
405 /* store channel count */
408 WaveInfo
->u
.InCaps
.wChannels
= DataRangeAudio
->MaximumChannels
;
412 WaveInfo
->u
.OutCaps
.wChannels
= DataRangeAudio
->MaximumChannels
;
415 /* get all supported formats */
416 MMixerCheckFormat(DataRangeAudio
, WaveInfo
, bWaveIn
);
418 /* free dataranges buffer */
419 MixerContext
->Free(MultipleItem
);
423 InsertTailList(&MixerList
->WaveInList
, &WaveInfo
->Entry
);
424 MixerList
->WaveInListCount
++;
428 InsertTailList(&MixerList
->WaveOutList
, &WaveInfo
->Entry
);
429 MixerList
->WaveOutListCount
++;
432 return MM_STATUS_SUCCESS
;
437 IN PMIXER_CONTEXT MixerContext
,
438 IN ULONG DeviceIndex
,
440 IN LPWAVEFORMATEX WaveFormat
,
441 IN PIN_CREATE_CALLBACK CreateCallback
,
443 OUT PHANDLE PinHandle
)
445 PMIXER_LIST MixerList
;
447 LPWAVE_INFO WaveInfo
;
448 ACCESS_MASK DesiredAccess
= 0;
450 /* verify mixer context */
451 Status
= MMixerVerifyContext(MixerContext
);
453 if (Status
!= MM_STATUS_SUCCESS
)
455 /* invalid context passed */
459 /* grab mixer list */
460 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
462 if (WaveFormat
->wFormatTag
!= WAVE_FORMAT_PCM
)
464 /* not implemented */
465 return MM_STATUS_NOT_IMPLEMENTED
;
468 /* find destination wave */
469 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, bWaveIn
, &WaveInfo
);
470 if (Status
!= MM_STATUS_SUCCESS
)
472 /* failed to find wave info */
473 return MM_STATUS_INVALID_PARAMETER
;
476 /* get desired access */
479 DesiredAccess
|= GENERIC_READ
;
483 DesiredAccess
|= GENERIC_WRITE
;
486 /* now try open the pin */
487 return MMixerOpenWavePin(MixerContext
, MixerList
, WaveInfo
->DeviceId
, WaveInfo
->PinId
, WaveFormat
, DesiredAccess
, CreateCallback
, Context
, PinHandle
);
491 MMixerWaveInCapabilities(
492 IN PMIXER_CONTEXT MixerContext
,
493 IN ULONG DeviceIndex
,
494 OUT LPWAVEINCAPSW Caps
)
496 PMIXER_LIST MixerList
;
498 LPWAVE_INFO WaveInfo
;
500 /* verify mixer context */
501 Status
= MMixerVerifyContext(MixerContext
);
503 if (Status
!= MM_STATUS_SUCCESS
)
505 /* invalid context passed */
509 /* grab mixer list */
510 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
512 /* find destination wave */
513 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, TRUE
, &WaveInfo
);
514 if (Status
!= MM_STATUS_SUCCESS
)
516 /* failed to find wave info */
517 return MM_STATUS_UNSUCCESSFUL
;
520 /* copy capabilities */
521 MixerContext
->Copy(Caps
, &WaveInfo
->u
.InCaps
, sizeof(WAVEINCAPSW
));
523 return MM_STATUS_SUCCESS
;
527 MMixerWaveOutCapabilities(
528 IN PMIXER_CONTEXT MixerContext
,
529 IN ULONG DeviceIndex
,
530 OUT LPWAVEOUTCAPSW Caps
)
532 PMIXER_LIST MixerList
;
534 LPWAVE_INFO WaveInfo
;
536 /* verify mixer context */
537 Status
= MMixerVerifyContext(MixerContext
);
539 if (Status
!= MM_STATUS_SUCCESS
)
541 /* invalid context passed */
545 /* grab mixer list */
546 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
548 /* find destination wave */
549 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, FALSE
, &WaveInfo
);
550 if (Status
!= MM_STATUS_SUCCESS
)
552 /* failed to find wave info */
553 return MM_STATUS_UNSUCCESSFUL
;
556 /* copy capabilities */
557 MixerContext
->Copy(Caps
, &WaveInfo
->u
.OutCaps
, sizeof(WAVEOUTCAPSW
));
559 return MM_STATUS_SUCCESS
;
563 MMixerGetWaveInCount(
564 IN PMIXER_CONTEXT MixerContext
)
566 PMIXER_LIST MixerList
;
569 /* verify mixer context */
570 Status
= MMixerVerifyContext(MixerContext
);
572 if (Status
!= MM_STATUS_SUCCESS
)
574 /* invalid context passed */
578 /* grab mixer list */
579 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
581 return MixerList
->WaveInListCount
;
585 MMixerGetWaveOutCount(
586 IN PMIXER_CONTEXT MixerContext
)
588 PMIXER_LIST MixerList
;
591 /* verify mixer context */
592 Status
= MMixerVerifyContext(MixerContext
);
594 if (Status
!= MM_STATUS_SUCCESS
)
596 /* invalid context passed */
600 /* grab mixer list */
601 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
603 return MixerList
->WaveOutListCount
;
608 IN PMIXER_CONTEXT MixerContext
,
616 /* verify mixer context */
617 Status
= MMixerVerifyContext(MixerContext
);
619 if (Status
!= MM_STATUS_SUCCESS
)
621 /* invalid context passed */
625 /* setup property request */
626 Property
.Set
= KSPROPSETID_Connection
;
627 Property
.Id
= KSPROPERTY_CONNECTION_STATE
;
628 Property
.Flags
= KSPROPERTY_TYPE_SET
;
630 return MixerContext
->Control(PinHandle
, IOCTL_KS_PROPERTY
, &Property
, sizeof(KSPROPERTY
), &State
, sizeof(KSSTATE
), &Length
);
634 MMixerSetWaveResetState(
635 IN PMIXER_CONTEXT MixerContext
,
643 /* verify mixer context */
644 Status
= MMixerVerifyContext(MixerContext
);
646 if (Status
!= MM_STATUS_SUCCESS
)
648 /* invalid context passed */
652 /* begin / stop reset */
653 Reset
= (bBegin
? KSRESET_BEGIN
: KSRESET_END
);
655 return MixerContext
->Control(PinHandle
, IOCTL_KS_RESET_STATE
, &Reset
, sizeof(KSRESET
), NULL
, 0, &Length
);
659 MMixerGetWaveDevicePath(
660 IN PMIXER_CONTEXT MixerContext
,
663 OUT LPWSTR
* DevicePath
)
665 PMIXER_LIST MixerList
;
666 LPMIXER_DATA MixerData
;
667 LPWAVE_INFO WaveInfo
;
671 /* verify mixer context */
672 Status
= MMixerVerifyContext(MixerContext
);
674 if (Status
!= MM_STATUS_SUCCESS
)
676 /* invalid context passed */
680 /* grab mixer list */
681 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
683 /* find destination wave */
684 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceId
, bWaveIn
, &WaveInfo
);
685 if (Status
!= MM_STATUS_SUCCESS
)
687 /* failed to find wave info */
688 return MM_STATUS_INVALID_PARAMETER
;
691 /* get associated device id */
692 MixerData
= MMixerGetDataByDeviceId(MixerList
, WaveInfo
->DeviceId
);
694 return MM_STATUS_INVALID_PARAMETER
;
696 /* calculate length */
697 Length
= wcslen(MixerData
->DeviceName
)+1;
699 /* allocate destination buffer */
700 *DevicePath
= MixerContext
->Alloc(Length
* sizeof(WCHAR
));
705 return MM_STATUS_NO_MEMORY
;
708 /* copy device path */
709 MixerContext
->Copy(*DevicePath
, MixerData
->DeviceName
, Length
* sizeof(WCHAR
));
712 return MM_STATUS_SUCCESS
;