[MMIXER]
[reactos.git] / reactos / lib / drivers / sound / mmixer / wave.c
1 /*
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
7 */
8
9 #include "priv.h"
10
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}};
16
17 typedef struct
18 {
19 ULONG SampleRate;
20 ULONG Bit8Mono;
21 ULONG Bit8Stereo;
22 ULONG Bit16Mono;
23 ULONG Bit16Stereo;
24 }AUDIO_RANGE;
25
26 #define AUDIO_TEST_RANGE (5)
27
28 static AUDIO_RANGE TestRange[AUDIO_TEST_RANGE] =
29 {
30 {
31 11025,
32 WAVE_FORMAT_1M08,
33 WAVE_FORMAT_1S08,
34 WAVE_FORMAT_1M16,
35 WAVE_FORMAT_1S16
36 },
37 {
38 22050,
39 WAVE_FORMAT_2M08,
40 WAVE_FORMAT_2S08,
41 WAVE_FORMAT_2M16,
42 WAVE_FORMAT_2S16
43 },
44 {
45 44100,
46 WAVE_FORMAT_4M08,
47 WAVE_FORMAT_4S08,
48 WAVE_FORMAT_4M16,
49 WAVE_FORMAT_4S16
50 },
51 {
52 48000,
53 WAVE_FORMAT_48M08,
54 WAVE_FORMAT_48S08,
55 WAVE_FORMAT_48M16,
56 WAVE_FORMAT_48S16
57 },
58 {
59 96000,
60 WAVE_FORMAT_96M08,
61 WAVE_FORMAT_96S08,
62 WAVE_FORMAT_96M16,
63 WAVE_FORMAT_96S16
64 }
65 };
66
67 PKSPIN_CONNECT
68 MMixerAllocatePinConnect(
69 IN PMIXER_CONTEXT MixerContext,
70 ULONG DataFormatSize)
71 {
72 return MixerContext->Alloc(sizeof(KSPIN_CONNECT) + DataFormatSize);
73 }
74
75 MIXER_STATUS
76 MMixerGetWaveInfoByIndexAndType(
77 IN PMIXER_LIST MixerList,
78 IN ULONG DeviceIndex,
79 IN ULONG bWaveInType,
80 OUT LPWAVE_INFO *OutWaveInfo)
81 {
82 ULONG Index = 0;
83 PLIST_ENTRY Entry, ListHead;
84 LPWAVE_INFO WaveInfo;
85
86 if (bWaveInType)
87 ListHead = &MixerList->WaveInList;
88 else
89 ListHead = &MixerList->WaveOutList;
90
91 /* get first entry */
92 Entry = ListHead->Flink;
93
94 while(Entry != ListHead)
95 {
96 WaveInfo = (LPWAVE_INFO)CONTAINING_RECORD(Entry, WAVE_INFO, Entry);
97
98 if (Index == DeviceIndex)
99 {
100 *OutWaveInfo = WaveInfo;
101 return MM_STATUS_SUCCESS;
102 }
103 Index++;
104 Entry = Entry->Flink;
105 }
106
107 return MM_STATUS_INVALID_PARAMETER;
108 }
109
110
111 VOID
112 MMixerInitializePinConnect(
113 IN OUT PKSPIN_CONNECT PinConnect,
114 IN ULONG PinId)
115 {
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;
126 }
127
128 VOID
129 MMixerInitializeDataFormat(
130 IN PKSDATAFORMAT_WAVEFORMATEX DataFormat,
131 LPWAVEFORMATEX WaveFormatEx)
132 {
133
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;
145
146 DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
147 DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
148 DataFormat->DataFormat.SampleSize = 4;
149 }
150
151
152 MIXER_STATUS
153 MMixerGetAudioPinDataRanges(
154 IN PMIXER_CONTEXT MixerContext,
155 IN HANDLE hDevice,
156 IN ULONG PinId,
157 IN OUT PKSMULTIPLE_ITEM * OutMultipleItem)
158 {
159 KSP_PIN PinProperty;
160 ULONG BytesReturned = 0;
161 MIXER_STATUS Status;
162 PKSMULTIPLE_ITEM MultipleItem;
163
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;
170
171 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)NULL, 0, &BytesReturned);
172 if (Status != MM_STATUS_MORE_ENTRIES)
173 {
174 return Status;
175 }
176
177 MultipleItem = MixerContext->Alloc(BytesReturned);
178 if (!MultipleItem)
179 {
180 /* not enough memory */
181 return MM_STATUS_NO_MEMORY;
182 }
183
184 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
185 if (Status != MM_STATUS_SUCCESS)
186 {
187 /* failed */
188 MixerContext->Free(MultipleItem);
189 return Status;
190 }
191
192 /* save result */
193 *OutMultipleItem = MultipleItem;
194 return Status;
195 }
196
197 MIXER_STATUS
198 MMixerFindAudioDataRange(
199 PKSMULTIPLE_ITEM MultipleItem,
200 PKSDATARANGE_AUDIO * OutDataRangeAudio)
201 {
202 ULONG Index;
203 PKSDATARANGE_AUDIO DataRangeAudio;
204 PKSDATARANGE DataRange;
205
206 DataRange = (PKSDATARANGE) (MultipleItem + 1);
207 for(Index = 0; Index < MultipleItem->Count; Index++)
208 {
209 if (DataRange->FormatSize == sizeof(KSDATARANGE_AUDIO))
210 {
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))
215 {
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;
220 }
221 }
222 DataRange = (PKSDATARANGE)((ULONG_PTR)DataRange + DataRange->FormatSize);
223 }
224 return MM_STATUS_UNSUCCESSFUL;
225 }
226
227 MIXER_STATUS
228 MMixerOpenWavePin(
229 IN PMIXER_CONTEXT MixerContext,
230 IN PMIXER_LIST MixerList,
231 IN ULONG DeviceId,
232 IN ULONG PinId,
233 IN LPWAVEFORMATEX WaveFormatEx,
234 IN ACCESS_MASK DesiredAccess,
235 OUT PHANDLE PinHandle)
236 {
237 PKSPIN_CONNECT PinConnect;
238 PKSDATAFORMAT_WAVEFORMATEX DataFormat;
239 LPMIXER_DATA MixerData;
240 NTSTATUS Status;
241
242 MixerData = MMixerGetDataByDeviceId(MixerList, DeviceId);
243 if (!MixerData)
244 return MM_STATUS_INVALID_PARAMETER;
245
246 /* allocate pin connect */
247 PinConnect = MMixerAllocatePinConnect(MixerContext, sizeof(KSDATAFORMAT_WAVEFORMATEX));
248 if (!PinConnect)
249 {
250 /* no memory */
251 return MM_STATUS_NO_MEMORY;
252 }
253
254 /* initialize pin connect struct */
255 MMixerInitializePinConnect(PinConnect, PinId);
256
257 /* get offset to dataformat */
258 DataFormat = (PKSDATAFORMAT_WAVEFORMATEX) (PinConnect + 1);
259 /* initialize with requested wave format */
260 MMixerInitializeDataFormat(DataFormat, WaveFormatEx);
261
262 /* now create the pin */
263 Status = KsCreatePin(MixerData->hDevice, PinConnect, DesiredAccess, PinHandle);
264
265 /* free create info */
266 MixerContext->Free(PinConnect);
267
268 if (Status == STATUS_SUCCESS)
269 return MM_STATUS_SUCCESS;
270 else
271 return MM_STATUS_UNSUCCESSFUL;
272 }
273
274 VOID
275 MMixerCheckFormat(
276 IN PKSDATARANGE_AUDIO DataRangeAudio,
277 IN LPWAVE_INFO WaveInfo,
278 IN ULONG bInput)
279 {
280 ULONG Index, SampleFrequency;
281 ULONG Result = 0;
282
283 for(Index = 0; Index < AUDIO_TEST_RANGE; Index++)
284 {
285 SampleFrequency = TestRange[Index].SampleRate;
286
287 if (DataRangeAudio->MinimumSampleFrequency <= SampleFrequency && DataRangeAudio->MaximumSampleFrequency >= SampleFrequency)
288 {
289 /* the audio adapter supports the sample frequency */
290 if (DataRangeAudio->MinimumBitsPerSample <= 8 && DataRangeAudio->MaximumBitsPerSample >= 8)
291 {
292 Result |= TestRange[Index].Bit8Mono;
293
294 if (DataRangeAudio->MaximumChannels > 1)
295 {
296 /* check if pin supports the sample rate in 8-Bit Stereo */
297 Result |= TestRange[Index].Bit8Stereo;
298 }
299 }
300
301 if (DataRangeAudio->MinimumBitsPerSample <= 16 && DataRangeAudio->MaximumBitsPerSample >= 16)
302 {
303 /* check if pin supports the sample rate in 16-Bit Mono */
304 Result |= TestRange[Index].Bit16Mono;
305
306
307 if (DataRangeAudio->MaximumChannels > 1)
308 {
309 /* check if pin supports the sample rate in 16-Bit Stereo */
310 Result |= TestRange[Index].Bit16Stereo;
311 }
312 }
313 }
314 }
315
316
317 if (bInput)
318 WaveInfo->u.InCaps.dwFormats = Result;
319 else
320 WaveInfo->u.OutCaps.dwFormats = Result;
321
322 DPRINT("Format %lx bInput %u\n", Result, bInput);
323 }
324
325 MIXER_STATUS
326 MMixerInitializeWaveInfo(
327 IN PMIXER_CONTEXT MixerContext,
328 IN PMIXER_LIST MixerList,
329 IN LPMIXER_DATA MixerData,
330 IN LPWSTR DeviceName,
331 IN ULONG bWaveIn,
332 IN ULONG PinId)
333 {
334 MIXER_STATUS Status;
335 PKSMULTIPLE_ITEM MultipleItem;
336 PKSDATARANGE_AUDIO DataRangeAudio;
337 LPWAVE_INFO WaveInfo;
338
339 WaveInfo = (LPWAVE_INFO)MixerContext->Alloc(sizeof(WAVE_INFO));
340 if (!WaveInfo)
341 return MM_STATUS_NO_MEMORY;
342
343 /* initialize wave info */
344 WaveInfo->DeviceId = MixerData->DeviceId;
345 WaveInfo->PinId = PinId;
346
347 /* FIXME determine manufacturer / product id */
348 if (bWaveIn)
349 {
350 WaveInfo->u.InCaps.wMid = MM_MICROSOFT;
351 WaveInfo->u.InCaps.wPid = MM_PID_UNMAPPED;
352 WaveInfo->u.InCaps.vDriverVersion = 1;
353 }
354 else
355 {
356 WaveInfo->u.OutCaps.wMid = MM_MICROSOFT;
357 WaveInfo->u.OutCaps.wPid = MM_PID_UNMAPPED;
358 WaveInfo->u.OutCaps.vDriverVersion = 1;
359 }
360
361 /* get audio pin data ranges */
362 Status = MMixerGetAudioPinDataRanges(MixerContext, MixerData->hDevice, PinId, &MultipleItem);
363 if (Status != MM_STATUS_SUCCESS)
364 {
365 /* failed to get audio pin data ranges */
366 MixerContext->Free(WaveInfo);
367 return MM_STATUS_UNSUCCESSFUL;
368 }
369
370 /* find an KSDATARANGE_AUDIO range */
371 Status = MMixerFindAudioDataRange(MultipleItem, &DataRangeAudio);
372 if (Status != MM_STATUS_SUCCESS)
373 {
374 /* failed to find audio pin data range */
375 MixerContext->Free(MultipleItem);
376 MixerContext->Free(WaveInfo);
377 return MM_STATUS_UNSUCCESSFUL;
378 }
379
380 /* store channel count */
381 if (bWaveIn)
382 {
383 WaveInfo->u.InCaps.wChannels = DataRangeAudio->MaximumChannels;
384 }
385 else
386 {
387 WaveInfo->u.OutCaps.wChannels = DataRangeAudio->MaximumChannels;
388 }
389
390 /* get all supported formats */
391 MMixerCheckFormat(DataRangeAudio, WaveInfo, bWaveIn);
392
393 /* free dataranges buffer */
394 MixerContext->Free(MultipleItem);
395
396
397 if (bWaveIn)
398 {
399 InsertTailList(&MixerList->WaveInList, &WaveInfo->Entry);
400 MixerList->WaveInListCount++;
401 }
402 else
403 {
404 InsertTailList(&MixerList->WaveOutList, &WaveInfo->Entry);
405 MixerList->WaveOutListCount++;
406 }
407
408 return MM_STATUS_SUCCESS;
409 }
410
411 MIXER_STATUS
412 MMixerOpenWave(
413 IN PMIXER_CONTEXT MixerContext,
414 IN ULONG DeviceIndex,
415 IN ULONG bWaveIn,
416 IN LPWAVEFORMATEX WaveFormat,
417 OUT PHANDLE PinHandle)
418 {
419 PMIXER_LIST MixerList;
420 MIXER_STATUS Status;
421 LPWAVE_INFO WaveInfo;
422 ACCESS_MASK DesiredAccess = 0;
423
424 // verify mixer context
425 Status = MMixerVerifyContext(MixerContext);
426
427 if (Status != MM_STATUS_SUCCESS)
428 {
429 // invalid context passed
430 return Status;
431 }
432
433 // grab mixer list
434 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
435
436 if (WaveFormat->wFormatTag != WAVE_FORMAT_PCM)
437 {
438 // not implemented
439 return MM_STATUS_NOT_IMPLEMENTED;
440 }
441
442 /* find destination wave */
443 Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, bWaveIn, &WaveInfo);
444 if (Status != MM_STATUS_SUCCESS)
445 {
446 /* failed to find wave info */
447 return MM_STATUS_INVALID_PARAMETER;
448 }
449
450 /* get desired access */
451 if (bWaveIn)
452 {
453 DesiredAccess |= GENERIC_READ;
454 }
455 else
456 {
457 DesiredAccess |= GENERIC_WRITE;
458 }
459
460 /* now try open the pin */
461 return MMixerOpenWavePin(MixerContext, MixerList, WaveInfo->DeviceId, WaveInfo->PinId, WaveFormat, DesiredAccess, PinHandle);
462 }
463
464 MIXER_STATUS
465 MMixerWaveInCapabilities(
466 IN PMIXER_CONTEXT MixerContext,
467 IN ULONG DeviceIndex,
468 OUT LPWAVEINCAPSW Caps)
469 {
470 PMIXER_LIST MixerList;
471 MIXER_STATUS Status;
472 LPWAVE_INFO WaveInfo;
473
474 // verify mixer context
475 Status = MMixerVerifyContext(MixerContext);
476
477 if (Status != MM_STATUS_SUCCESS)
478 {
479 // invalid context passed
480 return Status;
481 }
482
483 // grab mixer list
484 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
485
486 /* find destination wave */
487 Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, TRUE, &WaveInfo);
488 if (Status != MM_STATUS_SUCCESS)
489 {
490 /* failed to find wave info */
491 return MM_STATUS_UNSUCCESSFUL;
492 }
493
494 //copy capabilities
495 MixerContext->Copy(Caps, &WaveInfo->u.InCaps, sizeof(WAVEINCAPSW));
496
497 return MM_STATUS_SUCCESS;
498 }
499
500 MIXER_STATUS
501 MMixerWaveOutCapabilities(
502 IN PMIXER_CONTEXT MixerContext,
503 IN ULONG DeviceIndex,
504 OUT LPWAVEOUTCAPSW Caps)
505 {
506 PMIXER_LIST MixerList;
507 MIXER_STATUS Status;
508 LPWAVE_INFO WaveInfo;
509
510 // verify mixer context
511 Status = MMixerVerifyContext(MixerContext);
512
513 if (Status != MM_STATUS_SUCCESS)
514 {
515 // invalid context passed
516 return Status;
517 }
518
519 // grab mixer list
520 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
521
522 /* find destination wave */
523 Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, FALSE, &WaveInfo);
524 if (Status != MM_STATUS_SUCCESS)
525 {
526 /* failed to find wave info */
527 return MM_STATUS_UNSUCCESSFUL;
528 }
529
530 //copy capabilities
531 MixerContext->Copy(Caps, &WaveInfo->u.OutCaps, sizeof(WAVEOUTCAPSW));
532
533 return MM_STATUS_SUCCESS;
534 }
535
536 ULONG
537 MMixerGetWaveInCount(
538 IN PMIXER_CONTEXT MixerContext)
539 {
540 PMIXER_LIST MixerList;
541 MIXER_STATUS Status;
542
543 // verify mixer context
544 Status = MMixerVerifyContext(MixerContext);
545
546 if (Status != MM_STATUS_SUCCESS)
547 {
548 // invalid context passed
549 return 0;
550 }
551
552 // grab mixer list
553 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
554
555 return MixerList->WaveInListCount;
556 }
557
558 ULONG
559 MMixerGetWaveOutCount(
560 IN PMIXER_CONTEXT MixerContext)
561 {
562 PMIXER_LIST MixerList;
563 MIXER_STATUS Status;
564
565 // verify mixer context
566 Status = MMixerVerifyContext(MixerContext);
567
568 if (Status != MM_STATUS_SUCCESS)
569 {
570 // invalid context passed
571 return 0;
572 }
573
574 // grab mixer list
575 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
576
577 return MixerList->WaveOutListCount;
578 }