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