Revert the sync.
[reactos.git] / 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 PinId)
349 {
350 MIXER_STATUS Status;
351 PKSMULTIPLE_ITEM MultipleItem;
352 PKSDATARANGE_AUDIO DataRangeAudio;
353 LPWAVE_INFO WaveInfo;
354
355 WaveInfo = (LPWAVE_INFO)MixerContext->Alloc(sizeof(WAVE_INFO));
356 if (!WaveInfo)
357 return MM_STATUS_NO_MEMORY;
358
359 /* initialize wave info */
360 WaveInfo->DeviceId = MixerData->DeviceId;
361 WaveInfo->PinId = PinId;
362
363 /* FIXME determine manufacturer / product id */
364 if (bWaveIn)
365 {
366 WaveInfo->u.InCaps.wMid = MM_MICROSOFT;
367 WaveInfo->u.InCaps.wPid = MM_PID_UNMAPPED;
368 WaveInfo->u.InCaps.vDriverVersion = 1;
369 }
370 else
371 {
372 WaveInfo->u.OutCaps.wMid = MM_MICROSOFT;
373 WaveInfo->u.OutCaps.wPid = MM_PID_UNMAPPED;
374 WaveInfo->u.OutCaps.vDriverVersion = 1;
375 }
376
377 /* get audio pin data ranges */
378 Status = MMixerGetAudioPinDataRanges(MixerContext, MixerData->hDevice, PinId, &MultipleItem);
379 if (Status != MM_STATUS_SUCCESS)
380 {
381 /* failed to get audio pin data ranges */
382 MixerContext->Free(WaveInfo);
383 return MM_STATUS_UNSUCCESSFUL;
384 }
385
386 /* find an KSDATARANGE_AUDIO range */
387 Status = MMixerFindAudioDataRange(MultipleItem, &DataRangeAudio);
388 if (Status != MM_STATUS_SUCCESS)
389 {
390 /* failed to find audio pin data range */
391 MixerContext->Free(MultipleItem);
392 MixerContext->Free(WaveInfo);
393 return MM_STATUS_UNSUCCESSFUL;
394 }
395
396 /* store channel count */
397 if (bWaveIn)
398 {
399 WaveInfo->u.InCaps.wChannels = DataRangeAudio->MaximumChannels;
400 }
401 else
402 {
403 WaveInfo->u.OutCaps.wChannels = DataRangeAudio->MaximumChannels;
404 }
405
406 /* get all supported formats */
407 MMixerCheckFormat(DataRangeAudio, WaveInfo, bWaveIn);
408
409 /* free dataranges buffer */
410 MixerContext->Free(MultipleItem);
411
412
413 if (bWaveIn)
414 {
415 InsertTailList(&MixerList->WaveInList, &WaveInfo->Entry);
416 MixerList->WaveInListCount++;
417 }
418 else
419 {
420 InsertTailList(&MixerList->WaveOutList, &WaveInfo->Entry);
421 MixerList->WaveOutListCount++;
422 }
423
424 return MM_STATUS_SUCCESS;
425 }
426
427 MIXER_STATUS
428 MMixerOpenWave(
429 IN PMIXER_CONTEXT MixerContext,
430 IN ULONG DeviceIndex,
431 IN ULONG bWaveIn,
432 IN LPWAVEFORMATEX WaveFormat,
433 IN PIN_CREATE_CALLBACK CreateCallback,
434 IN PVOID Context,
435 OUT PHANDLE PinHandle)
436 {
437 PMIXER_LIST MixerList;
438 MIXER_STATUS Status;
439 LPWAVE_INFO WaveInfo;
440 ACCESS_MASK DesiredAccess = 0;
441
442 // verify mixer context
443 Status = MMixerVerifyContext(MixerContext);
444
445 if (Status != MM_STATUS_SUCCESS)
446 {
447 // invalid context passed
448 return Status;
449 }
450
451 // grab mixer list
452 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
453
454 if (WaveFormat->wFormatTag != WAVE_FORMAT_PCM)
455 {
456 // not implemented
457 return MM_STATUS_NOT_IMPLEMENTED;
458 }
459
460 /* find destination wave */
461 Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, bWaveIn, &WaveInfo);
462 if (Status != MM_STATUS_SUCCESS)
463 {
464 /* failed to find wave info */
465 return MM_STATUS_INVALID_PARAMETER;
466 }
467
468 /* get desired access */
469 if (bWaveIn)
470 {
471 DesiredAccess |= GENERIC_READ;
472 }
473 else
474 {
475 DesiredAccess |= GENERIC_WRITE;
476 }
477
478 /* now try open the pin */
479 return MMixerOpenWavePin(MixerContext, MixerList, WaveInfo->DeviceId, WaveInfo->PinId, WaveFormat, DesiredAccess, CreateCallback, Context, PinHandle);
480 }
481
482 MIXER_STATUS
483 MMixerWaveInCapabilities(
484 IN PMIXER_CONTEXT MixerContext,
485 IN ULONG DeviceIndex,
486 OUT LPWAVEINCAPSW Caps)
487 {
488 PMIXER_LIST MixerList;
489 MIXER_STATUS Status;
490 LPWAVE_INFO WaveInfo;
491
492 // verify mixer context
493 Status = MMixerVerifyContext(MixerContext);
494
495 if (Status != MM_STATUS_SUCCESS)
496 {
497 // invalid context passed
498 return Status;
499 }
500
501 // grab mixer list
502 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
503
504 /* find destination wave */
505 Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, TRUE, &WaveInfo);
506 if (Status != MM_STATUS_SUCCESS)
507 {
508 /* failed to find wave info */
509 return MM_STATUS_UNSUCCESSFUL;
510 }
511
512 //copy capabilities
513 MixerContext->Copy(Caps, &WaveInfo->u.InCaps, sizeof(WAVEINCAPSW));
514
515 return MM_STATUS_SUCCESS;
516 }
517
518 MIXER_STATUS
519 MMixerWaveOutCapabilities(
520 IN PMIXER_CONTEXT MixerContext,
521 IN ULONG DeviceIndex,
522 OUT LPWAVEOUTCAPSW Caps)
523 {
524 PMIXER_LIST MixerList;
525 MIXER_STATUS Status;
526 LPWAVE_INFO WaveInfo;
527
528 // verify mixer context
529 Status = MMixerVerifyContext(MixerContext);
530
531 if (Status != MM_STATUS_SUCCESS)
532 {
533 // invalid context passed
534 return Status;
535 }
536
537 // grab mixer list
538 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
539
540 /* find destination wave */
541 Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, FALSE, &WaveInfo);
542 if (Status != MM_STATUS_SUCCESS)
543 {
544 /* failed to find wave info */
545 return MM_STATUS_UNSUCCESSFUL;
546 }
547
548 //copy capabilities
549 MixerContext->Copy(Caps, &WaveInfo->u.OutCaps, sizeof(WAVEOUTCAPSW));
550
551 return MM_STATUS_SUCCESS;
552 }
553
554 ULONG
555 MMixerGetWaveInCount(
556 IN PMIXER_CONTEXT MixerContext)
557 {
558 PMIXER_LIST MixerList;
559 MIXER_STATUS Status;
560
561 // verify mixer context
562 Status = MMixerVerifyContext(MixerContext);
563
564 if (Status != MM_STATUS_SUCCESS)
565 {
566 // invalid context passed
567 return 0;
568 }
569
570 // grab mixer list
571 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
572
573 return MixerList->WaveInListCount;
574 }
575
576 ULONG
577 MMixerGetWaveOutCount(
578 IN PMIXER_CONTEXT MixerContext)
579 {
580 PMIXER_LIST MixerList;
581 MIXER_STATUS Status;
582
583 // verify mixer context
584 Status = MMixerVerifyContext(MixerContext);
585
586 if (Status != MM_STATUS_SUCCESS)
587 {
588 // invalid context passed
589 return 0;
590 }
591
592 // grab mixer list
593 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
594
595 return MixerList->WaveOutListCount;
596 }
597
598 MIXER_STATUS
599 MMixerSetWaveStatus(
600 IN PMIXER_CONTEXT MixerContext,
601 IN HANDLE PinHandle,
602 IN KSSTATE State)
603 {
604 KSPROPERTY Property;
605 ULONG Length;
606
607 /* setup property request */
608 Property.Set = KSPROPSETID_Connection;
609 Property.Id = KSPROPERTY_CONNECTION_STATE;
610 Property.Flags = KSPROPERTY_TYPE_SET;
611
612 return MixerContext->Control(PinHandle, IOCTL_KS_PROPERTY, &Property, sizeof(KSPROPERTY), &State, sizeof(KSSTATE), &Length);
613 }
614
615 MIXER_STATUS
616 MMixerGetWaveDevicePath(
617 IN PMIXER_CONTEXT MixerContext,
618 IN ULONG bWaveIn,
619 IN ULONG DeviceId,
620 OUT LPWSTR * DevicePath)
621 {
622 PMIXER_LIST MixerList;
623 LPMIXER_DATA MixerData;
624 LPWAVE_INFO WaveInfo;
625 ULONG Length;
626 MIXER_STATUS Status;
627
628 // verify mixer context
629 Status = MMixerVerifyContext(MixerContext);
630
631 if (Status != MM_STATUS_SUCCESS)
632 {
633 // invalid context passed
634 return Status;
635 }
636
637 // grab mixer list
638 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
639
640 /* find destination wave */
641 Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceId, bWaveIn, &WaveInfo);
642 if (Status != MM_STATUS_SUCCESS)
643 {
644 /* failed to find wave info */
645 return MM_STATUS_INVALID_PARAMETER;
646 }
647
648 /* get associated device id */
649 MixerData = MMixerGetDataByDeviceId(MixerList, WaveInfo->DeviceId);
650 if (!MixerData)
651 return MM_STATUS_INVALID_PARAMETER;
652
653 /* calculate length */
654 Length = wcslen(MixerData->DeviceName)+1;
655
656 /* allocate destination buffer */
657 *DevicePath = MixerContext->Alloc(Length * sizeof(WCHAR));
658
659 if (!*DevicePath)
660 {
661 /* no memory */
662 return MM_STATUS_NO_MEMORY;
663 }
664
665 /* copy device path */
666 MixerContext->Copy(*DevicePath, MixerData->DeviceName, Length * sizeof(WCHAR));
667
668 /* done */
669 return MM_STATUS_SUCCESS;
670 }
671