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
,
352 PKSMULTIPLE_ITEM MultipleItem
;
353 PKSDATARANGE_AUDIO DataRangeAudio
;
354 LPWAVE_INFO WaveInfo
;
356 WaveInfo
= (LPWAVE_INFO
)MixerContext
->Alloc(sizeof(WAVE_INFO
));
358 return MM_STATUS_NO_MEMORY
;
362 /* FIXME support multiple pins for wave device */
363 DPRINT1("Implement support for multiple pins\n");
364 //ASSERT(PinCount == 1);
367 /* initialize wave info */
368 WaveInfo
->DeviceId
= MixerData
->DeviceId
;
369 WaveInfo
->PinId
= Pins
[0];
372 ASSERT(wcslen(DeviceName
) < MAXPNAMELEN
);
374 /* copy device name */
377 wcscpy(WaveInfo
->u
.InCaps
.szPname
, DeviceName
);
381 wcscpy(WaveInfo
->u
.OutCaps
.szPname
, DeviceName
);
384 /* FIXME determine manufacturer / product id */
387 WaveInfo
->u
.InCaps
.wMid
= MM_MICROSOFT
;
388 WaveInfo
->u
.InCaps
.wPid
= MM_PID_UNMAPPED
;
389 WaveInfo
->u
.InCaps
.vDriverVersion
= 1;
393 WaveInfo
->u
.OutCaps
.wMid
= MM_MICROSOFT
;
394 WaveInfo
->u
.OutCaps
.wPid
= MM_PID_UNMAPPED
;
395 WaveInfo
->u
.OutCaps
.vDriverVersion
= 1;
398 /* get audio pin data ranges */
399 Status
= MMixerGetAudioPinDataRanges(MixerContext
, MixerData
->hDevice
, Pins
[0], &MultipleItem
);
400 if (Status
!= MM_STATUS_SUCCESS
)
402 /* failed to get audio pin data ranges */
403 MixerContext
->Free(WaveInfo
);
404 return MM_STATUS_UNSUCCESSFUL
;
407 /* find an KSDATARANGE_AUDIO range */
408 Status
= MMixerFindAudioDataRange(MultipleItem
, &DataRangeAudio
);
409 if (Status
!= MM_STATUS_SUCCESS
)
411 /* failed to find audio pin data range */
412 MixerContext
->Free(MultipleItem
);
413 MixerContext
->Free(WaveInfo
);
414 return MM_STATUS_UNSUCCESSFUL
;
417 /* store channel count */
420 WaveInfo
->u
.InCaps
.wChannels
= DataRangeAudio
->MaximumChannels
;
424 WaveInfo
->u
.OutCaps
.wChannels
= DataRangeAudio
->MaximumChannels
;
427 /* get all supported formats */
428 MMixerCheckFormat(DataRangeAudio
, WaveInfo
, bWaveIn
);
430 /* free dataranges buffer */
431 MixerContext
->Free(MultipleItem
);
435 InsertTailList(&MixerList
->WaveInList
, &WaveInfo
->Entry
);
436 MixerList
->WaveInListCount
++;
440 InsertTailList(&MixerList
->WaveOutList
, &WaveInfo
->Entry
);
441 MixerList
->WaveOutListCount
++;
444 return MM_STATUS_SUCCESS
;
449 IN PMIXER_CONTEXT MixerContext
,
450 IN ULONG DeviceIndex
,
452 IN LPWAVEFORMATEX WaveFormat
,
453 IN PIN_CREATE_CALLBACK CreateCallback
,
455 OUT PHANDLE PinHandle
)
457 PMIXER_LIST MixerList
;
459 LPWAVE_INFO WaveInfo
;
460 ACCESS_MASK DesiredAccess
= 0;
462 /* verify mixer context */
463 Status
= MMixerVerifyContext(MixerContext
);
465 if (Status
!= MM_STATUS_SUCCESS
)
467 /* invalid context passed */
471 /* grab mixer list */
472 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
474 if (WaveFormat
->wFormatTag
!= WAVE_FORMAT_PCM
)
476 /* not implemented */
477 return MM_STATUS_NOT_IMPLEMENTED
;
480 /* find destination wave */
481 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, bWaveIn
, &WaveInfo
);
482 if (Status
!= MM_STATUS_SUCCESS
)
484 /* failed to find wave info */
485 return MM_STATUS_INVALID_PARAMETER
;
488 /* get desired access */
491 DesiredAccess
|= GENERIC_READ
;
495 DesiredAccess
|= GENERIC_WRITE
;
498 /* now try open the pin */
499 return MMixerOpenWavePin(MixerContext
, MixerList
, WaveInfo
->DeviceId
, WaveInfo
->PinId
, WaveFormat
, DesiredAccess
, CreateCallback
, Context
, PinHandle
);
503 MMixerWaveInCapabilities(
504 IN PMIXER_CONTEXT MixerContext
,
505 IN ULONG DeviceIndex
,
506 OUT LPWAVEINCAPSW Caps
)
508 PMIXER_LIST MixerList
;
510 LPWAVE_INFO WaveInfo
;
512 /* verify mixer context */
513 Status
= MMixerVerifyContext(MixerContext
);
515 if (Status
!= MM_STATUS_SUCCESS
)
517 /* invalid context passed */
521 /* grab mixer list */
522 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
524 /* find destination wave */
525 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, TRUE
, &WaveInfo
);
526 if (Status
!= MM_STATUS_SUCCESS
)
528 /* failed to find wave info */
529 return MM_STATUS_UNSUCCESSFUL
;
532 /* copy capabilities */
533 MixerContext
->Copy(Caps
, &WaveInfo
->u
.InCaps
, sizeof(WAVEINCAPSW
));
535 return MM_STATUS_SUCCESS
;
539 MMixerWaveOutCapabilities(
540 IN PMIXER_CONTEXT MixerContext
,
541 IN ULONG DeviceIndex
,
542 OUT LPWAVEOUTCAPSW Caps
)
544 PMIXER_LIST MixerList
;
546 LPWAVE_INFO WaveInfo
;
548 /* verify mixer context */
549 Status
= MMixerVerifyContext(MixerContext
);
551 if (Status
!= MM_STATUS_SUCCESS
)
553 /* invalid context passed */
557 /* grab mixer list */
558 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
560 /* find destination wave */
561 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceIndex
, FALSE
, &WaveInfo
);
562 if (Status
!= MM_STATUS_SUCCESS
)
564 /* failed to find wave info */
565 return MM_STATUS_UNSUCCESSFUL
;
568 /* copy capabilities */
569 MixerContext
->Copy(Caps
, &WaveInfo
->u
.OutCaps
, sizeof(WAVEOUTCAPSW
));
571 return MM_STATUS_SUCCESS
;
575 MMixerGetWaveInCount(
576 IN PMIXER_CONTEXT MixerContext
)
578 PMIXER_LIST MixerList
;
581 /* verify mixer context */
582 Status
= MMixerVerifyContext(MixerContext
);
584 if (Status
!= MM_STATUS_SUCCESS
)
586 /* invalid context passed */
590 /* grab mixer list */
591 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
593 return MixerList
->WaveInListCount
;
597 MMixerGetWaveOutCount(
598 IN PMIXER_CONTEXT MixerContext
)
600 PMIXER_LIST MixerList
;
603 /* verify mixer context */
604 Status
= MMixerVerifyContext(MixerContext
);
606 if (Status
!= MM_STATUS_SUCCESS
)
608 /* invalid context passed */
612 /* grab mixer list */
613 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
615 return MixerList
->WaveOutListCount
;
620 IN PMIXER_CONTEXT MixerContext
,
627 /* setup property request */
628 Property
.Set
= KSPROPSETID_Connection
;
629 Property
.Id
= KSPROPERTY_CONNECTION_STATE
;
630 Property
.Flags
= KSPROPERTY_TYPE_SET
;
632 return MixerContext
->Control(PinHandle
, IOCTL_KS_PROPERTY
, &Property
, sizeof(KSPROPERTY
), &State
, sizeof(KSSTATE
), &Length
);
636 MMixerGetWaveDevicePath(
637 IN PMIXER_CONTEXT MixerContext
,
640 OUT LPWSTR
* DevicePath
)
642 PMIXER_LIST MixerList
;
643 LPMIXER_DATA MixerData
;
644 LPWAVE_INFO WaveInfo
;
648 /* verify mixer context */
649 Status
= MMixerVerifyContext(MixerContext
);
651 if (Status
!= MM_STATUS_SUCCESS
)
653 /* invalid context passed */
657 /* grab mixer list */
658 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
660 /* find destination wave */
661 Status
= MMixerGetWaveInfoByIndexAndType(MixerList
, DeviceId
, bWaveIn
, &WaveInfo
);
662 if (Status
!= MM_STATUS_SUCCESS
)
664 /* failed to find wave info */
665 return MM_STATUS_INVALID_PARAMETER
;
668 /* get associated device id */
669 MixerData
= MMixerGetDataByDeviceId(MixerList
, WaveInfo
->DeviceId
);
671 return MM_STATUS_INVALID_PARAMETER
;
673 /* calculate length */
674 Length
= wcslen(MixerData
->DeviceName
)+1;
676 /* allocate destination buffer */
677 *DevicePath
= MixerContext
->Alloc(Length
* sizeof(WCHAR
));
682 return MM_STATUS_NO_MEMORY
;
685 /* copy device path */
686 MixerContext
->Copy(*DevicePath
, MixerData
->DeviceName
, Length
* sizeof(WCHAR
));
689 return MM_STATUS_SUCCESS
;