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