2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: lib/drivers/sound/mmixer/mmixer.c
5 * PURPOSE: Mixer Handling Functions
6 * PROGRAMMER: Johannes Anderwald
11 const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
= {0x05589f81L
, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
12 const GUID KSDATAFORMAT_SUBTYPE_PCM
= {0x00000001L
, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
13 const GUID KSDATAFORMAT_TYPE_AUDIO
= {0x73647561L
, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
14 const GUID KSINTERFACESETID_Standard
= {0x1A8766A0L
, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
15 const GUID KSMEDIUMSETID_Standard
= {0x4747B320L
, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
26 #define AUDIO_TEST_RANGE (5)
28 static AUDIO_RANGE TestRange
[AUDIO_TEST_RANGE
] =
68 MMixerAllocatePinConnect(
69 IN PMIXER_CONTEXT MixerContext
,
72 return MixerContext
->Alloc(sizeof(KSPIN_CONNECT
) + DataFormatSize
);
76 MMixerGetWaveInfoByIndexAndType(
77 IN PMIXER_LIST MixerList
,
80 OUT LPWAVE_INFO
*OutWaveInfo
)
83 PLIST_ENTRY Entry
, ListHead
;
87 ListHead
= &MixerList
->WaveInList
;
89 ListHead
= &MixerList
->WaveOutList
;
92 Entry
= ListHead
->Flink
;
94 while(Entry
!= ListHead
)
96 WaveInfo
= (LPWAVE_INFO
)CONTAINING_RECORD(Entry
, WAVE_INFO
, Entry
);
98 if (Index
== DeviceIndex
)
100 *OutWaveInfo
= WaveInfo
;
101 return MM_STATUS_SUCCESS
;
104 Entry
= Entry
->Flink
;
107 return MM_STATUS_INVALID_PARAMETER
;
112 MMixerInitializePinConnect(
113 IN OUT PKSPIN_CONNECT PinConnect
,
116 PinConnect
->Interface
.Set
= KSINTERFACESETID_Standard
;
117 PinConnect
->Interface
.Id
= KSINTERFACE_STANDARD_STREAMING
;
118 PinConnect
->Interface
.Flags
= 0;
119 PinConnect
->Medium
.Set
= KSMEDIUMSETID_Standard
;
120 PinConnect
->Medium
.Id
= KSMEDIUM_TYPE_ANYINSTANCE
;
121 PinConnect
->Medium
.Flags
= 0;
122 PinConnect
->PinToHandle
= NULL
;
123 PinConnect
->PinId
= PinId
;
124 PinConnect
->Priority
.PriorityClass
= KSPRIORITY_NORMAL
;
125 PinConnect
->Priority
.PrioritySubClass
= 1;
129 MMixerInitializeDataFormat(
130 IN PKSDATAFORMAT_WAVEFORMATEX DataFormat
,
131 LPWAVEFORMATEX WaveFormatEx
)
134 DataFormat
->WaveFormatEx
.wFormatTag
= WaveFormatEx
->wFormatTag
;
135 DataFormat
->WaveFormatEx
.nChannels
= WaveFormatEx
->nChannels
;
136 DataFormat
->WaveFormatEx
.nSamplesPerSec
= WaveFormatEx
->nSamplesPerSec
;
137 DataFormat
->WaveFormatEx
.nBlockAlign
= WaveFormatEx
->nBlockAlign
;
138 DataFormat
->WaveFormatEx
.nAvgBytesPerSec
= WaveFormatEx
->nAvgBytesPerSec
;
139 DataFormat
->WaveFormatEx
.wBitsPerSample
= WaveFormatEx
->wBitsPerSample
;
140 DataFormat
->WaveFormatEx
.cbSize
= 0;
141 DataFormat
->DataFormat
.FormatSize
= sizeof(KSDATAFORMAT
) + sizeof(WAVEFORMATEX
);
142 DataFormat
->DataFormat
.Flags
= 0;
143 DataFormat
->DataFormat
.Reserved
= 0;
144 DataFormat
->DataFormat
.MajorFormat
= KSDATAFORMAT_TYPE_AUDIO
;
146 DataFormat
->DataFormat
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
147 DataFormat
->DataFormat
.Specifier
= KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
;
148 DataFormat
->DataFormat
.SampleSize
= 4;
153 MMixerGetAudioPinDataRanges(
154 IN PMIXER_CONTEXT MixerContext
,
157 IN OUT PKSMULTIPLE_ITEM
* OutMultipleItem
)
160 ULONG BytesReturned
= 0;
162 PKSMULTIPLE_ITEM MultipleItem
;
164 /* retrieve size of data ranges buffer */
165 PinProperty
.Reserved
= 0;
166 PinProperty
.PinId
= PinId
;
167 PinProperty
.Property
.Set
= KSPROPSETID_Pin
;
168 PinProperty
.Property
.Id
= KSPROPERTY_PIN_DATARANGES
;
169 PinProperty
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
171 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&PinProperty
, sizeof(KSP_PIN
), (PVOID
)NULL
, 0, &BytesReturned
);
172 if (Status
!= MM_STATUS_MORE_ENTRIES
)
177 MultipleItem
= MixerContext
->Alloc(BytesReturned
);
180 /* not enough memory */
181 return MM_STATUS_NO_MEMORY
;
184 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&PinProperty
, sizeof(KSP_PIN
), (PVOID
)MultipleItem
, BytesReturned
, &BytesReturned
);
185 if (Status
!= MM_STATUS_SUCCESS
)
188 MixerContext
->Free(MultipleItem
);
193 *OutMultipleItem
= MultipleItem
;
198 MMixerFindAudioDataRange(
199 PKSMULTIPLE_ITEM MultipleItem
,
200 PKSDATARANGE_AUDIO
* OutDataRangeAudio
)
203 PKSDATARANGE_AUDIO DataRangeAudio
;
204 PKSDATARANGE DataRange
;
206 DataRange
= (PKSDATARANGE
) (MultipleItem
+ 1);
207 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
209 if (DataRange
->FormatSize
== sizeof(KSDATARANGE_AUDIO
))
211 DataRangeAudio
= (PKSDATARANGE_AUDIO
)DataRange
;
212 if (IsEqualGUIDAligned(&DataRangeAudio
->DataRange
.MajorFormat
, &KSDATAFORMAT_TYPE_AUDIO
) &&
213 IsEqualGUIDAligned(&DataRangeAudio
->DataRange
.SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
) &&
214 IsEqualGUIDAligned(&DataRangeAudio
->DataRange
.Specifier
, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
))
216 DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio
->MinimumSampleFrequency
, DataRangeAudio
->MaximumSampleFrequency
,
217 DataRangeAudio
->MinimumBitsPerSample
, DataRangeAudio
->MaximumBitsPerSample
, DataRangeAudio
->MaximumChannels
);
218 *OutDataRangeAudio
= DataRangeAudio
;
219 return MM_STATUS_SUCCESS
;
222 DataRange
= (PKSDATARANGE
)((ULONG_PTR
)DataRange
+ DataRange
->FormatSize
);
224 return MM_STATUS_UNSUCCESSFUL
;
229 IN PMIXER_CONTEXT MixerContext
,
230 IN PMIXER_LIST MixerList
,
233 IN LPWAVEFORMATEX WaveFormatEx
,
234 IN ACCESS_MASK DesiredAccess
,
235 OUT PHANDLE PinHandle
)
237 PKSPIN_CONNECT PinConnect
;
238 PKSDATAFORMAT_WAVEFORMATEX DataFormat
;
239 LPMIXER_DATA MixerData
;
242 MixerData
= MMixerGetDataByDeviceId(MixerList
, DeviceId
);
244 return MM_STATUS_INVALID_PARAMETER
;
246 /* allocate pin connect */
247 PinConnect
= MMixerAllocatePinConnect(MixerContext
, sizeof(KSDATAFORMAT_WAVEFORMATEX
));
251 return MM_STATUS_NO_MEMORY
;
254 /* initialize pin connect struct */
255 MMixerInitializePinConnect(PinConnect
, PinId
);
257 /* get offset to dataformat */
258 DataFormat
= (PKSDATAFORMAT_WAVEFORMATEX
) (PinConnect
+ 1);
259 /* initialize with requested wave format */
260 MMixerInitializeDataFormat(DataFormat
, WaveFormatEx
);
262 /* now create the pin */
263 Status
= KsCreatePin(MixerData
->hDevice
, PinConnect
, DesiredAccess
, PinHandle
);
265 /* free create info */
266 MixerContext
->Free(PinConnect
);
268 if (Status
== STATUS_SUCCESS
)
269 return MM_STATUS_SUCCESS
;
271 return MM_STATUS_UNSUCCESSFUL
;
276 IN PKSDATARANGE_AUDIO DataRangeAudio
,
277 IN LPWAVE_INFO WaveInfo
,
280 ULONG Index
, SampleFrequency
;
283 for(Index
= 0; Index
< AUDIO_TEST_RANGE
; Index
++)
285 SampleFrequency
= TestRange
[Index
].SampleRate
;
287 if (DataRangeAudio
->MinimumSampleFrequency
<= SampleFrequency
&& DataRangeAudio
->MaximumSampleFrequency
>= SampleFrequency
)
289 /* the audio adapter supports the sample frequency */
290 if (DataRangeAudio
->MinimumBitsPerSample
<= 8 && DataRangeAudio
->MaximumBitsPerSample
>= 8)
292 Result
|= TestRange
[Index
].Bit8Mono
;
294 if (DataRangeAudio
->MaximumChannels
> 1)
296 /* check if pin supports the sample rate in 8-Bit Stereo */
297 Result
|= TestRange
[Index
].Bit8Stereo
;
301 if (DataRangeAudio
->MinimumBitsPerSample
<= 16 && DataRangeAudio
->MaximumBitsPerSample
>= 16)
303 /* check if pin supports the sample rate in 16-Bit Mono */
304 Result
|= TestRange
[Index
].Bit16Mono
;
307 if (DataRangeAudio
->MaximumChannels
> 1)
309 /* check if pin supports the sample rate in 16-Bit Stereo */
310 Result
|= TestRange
[Index
].Bit16Stereo
;
318 WaveInfo
->u
.InCaps
.dwFormats
= Result
;
320 WaveInfo
->u
.OutCaps
.dwFormats
= Result
;
322 DPRINT("Format %lx bInput %u\n", Result
, bInput
);
326 MMixerInitializeWaveInfo(
327 IN PMIXER_CONTEXT MixerContext
,
328 IN PMIXER_LIST MixerList
,
329 IN LPMIXER_DATA MixerData
,
330 IN LPWSTR DeviceName
,
335 PKSMULTIPLE_ITEM MultipleItem
;
336 PKSDATARANGE_AUDIO DataRangeAudio
;
337 LPWAVE_INFO WaveInfo
;
339 WaveInfo
= (LPWAVE_INFO
)MixerContext
->Alloc(sizeof(WAVE_INFO
));
341 return MM_STATUS_NO_MEMORY
;
343 /* initialize wave info */
344 WaveInfo
->DeviceId
= MixerData
->DeviceId
;
345 WaveInfo
->PinId
= PinId
;
347 /* FIXME determine manufacturer / product id */
350 WaveInfo
->u
.InCaps
.wMid
= MM_MICROSOFT
;
351 WaveInfo
->u
.InCaps
.wPid
= MM_PID_UNMAPPED
;
352 WaveInfo
->u
.InCaps
.vDriverVersion
= 1;
356 WaveInfo
->u
.OutCaps
.wMid
= MM_MICROSOFT
;
357 WaveInfo
->u
.OutCaps
.wPid
= MM_PID_UNMAPPED
;
358 WaveInfo
->u
.OutCaps
.vDriverVersion
= 1;
361 /* get audio pin data ranges */
362 Status
= MMixerGetAudioPinDataRanges(MixerContext
, MixerData
->hDevice
, PinId
, &MultipleItem
);
363 if (Status
!= MM_STATUS_SUCCESS
)
365 /* failed to get audio pin data ranges */
366 MixerContext
->Free(WaveInfo
);
367 return MM_STATUS_UNSUCCESSFUL
;
370 /* find an KSDATARANGE_AUDIO range */
371 Status
= MMixerFindAudioDataRange(MultipleItem
, &DataRangeAudio
);
372 if (Status
!= MM_STATUS_SUCCESS
)
374 /* failed to find audio pin data range */
375 MixerContext
->Free(MultipleItem
);
376 MixerContext
->Free(WaveInfo
);
377 return MM_STATUS_UNSUCCESSFUL
;
380 /* store channel count */
383 WaveInfo
->u
.InCaps
.wChannels
= DataRangeAudio
->MaximumChannels
;
387 WaveInfo
->u
.OutCaps
.wChannels
= DataRangeAudio
->MaximumChannels
;
390 /* get all supported formats */
391 MMixerCheckFormat(DataRangeAudio
, WaveInfo
, bWaveIn
);
393 /* free dataranges buffer */
394 MixerContext
->Free(MultipleItem
);
399 InsertTailList(&MixerList
->WaveInList
, &WaveInfo
->Entry
);
400 MixerList
->WaveInListCount
++;
404 InsertTailList(&MixerList
->WaveOutList
, &WaveInfo
->Entry
);
405 MixerList
->WaveOutListCount
++;
408 return MM_STATUS_SUCCESS
;
413 IN PMIXER_CONTEXT MixerContext
,
414 IN ULONG DeviceIndex
,
416 IN LPWAVEFORMATEX WaveFormat
,
417 OUT PHANDLE PinHandle
)
419 PMIXER_LIST MixerList
;
421 LPWAVE_INFO WaveInfo
;
422 ACCESS_MASK DesiredAccess
= 0;
424 // verify mixer context
425 Status
= MMixerVerifyContext(MixerContext
);
427 if (Status
!= MM_STATUS_SUCCESS
)
429 // invalid context passed
434 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
436 if (WaveFormat
->wFormatTag
!= WAVE_FORMAT_PCM
)
439 return MM_STATUS_NOT_IMPLEMENTED
;
442 /* find destination wave */
443 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, bWaveIn
, &WaveInfo
);
444 if (Status
!= MM_STATUS_SUCCESS
)
446 /* failed to find wave info */
447 return MM_STATUS_INVALID_PARAMETER
;
450 /* get desired access */
453 DesiredAccess
|= GENERIC_READ
;
457 DesiredAccess
|= GENERIC_WRITE
;
460 /* now try open the pin */
461 return MMixerOpenWavePin(MixerContext
, MixerList
, WaveInfo
->DeviceId
, WaveInfo
->PinId
, WaveFormat
, DesiredAccess
, PinHandle
);
465 MMixerWaveInCapabilities(
466 IN PMIXER_CONTEXT MixerContext
,
467 IN ULONG DeviceIndex
,
468 OUT LPWAVEINCAPSW Caps
)
470 PMIXER_LIST MixerList
;
472 LPWAVE_INFO WaveInfo
;
474 // verify mixer context
475 Status
= MMixerVerifyContext(MixerContext
);
477 if (Status
!= MM_STATUS_SUCCESS
)
479 // invalid context passed
484 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
486 /* find destination wave */
487 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, TRUE
, &WaveInfo
);
488 if (Status
!= MM_STATUS_SUCCESS
)
490 /* failed to find wave info */
491 return MM_STATUS_UNSUCCESSFUL
;
495 MixerContext
->Copy(Caps
, &WaveInfo
->u
.InCaps
, sizeof(WAVEINCAPSW
));
497 return MM_STATUS_SUCCESS
;
501 MMixerWaveOutCapabilities(
502 IN PMIXER_CONTEXT MixerContext
,
503 IN ULONG DeviceIndex
,
504 OUT LPWAVEOUTCAPSW Caps
)
506 PMIXER_LIST MixerList
;
508 LPWAVE_INFO WaveInfo
;
510 // verify mixer context
511 Status
= MMixerVerifyContext(MixerContext
);
513 if (Status
!= MM_STATUS_SUCCESS
)
515 // invalid context passed
520 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
522 /* find destination wave */
523 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, FALSE
, &WaveInfo
);
524 if (Status
!= MM_STATUS_SUCCESS
)
526 /* failed to find wave info */
527 return MM_STATUS_UNSUCCESSFUL
;
531 MixerContext
->Copy(Caps
, &WaveInfo
->u
.OutCaps
, sizeof(WAVEOUTCAPSW
));
533 return MM_STATUS_SUCCESS
;
537 MMixerGetWaveInCount(
538 IN PMIXER_CONTEXT MixerContext
)
540 PMIXER_LIST MixerList
;
543 // verify mixer context
544 Status
= MMixerVerifyContext(MixerContext
);
546 if (Status
!= MM_STATUS_SUCCESS
)
548 // invalid context passed
553 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
555 return MixerList
->WaveInListCount
;
559 MMixerGetWaveOutCount(
560 IN PMIXER_CONTEXT MixerContext
)
562 PMIXER_LIST MixerList
;
565 // verify mixer context
566 Status
= MMixerVerifyContext(MixerContext
);
568 if (Status
!= MM_STATUS_SUCCESS
)
570 // invalid context passed
575 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
577 return MixerList
->WaveOutListCount
;