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
;
115 MMixerInitializeDataFormat(
116 IN PKSDATAFORMAT_WAVEFORMATEX DataFormat
,
117 LPWAVEFORMATEX WaveFormatEx
)
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
= 0;
127 DataFormat
->DataFormat
.FormatSize
= sizeof(KSDATAFORMAT
) + sizeof(WAVEFORMATEX
);
128 DataFormat
->DataFormat
.Flags
= 0;
129 DataFormat
->DataFormat
.Reserved
= 0;
130 DataFormat
->DataFormat
.MajorFormat
= KSDATAFORMAT_TYPE_AUDIO
;
132 DataFormat
->DataFormat
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
133 DataFormat
->DataFormat
.Specifier
= KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
;
134 DataFormat
->DataFormat
.SampleSize
= 4;
139 MMixerGetAudioPinDataRanges(
140 IN PMIXER_CONTEXT MixerContext
,
143 IN OUT PKSMULTIPLE_ITEM
* OutMultipleItem
)
146 ULONG BytesReturned
= 0;
148 PKSMULTIPLE_ITEM MultipleItem
;
150 /* retrieve size of data ranges buffer */
151 PinProperty
.Reserved
= 0;
152 PinProperty
.PinId
= PinId
;
153 PinProperty
.Property
.Set
= KSPROPSETID_Pin
;
154 PinProperty
.Property
.Id
= KSPROPERTY_PIN_DATARANGES
;
155 PinProperty
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
157 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&PinProperty
, sizeof(KSP_PIN
), (PVOID
)NULL
, 0, &BytesReturned
);
158 if (Status
!= MM_STATUS_MORE_ENTRIES
)
163 MultipleItem
= MixerContext
->Alloc(BytesReturned
);
166 /* not enough memory */
167 return MM_STATUS_NO_MEMORY
;
170 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&PinProperty
, sizeof(KSP_PIN
), (PVOID
)MultipleItem
, BytesReturned
, &BytesReturned
);
171 if (Status
!= MM_STATUS_SUCCESS
)
174 MixerContext
->Free(MultipleItem
);
179 *OutMultipleItem
= MultipleItem
;
184 MMixerFindAudioDataRange(
185 PKSMULTIPLE_ITEM MultipleItem
,
186 PKSDATARANGE_AUDIO
* OutDataRangeAudio
)
189 PKSDATARANGE_AUDIO DataRangeAudio
;
190 PKSDATARANGE DataRange
;
192 DataRange
= (PKSDATARANGE
) (MultipleItem
+ 1);
193 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
195 if (DataRange
->FormatSize
== sizeof(KSDATARANGE_AUDIO
))
197 DataRangeAudio
= (PKSDATARANGE_AUDIO
)DataRange
;
198 if (IsEqualGUIDAligned(&DataRangeAudio
->DataRange
.MajorFormat
, &KSDATAFORMAT_TYPE_AUDIO
) &&
199 IsEqualGUIDAligned(&DataRangeAudio
->DataRange
.SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
) &&
200 IsEqualGUIDAligned(&DataRangeAudio
->DataRange
.Specifier
, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
))
202 DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio
->MinimumSampleFrequency
, DataRangeAudio
->MaximumSampleFrequency
,
203 DataRangeAudio
->MinimumBitsPerSample
, DataRangeAudio
->MaximumBitsPerSample
, DataRangeAudio
->MaximumChannels
);
204 *OutDataRangeAudio
= DataRangeAudio
;
205 return MM_STATUS_SUCCESS
;
208 DataRange
= (PKSDATARANGE
)((ULONG_PTR
)DataRange
+ DataRange
->FormatSize
);
210 return MM_STATUS_UNSUCCESSFUL
;
215 IN PMIXER_CONTEXT MixerContext
,
216 IN PMIXER_LIST MixerList
,
219 IN LPWAVEFORMATEX WaveFormatEx
,
220 IN ACCESS_MASK DesiredAccess
,
221 IN PIN_CREATE_CALLBACK CreateCallback
,
223 OUT PHANDLE PinHandle
)
225 PKSPIN_CONNECT PinConnect
;
226 PKSDATAFORMAT_WAVEFORMATEX DataFormat
;
227 LPMIXER_DATA MixerData
;
229 MIXER_STATUS MixerStatus
;
231 MixerData
= MMixerGetDataByDeviceId(MixerList
, DeviceId
);
233 return MM_STATUS_INVALID_PARAMETER
;
235 /* allocate pin connect */
236 PinConnect
= MMixerAllocatePinConnect(MixerContext
, sizeof(KSDATAFORMAT_WAVEFORMATEX
));
240 return MM_STATUS_NO_MEMORY
;
243 /* initialize pin connect struct */
244 MMixerInitializePinConnect(PinConnect
, PinId
);
246 /* get offset to dataformat */
247 DataFormat
= (PKSDATAFORMAT_WAVEFORMATEX
) (PinConnect
+ 1);
248 /* initialize with requested wave format */
249 MMixerInitializeDataFormat(DataFormat
, WaveFormatEx
);
253 /* let the callback handle the creation */
254 MixerStatus
= CreateCallback(Context
, DeviceId
, PinId
, MixerData
->hDevice
, PinConnect
, DesiredAccess
, PinHandle
);
258 /* now create the pin */
259 Status
= KsCreatePin(MixerData
->hDevice
, PinConnect
, DesiredAccess
, PinHandle
);
261 /* normalize status */
262 if (Status
== STATUS_SUCCESS
)
263 MixerStatus
= MM_STATUS_SUCCESS
;
265 MixerStatus
= MM_STATUS_UNSUCCESSFUL
;
268 /* free create info */
269 MixerContext
->Free(PinConnect
);
277 IN PKSDATARANGE_AUDIO DataRangeAudio
,
278 IN LPWAVE_INFO WaveInfo
,
281 ULONG Index
, SampleFrequency
;
284 for(Index
= 0; Index
< AUDIO_TEST_RANGE
; Index
++)
286 SampleFrequency
= TestRange
[Index
].SampleRate
;
288 if (DataRangeAudio
->MinimumSampleFrequency
<= SampleFrequency
&& DataRangeAudio
->MaximumSampleFrequency
>= SampleFrequency
)
290 /* the audio adapter supports the sample frequency */
291 if (DataRangeAudio
->MinimumBitsPerSample
<= 8 && DataRangeAudio
->MaximumBitsPerSample
>= 8)
293 Result
|= TestRange
[Index
].Bit8Mono
;
295 if (DataRangeAudio
->MaximumChannels
> 1)
297 /* check if pin supports the sample rate in 8-Bit Stereo */
298 Result
|= TestRange
[Index
].Bit8Stereo
;
302 if (DataRangeAudio
->MinimumBitsPerSample
<= 16 && DataRangeAudio
->MaximumBitsPerSample
>= 16)
304 /* check if pin supports the sample rate in 16-Bit Mono */
305 Result
|= TestRange
[Index
].Bit16Mono
;
308 if (DataRangeAudio
->MaximumChannels
> 1)
310 /* check if pin supports the sample rate in 16-Bit Stereo */
311 Result
|= TestRange
[Index
].Bit16Stereo
;
319 WaveInfo
->u
.InCaps
.dwFormats
= Result
;
321 WaveInfo
->u
.OutCaps
.dwFormats
= Result
;
323 DPRINT("Format %lx bInput %u\n", Result
, bInput
);
327 MMixerInitializeWaveInfo(
328 IN PMIXER_CONTEXT MixerContext
,
329 IN PMIXER_LIST MixerList
,
330 IN LPMIXER_DATA MixerData
,
331 IN LPWSTR DeviceName
,
337 PKSMULTIPLE_ITEM MultipleItem
;
338 PKSDATARANGE_AUDIO DataRangeAudio
;
339 LPWAVE_INFO WaveInfo
;
341 WaveInfo
= (LPWAVE_INFO
)MixerContext
->Alloc(sizeof(WAVE_INFO
));
343 return MM_STATUS_NO_MEMORY
;
347 /* FIXME support multiple pins for wave device */
348 DPRINT1("Implement support for multiple pins\n");
349 //ASSERT(PinCount == 1);
352 /* initialize wave info */
353 WaveInfo
->DeviceId
= MixerData
->DeviceId
;
354 WaveInfo
->PinId
= Pins
[0];
357 ASSERT(wcslen(DeviceName
) + 1 < MAXPNAMELEN
);
359 /* copy device name */
362 wcscpy(WaveInfo
->u
.InCaps
.szPname
, DeviceName
);
366 wcscpy(WaveInfo
->u
.OutCaps
.szPname
, DeviceName
);
369 /* FIXME determine manufacturer / product id */
372 WaveInfo
->u
.InCaps
.wMid
= MM_MICROSOFT
;
373 WaveInfo
->u
.InCaps
.wPid
= MM_PID_UNMAPPED
;
374 WaveInfo
->u
.InCaps
.vDriverVersion
= 1;
378 WaveInfo
->u
.OutCaps
.wMid
= MM_MICROSOFT
;
379 WaveInfo
->u
.OutCaps
.wPid
= MM_PID_UNMAPPED
;
380 WaveInfo
->u
.OutCaps
.vDriverVersion
= 1;
383 /* get audio pin data ranges */
384 Status
= MMixerGetAudioPinDataRanges(MixerContext
, MixerData
->hDevice
, Pins
[0], &MultipleItem
);
385 if (Status
!= MM_STATUS_SUCCESS
)
387 /* failed to get audio pin data ranges */
388 MixerContext
->Free(WaveInfo
);
389 return MM_STATUS_UNSUCCESSFUL
;
392 /* find an KSDATARANGE_AUDIO range */
393 Status
= MMixerFindAudioDataRange(MultipleItem
, &DataRangeAudio
);
394 if (Status
!= MM_STATUS_SUCCESS
)
396 /* failed to find audio pin data range */
397 MixerContext
->Free(MultipleItem
);
398 MixerContext
->Free(WaveInfo
);
399 return MM_STATUS_UNSUCCESSFUL
;
402 /* store channel count */
405 WaveInfo
->u
.InCaps
.wChannels
= DataRangeAudio
->MaximumChannels
;
409 WaveInfo
->u
.OutCaps
.wChannels
= DataRangeAudio
->MaximumChannels
;
412 /* get all supported formats */
413 MMixerCheckFormat(DataRangeAudio
, WaveInfo
, bWaveIn
);
415 /* free dataranges buffer */
416 MixerContext
->Free(MultipleItem
);
420 InsertTailList(&MixerList
->WaveInList
, &WaveInfo
->Entry
);
421 MixerList
->WaveInListCount
++;
425 InsertTailList(&MixerList
->WaveOutList
, &WaveInfo
->Entry
);
426 MixerList
->WaveOutListCount
++;
429 return MM_STATUS_SUCCESS
;
434 IN PMIXER_CONTEXT MixerContext
,
435 IN ULONG DeviceIndex
,
437 IN LPWAVEFORMATEX WaveFormat
,
438 IN PIN_CREATE_CALLBACK CreateCallback
,
440 OUT PHANDLE PinHandle
)
442 PMIXER_LIST MixerList
;
444 LPWAVE_INFO WaveInfo
;
445 ACCESS_MASK DesiredAccess
= 0;
447 /* verify mixer context */
448 Status
= MMixerVerifyContext(MixerContext
);
450 if (Status
!= MM_STATUS_SUCCESS
)
452 /* invalid context passed */
456 /* grab mixer list */
457 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
459 if (WaveFormat
->wFormatTag
!= WAVE_FORMAT_PCM
)
461 /* not implemented */
462 return MM_STATUS_NOT_IMPLEMENTED
;
465 /* find destination wave */
466 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, bWaveIn
, &WaveInfo
);
467 if (Status
!= MM_STATUS_SUCCESS
)
469 /* failed to find wave info */
470 return MM_STATUS_INVALID_PARAMETER
;
473 /* get desired access */
476 DesiredAccess
|= GENERIC_READ
;
480 DesiredAccess
|= GENERIC_WRITE
;
483 /* now try open the pin */
484 return MMixerOpenWavePin(MixerContext
, MixerList
, WaveInfo
->DeviceId
, WaveInfo
->PinId
, WaveFormat
, DesiredAccess
, CreateCallback
, Context
, PinHandle
);
488 MMixerWaveInCapabilities(
489 IN PMIXER_CONTEXT MixerContext
,
490 IN ULONG DeviceIndex
,
491 OUT LPWAVEINCAPSW Caps
)
493 PMIXER_LIST MixerList
;
495 LPWAVE_INFO WaveInfo
;
497 /* verify mixer context */
498 Status
= MMixerVerifyContext(MixerContext
);
500 if (Status
!= MM_STATUS_SUCCESS
)
502 /* invalid context passed */
506 /* grab mixer list */
507 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
509 /* find destination wave */
510 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, TRUE
, &WaveInfo
);
511 if (Status
!= MM_STATUS_SUCCESS
)
513 /* failed to find wave info */
514 return MM_STATUS_UNSUCCESSFUL
;
517 /* copy capabilities */
518 MixerContext
->Copy(Caps
, &WaveInfo
->u
.InCaps
, sizeof(WAVEINCAPSW
));
520 return MM_STATUS_SUCCESS
;
524 MMixerWaveOutCapabilities(
525 IN PMIXER_CONTEXT MixerContext
,
526 IN ULONG DeviceIndex
,
527 OUT LPWAVEOUTCAPSW Caps
)
529 PMIXER_LIST MixerList
;
531 LPWAVE_INFO WaveInfo
;
533 /* verify mixer context */
534 Status
= MMixerVerifyContext(MixerContext
);
536 if (Status
!= MM_STATUS_SUCCESS
)
538 /* invalid context passed */
542 /* grab mixer list */
543 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
545 /* find destination wave */
546 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, FALSE
, &WaveInfo
);
547 if (Status
!= MM_STATUS_SUCCESS
)
549 /* failed to find wave info */
550 return MM_STATUS_UNSUCCESSFUL
;
553 /* copy capabilities */
554 MixerContext
->Copy(Caps
, &WaveInfo
->u
.OutCaps
, sizeof(WAVEOUTCAPSW
));
556 return MM_STATUS_SUCCESS
;
560 MMixerGetWaveInCount(
561 IN PMIXER_CONTEXT MixerContext
)
563 PMIXER_LIST MixerList
;
566 /* verify mixer context */
567 Status
= MMixerVerifyContext(MixerContext
);
569 if (Status
!= MM_STATUS_SUCCESS
)
571 /* invalid context passed */
575 /* grab mixer list */
576 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
578 return MixerList
->WaveInListCount
;
582 MMixerGetWaveOutCount(
583 IN PMIXER_CONTEXT MixerContext
)
585 PMIXER_LIST MixerList
;
588 /* verify mixer context */
589 Status
= MMixerVerifyContext(MixerContext
);
591 if (Status
!= MM_STATUS_SUCCESS
)
593 /* invalid context passed */
597 /* grab mixer list */
598 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
600 return MixerList
->WaveOutListCount
;
605 IN PMIXER_CONTEXT MixerContext
,
612 /* setup property request */
613 Property
.Set
= KSPROPSETID_Connection
;
614 Property
.Id
= KSPROPERTY_CONNECTION_STATE
;
615 Property
.Flags
= KSPROPERTY_TYPE_SET
;
617 return MixerContext
->Control(PinHandle
, IOCTL_KS_PROPERTY
, &Property
, sizeof(KSPROPERTY
), &State
, sizeof(KSSTATE
), &Length
);
621 MMixerGetWaveDevicePath(
622 IN PMIXER_CONTEXT MixerContext
,
625 OUT LPWSTR
* DevicePath
)
627 PMIXER_LIST MixerList
;
628 LPMIXER_DATA MixerData
;
629 LPWAVE_INFO WaveInfo
;
633 /* verify mixer context */
634 Status
= MMixerVerifyContext(MixerContext
);
636 if (Status
!= MM_STATUS_SUCCESS
)
638 /* invalid context passed */
642 /* grab mixer list */
643 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
645 /* find destination wave */
646 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceId
, bWaveIn
, &WaveInfo
);
647 if (Status
!= MM_STATUS_SUCCESS
)
649 /* failed to find wave info */
650 return MM_STATUS_INVALID_PARAMETER
;
653 /* get associated device id */
654 MixerData
= MMixerGetDataByDeviceId(MixerList
, WaveInfo
->DeviceId
);
656 return MM_STATUS_INVALID_PARAMETER
;
658 /* calculate length */
659 Length
= wcslen(MixerData
->DeviceName
)+1;
661 /* allocate destination buffer */
662 *DevicePath
= MixerContext
->Alloc(Length
* sizeof(WCHAR
));
667 return MM_STATUS_NO_MEMORY
;
670 /* copy device path */
671 MixerContext
->Copy(*DevicePath
, MixerData
->DeviceName
, Length
* sizeof(WCHAR
));
674 return MM_STATUS_SUCCESS
;