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
11 const GUID KSPROPSETID_Connection
= {0x1D58C920L
, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
12 const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
= {0x05589f81L
, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
13 const GUID KSDATAFORMAT_SUBTYPE_PCM
= {0x00000001L
, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
14 const GUID KSDATAFORMAT_TYPE_AUDIO
= {0x73647561L
, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
15 const GUID KSINTERFACESETID_Standard
= {0x1A8766A0L
, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
16 const GUID KSMEDIUMSETID_Standard
= {0x4747B320L
, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
27 #define AUDIO_TEST_RANGE (5)
29 static AUDIO_RANGE TestRange
[AUDIO_TEST_RANGE
] =
69 MMixerAllocatePinConnect(
70 IN PMIXER_CONTEXT MixerContext
,
73 return MixerContext
->Alloc(sizeof(KSPIN_CONNECT
) + DataFormatSize
);
77 MMixerGetWaveInfoByIndexAndType(
78 IN PMIXER_LIST MixerList
,
81 OUT LPWAVE_INFO
*OutWaveInfo
)
84 PLIST_ENTRY Entry
, ListHead
;
88 ListHead
= &MixerList
->WaveInList
;
90 ListHead
= &MixerList
->WaveOutList
;
93 Entry
= ListHead
->Flink
;
95 while(Entry
!= ListHead
)
97 WaveInfo
= (LPWAVE_INFO
)CONTAINING_RECORD(Entry
, WAVE_INFO
, Entry
);
99 if (Index
== DeviceIndex
)
101 *OutWaveInfo
= WaveInfo
;
102 return MM_STATUS_SUCCESS
;
105 Entry
= Entry
->Flink
;
108 return MM_STATUS_INVALID_PARAMETER
;
113 MMixerInitializePinConnect(
114 IN OUT PKSPIN_CONNECT PinConnect
,
117 PinConnect
->Interface
.Set
= KSINTERFACESETID_Standard
;
118 PinConnect
->Interface
.Id
= KSINTERFACE_STANDARD_STREAMING
;
119 PinConnect
->Interface
.Flags
= 0;
120 PinConnect
->Medium
.Set
= KSMEDIUMSETID_Standard
;
121 PinConnect
->Medium
.Id
= KSMEDIUM_TYPE_ANYINSTANCE
;
122 PinConnect
->Medium
.Flags
= 0;
123 PinConnect
->PinToHandle
= NULL
;
124 PinConnect
->PinId
= PinId
;
125 PinConnect
->Priority
.PriorityClass
= KSPRIORITY_NORMAL
;
126 PinConnect
->Priority
.PrioritySubClass
= 1;
130 MMixerInitializeDataFormat(
131 IN PKSDATAFORMAT_WAVEFORMATEX DataFormat
,
132 LPWAVEFORMATEX WaveFormatEx
)
135 DataFormat
->WaveFormatEx
.wFormatTag
= WaveFormatEx
->wFormatTag
;
136 DataFormat
->WaveFormatEx
.nChannels
= WaveFormatEx
->nChannels
;
137 DataFormat
->WaveFormatEx
.nSamplesPerSec
= WaveFormatEx
->nSamplesPerSec
;
138 DataFormat
->WaveFormatEx
.nBlockAlign
= WaveFormatEx
->nBlockAlign
;
139 DataFormat
->WaveFormatEx
.nAvgBytesPerSec
= WaveFormatEx
->nAvgBytesPerSec
;
140 DataFormat
->WaveFormatEx
.wBitsPerSample
= WaveFormatEx
->wBitsPerSample
;
141 DataFormat
->WaveFormatEx
.cbSize
= 0;
142 DataFormat
->DataFormat
.FormatSize
= sizeof(KSDATAFORMAT
) + sizeof(WAVEFORMATEX
);
143 DataFormat
->DataFormat
.Flags
= 0;
144 DataFormat
->DataFormat
.Reserved
= 0;
145 DataFormat
->DataFormat
.MajorFormat
= KSDATAFORMAT_TYPE_AUDIO
;
147 DataFormat
->DataFormat
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
148 DataFormat
->DataFormat
.Specifier
= KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
;
149 DataFormat
->DataFormat
.SampleSize
= 4;
154 MMixerGetAudioPinDataRanges(
155 IN PMIXER_CONTEXT MixerContext
,
158 IN OUT PKSMULTIPLE_ITEM
* OutMultipleItem
)
161 ULONG BytesReturned
= 0;
163 PKSMULTIPLE_ITEM MultipleItem
;
165 /* retrieve size of data ranges buffer */
166 PinProperty
.Reserved
= 0;
167 PinProperty
.PinId
= PinId
;
168 PinProperty
.Property
.Set
= KSPROPSETID_Pin
;
169 PinProperty
.Property
.Id
= KSPROPERTY_PIN_DATARANGES
;
170 PinProperty
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
172 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&PinProperty
, sizeof(KSP_PIN
), (PVOID
)NULL
, 0, &BytesReturned
);
173 if (Status
!= MM_STATUS_MORE_ENTRIES
)
178 MultipleItem
= MixerContext
->Alloc(BytesReturned
);
181 /* not enough memory */
182 return MM_STATUS_NO_MEMORY
;
185 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&PinProperty
, sizeof(KSP_PIN
), (PVOID
)MultipleItem
, BytesReturned
, &BytesReturned
);
186 if (Status
!= MM_STATUS_SUCCESS
)
189 MixerContext
->Free(MultipleItem
);
194 *OutMultipleItem
= MultipleItem
;
199 MMixerFindAudioDataRange(
200 PKSMULTIPLE_ITEM MultipleItem
,
201 PKSDATARANGE_AUDIO
* OutDataRangeAudio
)
204 PKSDATARANGE_AUDIO DataRangeAudio
;
205 PKSDATARANGE DataRange
;
207 DataRange
= (PKSDATARANGE
) (MultipleItem
+ 1);
208 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
210 if (DataRange
->FormatSize
== sizeof(KSDATARANGE_AUDIO
))
212 DataRangeAudio
= (PKSDATARANGE_AUDIO
)DataRange
;
213 if (IsEqualGUIDAligned(&DataRangeAudio
->DataRange
.MajorFormat
, &KSDATAFORMAT_TYPE_AUDIO
) &&
214 IsEqualGUIDAligned(&DataRangeAudio
->DataRange
.SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
) &&
215 IsEqualGUIDAligned(&DataRangeAudio
->DataRange
.Specifier
, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
))
217 DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio
->MinimumSampleFrequency
, DataRangeAudio
->MaximumSampleFrequency
,
218 DataRangeAudio
->MinimumBitsPerSample
, DataRangeAudio
->MaximumBitsPerSample
, DataRangeAudio
->MaximumChannels
);
219 *OutDataRangeAudio
= DataRangeAudio
;
220 return MM_STATUS_SUCCESS
;
223 DataRange
= (PKSDATARANGE
)((ULONG_PTR
)DataRange
+ DataRange
->FormatSize
);
225 return MM_STATUS_UNSUCCESSFUL
;
230 IN PMIXER_CONTEXT MixerContext
,
231 IN PMIXER_LIST MixerList
,
234 IN LPWAVEFORMATEX WaveFormatEx
,
235 IN ACCESS_MASK DesiredAccess
,
236 IN PIN_CREATE_CALLBACK CreateCallback
,
238 OUT PHANDLE PinHandle
)
240 PKSPIN_CONNECT PinConnect
;
241 PKSDATAFORMAT_WAVEFORMATEX DataFormat
;
242 LPMIXER_DATA MixerData
;
244 MIXER_STATUS MixerStatus
;
246 MixerData
= MMixerGetDataByDeviceId(MixerList
, DeviceId
);
248 return MM_STATUS_INVALID_PARAMETER
;
250 /* allocate pin connect */
251 PinConnect
= MMixerAllocatePinConnect(MixerContext
, sizeof(KSDATAFORMAT_WAVEFORMATEX
));
255 return MM_STATUS_NO_MEMORY
;
258 /* initialize pin connect struct */
259 MMixerInitializePinConnect(PinConnect
, PinId
);
261 /* get offset to dataformat */
262 DataFormat
= (PKSDATAFORMAT_WAVEFORMATEX
) (PinConnect
+ 1);
263 /* initialize with requested wave format */
264 MMixerInitializeDataFormat(DataFormat
, WaveFormatEx
);
268 /* let the callback handle the creation */
269 MixerStatus
= CreateCallback(Context
, DeviceId
, PinId
, MixerData
->hDevice
, PinConnect
, DesiredAccess
, PinHandle
);
273 /* now create the pin */
274 Status
= KsCreatePin(MixerData
->hDevice
, PinConnect
, DesiredAccess
, PinHandle
);
276 /* normalize status */
277 if (Status
== STATUS_SUCCESS
)
278 MixerStatus
= MM_STATUS_SUCCESS
;
280 MixerStatus
= MM_STATUS_UNSUCCESSFUL
;
283 /* free create info */
284 MixerContext
->Free(PinConnect
);
292 IN PKSDATARANGE_AUDIO DataRangeAudio
,
293 IN LPWAVE_INFO WaveInfo
,
296 ULONG Index
, SampleFrequency
;
299 for(Index
= 0; Index
< AUDIO_TEST_RANGE
; Index
++)
301 SampleFrequency
= TestRange
[Index
].SampleRate
;
303 if (DataRangeAudio
->MinimumSampleFrequency
<= SampleFrequency
&& DataRangeAudio
->MaximumSampleFrequency
>= SampleFrequency
)
305 /* the audio adapter supports the sample frequency */
306 if (DataRangeAudio
->MinimumBitsPerSample
<= 8 && DataRangeAudio
->MaximumBitsPerSample
>= 8)
308 Result
|= TestRange
[Index
].Bit8Mono
;
310 if (DataRangeAudio
->MaximumChannels
> 1)
312 /* check if pin supports the sample rate in 8-Bit Stereo */
313 Result
|= TestRange
[Index
].Bit8Stereo
;
317 if (DataRangeAudio
->MinimumBitsPerSample
<= 16 && DataRangeAudio
->MaximumBitsPerSample
>= 16)
319 /* check if pin supports the sample rate in 16-Bit Mono */
320 Result
|= TestRange
[Index
].Bit16Mono
;
323 if (DataRangeAudio
->MaximumChannels
> 1)
325 /* check if pin supports the sample rate in 16-Bit Stereo */
326 Result
|= TestRange
[Index
].Bit16Stereo
;
334 WaveInfo
->u
.InCaps
.dwFormats
= Result
;
336 WaveInfo
->u
.OutCaps
.dwFormats
= Result
;
338 DPRINT("Format %lx bInput %u\n", Result
, bInput
);
342 MMixerInitializeWaveInfo(
343 IN PMIXER_CONTEXT MixerContext
,
344 IN PMIXER_LIST MixerList
,
345 IN LPMIXER_DATA MixerData
,
346 IN LPWSTR DeviceName
,
351 PKSMULTIPLE_ITEM MultipleItem
;
352 PKSDATARANGE_AUDIO DataRangeAudio
;
353 LPWAVE_INFO WaveInfo
;
355 WaveInfo
= (LPWAVE_INFO
)MixerContext
->Alloc(sizeof(WAVE_INFO
));
357 return MM_STATUS_NO_MEMORY
;
359 /* initialize wave info */
360 WaveInfo
->DeviceId
= MixerData
->DeviceId
;
361 WaveInfo
->PinId
= PinId
;
364 /* copy device name */
367 wcscpy(WaveInfo
->u
.InCaps
.szPname
, DeviceName
);
371 wcscpy(WaveInfo
->u
.OutCaps
.szPname
, DeviceName
);
374 /* FIXME determine manufacturer / product id */
377 WaveInfo
->u
.InCaps
.wMid
= MM_MICROSOFT
;
378 WaveInfo
->u
.InCaps
.wPid
= MM_PID_UNMAPPED
;
379 WaveInfo
->u
.InCaps
.vDriverVersion
= 1;
383 WaveInfo
->u
.OutCaps
.wMid
= MM_MICROSOFT
;
384 WaveInfo
->u
.OutCaps
.wPid
= MM_PID_UNMAPPED
;
385 WaveInfo
->u
.OutCaps
.vDriverVersion
= 1;
388 /* get audio pin data ranges */
389 Status
= MMixerGetAudioPinDataRanges(MixerContext
, MixerData
->hDevice
, PinId
, &MultipleItem
);
390 if (Status
!= MM_STATUS_SUCCESS
)
392 /* failed to get audio pin data ranges */
393 MixerContext
->Free(WaveInfo
);
394 return MM_STATUS_UNSUCCESSFUL
;
397 /* find an KSDATARANGE_AUDIO range */
398 Status
= MMixerFindAudioDataRange(MultipleItem
, &DataRangeAudio
);
399 if (Status
!= MM_STATUS_SUCCESS
)
401 /* failed to find audio pin data range */
402 MixerContext
->Free(MultipleItem
);
403 MixerContext
->Free(WaveInfo
);
404 return MM_STATUS_UNSUCCESSFUL
;
407 /* store channel count */
410 WaveInfo
->u
.InCaps
.wChannels
= DataRangeAudio
->MaximumChannels
;
414 WaveInfo
->u
.OutCaps
.wChannels
= DataRangeAudio
->MaximumChannels
;
417 /* get all supported formats */
418 MMixerCheckFormat(DataRangeAudio
, WaveInfo
, bWaveIn
);
420 /* free dataranges buffer */
421 MixerContext
->Free(MultipleItem
);
428 InsertTailList(&MixerList
->WaveInList
, &WaveInfo
->Entry
);
429 MixerList
->WaveInListCount
++;
433 InsertTailList(&MixerList
->WaveOutList
, &WaveInfo
->Entry
);
434 MixerList
->WaveOutListCount
++;
437 return MM_STATUS_SUCCESS
;
442 IN PMIXER_CONTEXT MixerContext
,
443 IN ULONG DeviceIndex
,
445 IN LPWAVEFORMATEX WaveFormat
,
446 IN PIN_CREATE_CALLBACK CreateCallback
,
448 OUT PHANDLE PinHandle
)
450 PMIXER_LIST MixerList
;
452 LPWAVE_INFO WaveInfo
;
453 ACCESS_MASK DesiredAccess
= 0;
455 // verify mixer context
456 Status
= MMixerVerifyContext(MixerContext
);
458 if (Status
!= MM_STATUS_SUCCESS
)
460 // invalid context passed
465 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
467 if (WaveFormat
->wFormatTag
!= WAVE_FORMAT_PCM
)
470 return MM_STATUS_NOT_IMPLEMENTED
;
473 /* find destination wave */
474 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, bWaveIn
, &WaveInfo
);
475 if (Status
!= MM_STATUS_SUCCESS
)
477 /* failed to find wave info */
478 return MM_STATUS_INVALID_PARAMETER
;
481 /* get desired access */
484 DesiredAccess
|= GENERIC_READ
;
488 DesiredAccess
|= GENERIC_WRITE
;
491 /* now try open the pin */
492 return MMixerOpenWavePin(MixerContext
, MixerList
, WaveInfo
->DeviceId
, WaveInfo
->PinId
, WaveFormat
, DesiredAccess
, CreateCallback
, Context
, PinHandle
);
496 MMixerWaveInCapabilities(
497 IN PMIXER_CONTEXT MixerContext
,
498 IN ULONG DeviceIndex
,
499 OUT LPWAVEINCAPSW Caps
)
501 PMIXER_LIST MixerList
;
503 LPWAVE_INFO WaveInfo
;
505 // verify mixer context
506 Status
= MMixerVerifyContext(MixerContext
);
508 if (Status
!= MM_STATUS_SUCCESS
)
510 // invalid context passed
515 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
517 /* find destination wave */
518 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, TRUE
, &WaveInfo
);
519 if (Status
!= MM_STATUS_SUCCESS
)
521 /* failed to find wave info */
522 return MM_STATUS_UNSUCCESSFUL
;
526 MixerContext
->Copy(Caps
, &WaveInfo
->u
.InCaps
, sizeof(WAVEINCAPSW
));
528 return MM_STATUS_SUCCESS
;
532 MMixerWaveOutCapabilities(
533 IN PMIXER_CONTEXT MixerContext
,
534 IN ULONG DeviceIndex
,
535 OUT LPWAVEOUTCAPSW Caps
)
537 PMIXER_LIST MixerList
;
539 LPWAVE_INFO WaveInfo
;
541 // verify mixer context
542 Status
= MMixerVerifyContext(MixerContext
);
544 if (Status
!= MM_STATUS_SUCCESS
)
546 // invalid context passed
551 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
553 /* find destination wave */
554 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, FALSE
, &WaveInfo
);
555 if (Status
!= MM_STATUS_SUCCESS
)
557 /* failed to find wave info */
558 return MM_STATUS_UNSUCCESSFUL
;
562 MixerContext
->Copy(Caps
, &WaveInfo
->u
.OutCaps
, sizeof(WAVEOUTCAPSW
));
564 return MM_STATUS_SUCCESS
;
568 MMixerGetWaveInCount(
569 IN PMIXER_CONTEXT MixerContext
)
571 PMIXER_LIST MixerList
;
574 // verify mixer context
575 Status
= MMixerVerifyContext(MixerContext
);
577 if (Status
!= MM_STATUS_SUCCESS
)
579 // invalid context passed
584 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
586 return MixerList
->WaveInListCount
;
590 MMixerGetWaveOutCount(
591 IN PMIXER_CONTEXT MixerContext
)
593 PMIXER_LIST MixerList
;
596 // verify mixer context
597 Status
= MMixerVerifyContext(MixerContext
);
599 if (Status
!= MM_STATUS_SUCCESS
)
601 // invalid context passed
606 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
608 return MixerList
->WaveOutListCount
;
613 IN PMIXER_CONTEXT MixerContext
,
620 /* setup property request */
621 Property
.Set
= KSPROPSETID_Connection
;
622 Property
.Id
= KSPROPERTY_CONNECTION_STATE
;
623 Property
.Flags
= KSPROPERTY_TYPE_SET
;
625 return MixerContext
->Control(PinHandle
, IOCTL_KS_PROPERTY
, &Property
, sizeof(KSPROPERTY
), &State
, sizeof(KSSTATE
), &Length
);
629 MMixerGetWaveDevicePath(
630 IN PMIXER_CONTEXT MixerContext
,
633 OUT LPWSTR
* DevicePath
)
635 PMIXER_LIST MixerList
;
636 LPMIXER_DATA MixerData
;
637 LPWAVE_INFO WaveInfo
;
641 // verify mixer context
642 Status
= MMixerVerifyContext(MixerContext
);
644 if (Status
!= MM_STATUS_SUCCESS
)
646 // invalid context passed
651 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
653 /* find destination wave */
654 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceId
, bWaveIn
, &WaveInfo
);
655 if (Status
!= MM_STATUS_SUCCESS
)
657 /* failed to find wave info */
658 return MM_STATUS_INVALID_PARAMETER
;
661 /* get associated device id */
662 MixerData
= MMixerGetDataByDeviceId(MixerList
, WaveInfo
->DeviceId
);
664 return MM_STATUS_INVALID_PARAMETER
;
666 /* calculate length */
667 Length
= wcslen(MixerData
->DeviceName
)+1;
669 /* allocate destination buffer */
670 *DevicePath
= MixerContext
->Alloc(Length
* sizeof(WCHAR
));
675 return MM_STATUS_NO_MEMORY
;
678 /* copy device path */
679 MixerContext
->Copy(*DevicePath
, MixerData
->DeviceName
, Length
* sizeof(WCHAR
));
682 return MM_STATUS_SUCCESS
;