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