xref: /reactos/sdk/lib/drivers/sound/mmixer/mixer.c (revision 60b0afc3)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            lib/drivers/sound/mmixer/mmixer.c
5  * PURPOSE:         Mixer Handling Functions
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "precomp.h"
10 
11 // #define NDEBUG
12 #include <debug.h>
13 
14 ULONG
MMixerGetCount(IN PMIXER_CONTEXT MixerContext)15 MMixerGetCount(
16     IN PMIXER_CONTEXT MixerContext)
17 {
18     PMIXER_LIST MixerList;
19     MIXER_STATUS Status;
20 
21     /* verify mixer context */
22     Status = MMixerVerifyContext(MixerContext);
23 
24     if (Status != MM_STATUS_SUCCESS)
25     {
26         /* invalid context passed */
27         return Status;
28     }
29 
30     /* grab mixer list */
31     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
32 
33     // return number of mixers
34     return MixerList->MixerListCount;
35 }
36 
37 MIXER_STATUS
MMixerGetCapabilities(IN PMIXER_CONTEXT MixerContext,IN ULONG MixerIndex,OUT LPMIXERCAPSW MixerCaps)38 MMixerGetCapabilities(
39     IN PMIXER_CONTEXT MixerContext,
40     IN ULONG MixerIndex,
41     OUT LPMIXERCAPSW MixerCaps)
42 {
43     MIXER_STATUS Status;
44     LPMIXER_INFO MixerInfo;
45 
46     /* verify mixer context */
47     Status = MMixerVerifyContext(MixerContext);
48 
49     if (Status != MM_STATUS_SUCCESS)
50     {
51         /* invalid context passed */
52         return Status;
53     }
54 
55     /* get mixer info */
56     MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, MixerIndex);
57 
58     if (!MixerInfo)
59     {
60         // invalid device index
61         return MM_STATUS_INVALID_PARAMETER;
62     }
63 
64     MixerCaps->wMid = MixerInfo->MixCaps.wMid;
65     MixerCaps->wPid = MixerInfo->MixCaps.wPid;
66     MixerCaps->vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
67     MixerCaps->fdwSupport = MixerInfo->MixCaps.fdwSupport;
68     MixerCaps->cDestinations = MixerInfo->MixCaps.cDestinations;
69 
70     ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == 0);
71     wcscpy(MixerCaps->szPname, MixerInfo->MixCaps.szPname);
72 
73     return MM_STATUS_SUCCESS;
74 }
75 
76 MIXER_STATUS
MMixerOpen(IN PMIXER_CONTEXT MixerContext,IN ULONG MixerId,IN PVOID MixerEventContext,IN PMIXER_EVENT MixerEventRoutine,OUT PHANDLE MixerHandle)77 MMixerOpen(
78     IN PMIXER_CONTEXT MixerContext,
79     IN ULONG MixerId,
80     IN PVOID MixerEventContext,
81     IN PMIXER_EVENT MixerEventRoutine,
82     OUT PHANDLE MixerHandle)
83 {
84     MIXER_STATUS Status;
85     LPMIXER_INFO MixerInfo;
86 
87     /* verify mixer context */
88     Status = MMixerVerifyContext(MixerContext);
89 
90     if (Status != MM_STATUS_SUCCESS)
91     {
92         /* invalid context passed */
93         DPRINT1("invalid context\n");
94         return Status;
95     }
96 
97     /* get mixer info */
98     MixerInfo = (LPMIXER_INFO)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
99     if (!MixerInfo)
100     {
101         /* invalid mixer id */
102         DPRINT1("invalid mixer id %lu\n", MixerId);
103         return MM_STATUS_INVALID_PARAMETER;
104     }
105 
106     /* add the event */
107     Status = MMixerAddEvent(MixerContext, MixerInfo, MixerEventContext, MixerEventRoutine);
108 
109     /* store result */
110     *MixerHandle = (HANDLE)MixerInfo;
111     return MM_STATUS_SUCCESS;
112 }
113 
114 MIXER_STATUS
MMixerClose(IN PMIXER_CONTEXT MixerContext,IN ULONG MixerId,IN PVOID MixerEventContext,IN PMIXER_EVENT MixerEventRoutine)115 MMixerClose(
116     IN PMIXER_CONTEXT MixerContext,
117     IN ULONG MixerId,
118     IN PVOID MixerEventContext,
119     IN PMIXER_EVENT MixerEventRoutine)
120 {
121     MIXER_STATUS Status;
122     LPMIXER_INFO MixerInfo;
123 
124     /* verify mixer context */
125     Status = MMixerVerifyContext(MixerContext);
126 
127     if (Status != MM_STATUS_SUCCESS)
128     {
129         /* invalid context passed */
130         DPRINT1("invalid context\n");
131         return Status;
132     }
133 
134     /* get mixer info */
135     MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, MixerId);
136     if (!MixerInfo)
137     {
138         /* invalid mixer id */
139         DPRINT1("invalid mixer id %lu\n", MixerId);
140         return MM_STATUS_INVALID_PARAMETER;
141     }
142 
143     /* remove event from list */
144     return MMixerRemoveEvent(MixerContext, MixerInfo, MixerEventContext, MixerEventRoutine);
145 }
146 
147 MIXER_STATUS
MMixerGetLineInfo(IN PMIXER_CONTEXT MixerContext,IN HANDLE MixerHandle,IN ULONG MixerId,IN ULONG Flags,OUT LPMIXERLINEW MixerLine)148 MMixerGetLineInfo(
149     IN PMIXER_CONTEXT MixerContext,
150     IN HANDLE MixerHandle,
151     IN ULONG MixerId,
152     IN ULONG Flags,
153     OUT LPMIXERLINEW MixerLine)
154 {
155     MIXER_STATUS Status;
156     LPMIXER_INFO MixerInfo;
157     LPMIXERLINE_EXT MixerLineSrc;
158     ULONG DestinationLineID;
159 
160     /* verify mixer context */
161     Status = MMixerVerifyContext(MixerContext);
162 
163     if (Status != MM_STATUS_SUCCESS)
164     {
165         /* invalid context passed */
166         return Status;
167     }
168     if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
169     {
170         /* caller passed mixer id */
171         MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
172 
173         if (!MixerHandle)
174         {
175             /* invalid parameter */
176             return MM_STATUS_INVALID_PARAMETER;
177         }
178     }
179 
180     if (MixerLine->cbStruct != sizeof(MIXERLINEW))
181     {
182         DPRINT1("MixerLine Expected %lu but got %lu\n", sizeof(MIXERLINEW), MixerLine->cbStruct);
183         return MM_STATUS_INVALID_PARAMETER;
184     }
185 
186     /* clear hmixer from flags */
187     Flags &=~MIXER_OBJECTF_HMIXER;
188 
189     DPRINT("MMixerGetLineInfo MixerId %lu Flags %lu\n", MixerId, Flags);
190 
191     if (Flags == MIXER_GETLINEINFOF_DESTINATION)
192     {
193         /* cast to mixer info */
194         MixerInfo = (LPMIXER_INFO)MixerHandle;
195 
196         /* calculate destination line id */
197         DestinationLineID = (MixerLine->dwDestination + DESTINATION_LINE);
198 
199         /* get destination line */
200         MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
201 
202         if (MixerLineSrc == NULL)
203         {
204             DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination);
205             return MM_STATUS_UNSUCCESSFUL;
206         }
207         /* copy mixer line */
208         MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
209 
210         /* make sure it is null terminated */
211         MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
212         MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
213         MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
214 
215         /* done */
216         return MM_STATUS_SUCCESS;
217     }
218     else if (Flags == MIXER_GETLINEINFOF_SOURCE)
219     {
220         /* cast to mixer info */
221         MixerInfo = (LPMIXER_INFO)MixerHandle;
222 
223         /* calculate destination line id */
224         DestinationLineID = (MixerLine->dwDestination + DESTINATION_LINE);
225 
226         /* get destination line */
227         MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
228 
229         if (MixerLineSrc == NULL)
230         {
231             DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination);
232             return MM_STATUS_UNSUCCESSFUL;
233         }
234 
235         /* check if dwSource is out of bounds */
236         if (MixerLine->dwSource >= MixerLineSrc->Line.cConnections)
237         {
238             DPRINT1("MixerCaps Name %S MixerLineName %S Connections %lu dwSource %lu not found\n", MixerInfo->MixCaps.szPname, MixerLineSrc->Line.szName, MixerLineSrc->Line.cConnections, MixerLine->dwSource);
239             return MM_STATUS_UNSUCCESSFUL;
240         }
241 
242         /* calculate destination line id */
243         DestinationLineID = (MixerLine->dwSource * SOURCE_LINE) + MixerLine->dwDestination;
244 
245         DPRINT("MixerName %S cDestinations %lu MixerLineName %S cConnections %lu dwSource %lu dwDestination %lu ID %lx\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations,
246                                                                                                                             MixerLineSrc->Line.szName, MixerLineSrc->Line.cConnections,
247                                                                                                                             MixerLine->dwSource, MixerLine->dwDestination,
248                                                                                                                             DestinationLineID);
249         /* get target destination line id */
250         MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
251 
252         /* sanity check */
253         ASSERT(MixerLineSrc);
254 
255         DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
256 
257         /* copy mixer line */
258         MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
259 
260         /* make sure it is null terminated */
261         MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
262         MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
263         MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
264 
265         /* done */
266         return MM_STATUS_SUCCESS;
267     }
268     else if (Flags == MIXER_GETLINEINFOF_LINEID)
269     {
270         /* cast to mixer info */
271         MixerInfo = (LPMIXER_INFO)MixerHandle;
272 
273         /* try to find line */
274         MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLine->dwLineID);
275         if (!MixerLineSrc)
276         {
277             /* invalid parameter */
278             DPRINT1("MMixerGetLineInfo: MixerName %S Line not found 0x%lx\n", MixerInfo->MixCaps.szPname, MixerLine->dwLineID);
279             return MM_STATUS_INVALID_PARAMETER;
280         }
281 
282         DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
283 
284         /* copy mixer line*/
285         MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
286 
287         /* make sure it is null terminated */
288         MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
289         MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
290         MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
291 
292         return MM_STATUS_SUCCESS;
293     }
294     else if (Flags == MIXER_GETLINEINFOF_COMPONENTTYPE)
295     {
296         /* cast to mixer info */
297         MixerInfo = (LPMIXER_INFO)MixerHandle;
298 
299         /* find mixer line by component type */
300         MixerLineSrc = MMixerGetSourceMixerLineByComponentType(MixerInfo, MixerLine->dwComponentType);
301         if (!MixerLineSrc)
302         {
303             DPRINT1("Failed to find component type %x\n", MixerLine->dwComponentType);
304             return MM_STATUS_UNSUCCESSFUL;
305         }
306 
307         /* copy mixer line */
308         MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
309 
310         /* make sure it is null terminated */
311         MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
312         MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
313         MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
314 
315         /* done */
316         return MM_STATUS_SUCCESS;
317     }
318     else if (Flags == MIXER_GETLINEINFOF_TARGETTYPE)
319     {
320         DPRINT1("MIXER_GETLINEINFOF_TARGETTYPE handling is unimplemented\n");
321     }
322     else
323     {
324         DPRINT1("Unknown Flags %lx handling is unimplemented\n", Flags);
325     }
326 
327     return MM_STATUS_NOT_IMPLEMENTED;
328 }
329 
330 MIXER_STATUS
MMixerGetLineControls(IN PMIXER_CONTEXT MixerContext,IN HANDLE MixerHandle,IN ULONG MixerId,IN ULONG Flags,OUT LPMIXERLINECONTROLSW MixerLineControls)331 MMixerGetLineControls(
332     IN PMIXER_CONTEXT MixerContext,
333     IN HANDLE MixerHandle,
334     IN ULONG MixerId,
335     IN ULONG Flags,
336     OUT LPMIXERLINECONTROLSW MixerLineControls)
337 {
338     LPMIXER_INFO MixerInfo;
339     LPMIXERLINE_EXT MixerLineSrc;
340     LPMIXERCONTROL_EXT MixerControl;
341     MIXER_STATUS Status;
342     PLIST_ENTRY Entry;
343     ULONG Index;
344 
345     /* verify mixer context */
346     Status = MMixerVerifyContext(MixerContext);
347 
348     if (Status != MM_STATUS_SUCCESS)
349     {
350         /* invalid context passed */
351         return Status;
352     }
353 
354     if (MixerLineControls->cbStruct != sizeof(MIXERLINECONTROLSW))
355     {
356         DPRINT1("Invalid MixerLineControls cbStruct passed %lu expected %lu\n", MixerLineControls->cbStruct, sizeof(MIXERLINECONTROLSW));
357         /* invalid parameter */
358         return MM_STATUS_INVALID_PARAMETER;
359     }
360 
361     if (MixerLineControls->cbmxctrl != sizeof(MIXERCONTROLW))
362     {
363         DPRINT1("Invalid MixerLineControls cbmxctrl passed %lu expected %lu\n", MixerLineControls->cbmxctrl, sizeof(MIXERCONTROLW));
364         /* invalid parameter */
365         return MM_STATUS_INVALID_PARAMETER;
366     }
367 
368     if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
369     {
370         /* caller passed mixer id */
371         MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
372 
373         if (!MixerHandle)
374         {
375             /* invalid parameter */
376             return MM_STATUS_INVALID_PARAMETER;
377         }
378     }
379 
380     Flags &= ~MIXER_OBJECTF_HMIXER;
381 
382     DPRINT("MMixerGetLineControls MixerId %lu Flags %lu\n", MixerId, Flags);
383 
384     if (Flags == MIXER_GETLINECONTROLSF_ALL)
385     {
386         /* cast to mixer info */
387         MixerInfo = (LPMIXER_INFO)MixerHandle;
388 
389         /* get mixer line */
390         MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
391 
392         if (!MixerLineSrc)
393         {
394             /* invalid line id */
395             DPRINT("MMixerGetLineControls Line not found %lx\n", MixerLineControls->dwLineID);
396             return MM_STATUS_INVALID_PARAMETER;
397         }
398 
399         if (MixerLineSrc->Line.cControls != MixerLineControls->cControls)
400         {
401             /* invalid parameter */
402             DPRINT1("Invalid control count %lu expected %lu\n", MixerLineControls->cControls, MixerLineSrc->Line.cControls);
403             return MM_STATUS_INVALID_PARAMETER;
404         }
405 
406         /* copy line control(s) */
407         Entry = MixerLineSrc->ControlsList.Flink;
408         Index = 0;
409         while(Entry != &MixerLineSrc->ControlsList)
410         {
411             /* get mixer control */
412             MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(Entry, MIXERCONTROL_EXT, Entry);
413 
414             /* copy mixer control */
415             MixerContext->Copy(&MixerLineControls->pamxctrl[Index], &MixerControl->Control, sizeof(MIXERCONTROLW));
416 
417             /* move to next */
418             Entry = Entry->Flink;
419 
420             /* increment mixer control offset */
421             Index++;
422         }
423         return MM_STATUS_SUCCESS;
424     }
425     else if (Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
426     {
427         /* cast to mixer info */
428         MixerInfo = (LPMIXER_INFO)MixerHandle;
429 
430         /* get mixer line */
431         MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
432 
433         if (!MixerLineSrc)
434         {
435             /* invalid line id */
436             DPRINT1("MMixerGetLineControls Line not found %lx\n", MixerLineControls->dwLineID);
437             return MM_STATUS_INVALID_PARAMETER;
438         }
439 
440         /* sanity checks */
441         ASSERT(MixerLineControls->cControls == 1);
442         ASSERT(MixerLineControls->cbmxctrl == sizeof(MIXERCONTROLW));
443         ASSERT(MixerLineControls->pamxctrl != NULL);
444 
445         Entry = MixerLineSrc->ControlsList.Flink;
446         while(Entry != &MixerLineSrc->ControlsList)
447         {
448             MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(Entry, MIXERCONTROL_EXT, Entry);
449             if (MixerLineControls->dwControlType == MixerControl->Control.dwControlType)
450             {
451                 /* found a control with that type */
452                 MixerContext->Copy(MixerLineControls->pamxctrl, &MixerControl->Control, sizeof(MIXERCONTROLW));
453                 return MM_STATUS_SUCCESS;
454             }
455 
456             /* move to next entry */
457             Entry = Entry->Flink;
458          }
459 
460          DPRINT("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x cControls %u \n", MixerLineControls->dwControlType, MixerLineControls->dwLineID, MixerLineSrc->Line.cControls);
461          return MM_STATUS_UNSUCCESSFUL;
462     }
463     else if (Flags == MIXER_GETLINECONTROLSF_ONEBYID)
464     {
465         /* cast to mixer info */
466         MixerInfo = (LPMIXER_INFO)MixerHandle;
467 
468         Status = MMixerGetMixerControlById(MixerInfo, MixerLineControls->dwControlID, NULL, &MixerControl, NULL);
469 
470         if (Status != MM_STATUS_SUCCESS)
471         {
472             /* invalid parameter */
473             DPRINT("MMixerGetLineControls ControlID not found %lx\n", MixerLineControls->dwLineID);
474             return MM_STATUS_INVALID_PARAMETER;
475         }
476 
477         ASSERT(MixerLineControls->cControls == 1);
478         ASSERT(MixerLineControls->cbmxctrl == sizeof(MIXERCONTROLW));
479         ASSERT(MixerLineControls->pamxctrl != NULL);
480 
481        DPRINT("MMixerGetLineControls ControlID %lx ControlType %lx Name %S\n", MixerControl->Control.dwControlID, MixerControl->Control.dwControlType, MixerControl->Control.szName);
482 
483         /* copy the controls */
484         MixerContext->Copy(MixerLineControls->pamxctrl, &MixerControl->Control, sizeof(MIXERCONTROLW));
485         MixerLineControls->pamxctrl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
486         MixerLineControls->pamxctrl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
487 
488         return MM_STATUS_SUCCESS;
489     }
490     UNIMPLEMENTED;
491     return MM_STATUS_NOT_IMPLEMENTED;
492 }
493 
494 MIXER_STATUS
MMixerSetControlDetails(IN PMIXER_CONTEXT MixerContext,IN HANDLE MixerHandle,IN ULONG MixerId,IN ULONG Flags,OUT LPMIXERCONTROLDETAILS MixerControlDetails)495 MMixerSetControlDetails(
496     IN PMIXER_CONTEXT MixerContext,
497     IN HANDLE MixerHandle,
498     IN ULONG MixerId,
499     IN ULONG Flags,
500     OUT LPMIXERCONTROLDETAILS MixerControlDetails)
501 {
502     MIXER_STATUS Status;
503     ULONG NodeId;
504     LPMIXER_INFO MixerInfo;
505     LPMIXERLINE_EXT MixerLine;
506     LPMIXERCONTROL_EXT MixerControl;
507 
508     /* verify mixer context */
509     Status = MMixerVerifyContext(MixerContext);
510 
511     if (Status != MM_STATUS_SUCCESS)
512     {
513         /* invalid context passed */
514         DPRINT1("invalid context\n");
515         return Status;
516     }
517 
518     if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
519     {
520         /* caller passed mixer id */
521         MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
522 
523         if (!MixerHandle)
524         {
525             /* invalid parameter */
526             DPRINT1("invalid handle\n");
527             return MM_STATUS_INVALID_PARAMETER;
528         }
529     }
530 
531     /* get mixer info */
532     MixerInfo = (LPMIXER_INFO)MixerHandle;
533 
534     /* get mixer control */
535      Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);
536 
537     /* check for success */
538     if (Status != MM_STATUS_SUCCESS)
539     {
540         /* failed to find control id */
541         DPRINT1("invalid control id %lu\n", MixerControlDetails->dwControlID);
542         return MM_STATUS_INVALID_PARAMETER;
543     }
544 
545     DPRINT("MMixerSetControlDetails ControlType %lx MixerControlName %S MixerLineName %S NodeID %lu\n", MixerControl->Control.dwControlType, MixerControl->Control.szName, MixerLine->Line.szName, NodeId);
546     switch(MixerControl->Control.dwControlType)
547     {
548         case MIXERCONTROL_CONTROLTYPE_MUTE:
549             Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo, MixerControl, MixerLine->Line.dwLineID, MixerControlDetails, TRUE);
550             break;
551         case MIXERCONTROL_CONTROLTYPE_VOLUME:
552             Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo, NodeId, TRUE, MixerControl, MixerControlDetails, MixerLine);
553             break;
554         case MIXERCONTROL_CONTROLTYPE_MUX:
555             Status = MMixerSetGetMuxControlDetails(MixerContext, MixerInfo, NodeId, TRUE, Flags, MixerControl, MixerControlDetails, MixerLine);
556             break;
557         default:
558             Status = MM_STATUS_NOT_IMPLEMENTED;
559     }
560 
561     return Status;
562 }
563 
564 MIXER_STATUS
MMixerGetControlDetails(IN PMIXER_CONTEXT MixerContext,IN HANDLE MixerHandle,IN ULONG MixerId,IN ULONG Flags,OUT LPMIXERCONTROLDETAILS MixerControlDetails)565 MMixerGetControlDetails(
566     IN PMIXER_CONTEXT MixerContext,
567     IN HANDLE MixerHandle,
568     IN ULONG MixerId,
569     IN ULONG Flags,
570     OUT LPMIXERCONTROLDETAILS MixerControlDetails)
571 {
572     MIXER_STATUS Status;
573     ULONG NodeId;
574     LPMIXER_INFO MixerInfo;
575     LPMIXERLINE_EXT MixerLine;
576     LPMIXERCONTROL_EXT MixerControl;
577 
578     /* verify mixer context */
579     Status = MMixerVerifyContext(MixerContext);
580 
581     if (Status != MM_STATUS_SUCCESS)
582     {
583         /* invalid context passed */
584         return Status;
585     }
586 
587     if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
588     {
589         /* caller passed mixer id */
590         MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
591 
592         if (!MixerHandle)
593         {
594             /* invalid parameter */
595             return MM_STATUS_INVALID_PARAMETER;
596         }
597     }
598 
599     /* get mixer info */
600     MixerInfo = (LPMIXER_INFO)MixerHandle;
601 
602     /* get mixer control */
603      Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);
604 
605     /* check for success */
606     if (Status != MM_STATUS_SUCCESS)
607     {
608         /* failed to find control id */
609         return MM_STATUS_INVALID_PARAMETER;
610     }
611 
612     switch(MixerControl->Control.dwControlType)
613     {
614         case MIXERCONTROL_CONTROLTYPE_MUTE:
615             Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo, MixerControl, MixerLine->Line.dwLineID, MixerControlDetails, FALSE);
616             break;
617         case MIXERCONTROL_CONTROLTYPE_VOLUME:
618             Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo, NodeId, FALSE, MixerControl, MixerControlDetails, MixerLine);
619             break;
620         case MIXERCONTROL_CONTROLTYPE_ONOFF:
621             DPRINT1("Not Implemented MIXERCONTROL_CONTROLTYPE_ONOFF\n");
622             break;
623         case MIXERCONTROL_CONTROLTYPE_MUX:
624             Status = MMixerSetGetMuxControlDetails(MixerContext, MixerInfo, NodeId, FALSE, Flags, MixerControl, MixerControlDetails, MixerLine);
625             break;
626 
627         default:
628             Status = MM_STATUS_NOT_IMPLEMENTED;
629             DPRINT1("ControlType %lx not implemented\n", MixerControl->Control.dwControlType);
630     }
631 
632     return Status;
633 }
634 
635 VOID
MMixerPrintMixerLineControls(IN LPMIXERLINE_EXT MixerLine)636 MMixerPrintMixerLineControls(
637     IN LPMIXERLINE_EXT MixerLine)
638 {
639     PLIST_ENTRY Entry;
640     LPMIXERCONTROL_EXT MixerControl;
641     ULONG Index = 0;
642 
643     Entry = MixerLine->ControlsList.Flink;
644     while(Entry != &MixerLine->ControlsList)
645     {
646         MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(Entry, MIXERCONTROL_EXT, Entry);
647 
648         DPRINT1("\n");
649         DPRINT1("Control Index: %lu\n", Index);
650         DPRINT("\n");
651         DPRINT1("cbStruct %u\n", MixerControl->Control.cbStruct);
652         DPRINT1("dwControlID %lu\n", MixerControl->Control.dwControlID);
653         DPRINT1("dwControlType %lx\n", MixerControl->Control.dwControlType);
654         DPRINT1("fdwControl %lu\n", MixerControl->Control.fdwControl);
655         DPRINT1("cMultipleItems %lu\n", MixerControl->Control.cMultipleItems);
656         DPRINT1("szShortName %S\n", MixerControl->Control.szShortName);
657         DPRINT1("szName %S\n", MixerControl->Control.szName);
658         DPRINT1("Bounds.dwMinimum %lu\n", MixerControl->Control.Bounds.dwMinimum);
659         DPRINT1("Bounds.dwMaximum %lu\n", MixerControl->Control.Bounds.dwMaximum);
660 
661         DPRINT1("Metrics.Reserved[0] %lu\n", MixerControl->Control.Metrics.dwReserved[0]);
662         DPRINT1("Metrics.Reserved[1] %lu\n", MixerControl->Control.Metrics.dwReserved[1]);
663         DPRINT1("Metrics.Reserved[2] %lu\n", MixerControl->Control.Metrics.dwReserved[2]);
664         DPRINT1("Metrics.Reserved[3] %lu\n", MixerControl->Control.Metrics.dwReserved[3]);
665         DPRINT1("Metrics.Reserved[4] %lu\n", MixerControl->Control.Metrics.dwReserved[4]);
666         DPRINT1("Metrics.Reserved[5] %lu\n", MixerControl->Control.Metrics.dwReserved[5]);
667 
668         Entry = Entry->Flink;
669         Index++;
670     }
671 }
672 
673 VOID
MMixerPrintMixers(IN PMIXER_CONTEXT MixerContext,IN PMIXER_LIST MixerList)674 MMixerPrintMixers(
675     IN PMIXER_CONTEXT MixerContext,
676     IN PMIXER_LIST MixerList)
677 {
678     ULONG Index, SubIndex, DestinationLineID, SrcIndex;
679     LPMIXER_INFO MixerInfo;
680     LPMIXERLINE_EXT DstMixerLine, SrcMixerLine;
681 
682     DPRINT1("MixerList %p\n", MixerList);
683     DPRINT1("MidiInCount %lu\n", MixerList->MidiInListCount);
684     DPRINT1("MidiOutCount %lu\n", MixerList->MidiOutListCount);
685     DPRINT1("WaveInCount %lu\n", MixerList->WaveInListCount);
686     DPRINT1("WaveOutCount %lu\n", MixerList->WaveOutListCount);
687     DPRINT1("MixerCount %p\n", MixerList->MixerListCount);
688 
689     for(Index = 0; Index < MixerList->MixerListCount; Index++)
690     {
691         /* get mixer info */
692         MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, Index);
693 
694         ASSERT(MixerInfo);
695         DPRINT1("\n");
696         DPRINT1("Name :%S\n", MixerInfo->MixCaps.szPname);
697         DPRINT1("cDestinations: %lu\n", MixerInfo->MixCaps.cDestinations);
698         DPRINT1("fdwSupport %lu\n", MixerInfo->MixCaps.fdwSupport);
699         DPRINT1("vDriverVersion %lx\n", MixerInfo->MixCaps.vDriverVersion);
700         DPRINT1("wMid %lx\n", MixerInfo->MixCaps.wMid);
701         DPRINT1("wPid %lx\n", MixerInfo->MixCaps.wPid);
702 
703         for(SubIndex = 0; SubIndex < MixerInfo->MixCaps.cDestinations; SubIndex++)
704         {
705             /* calculate destination line id */
706             DestinationLineID = (SubIndex + DESTINATION_LINE);
707 
708             /* get destination line */
709             DstMixerLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
710             DPRINT1("//----------------------------------------------------------------------------------------------\n");
711             DPRINT1("\n");
712             DPRINT1("Destination Index %lu\n", SubIndex);
713             DPRINT1("\n");
714             DPRINT1("cChannels %lu\n", DstMixerLine->Line.cChannels);
715             DPRINT1("cConnections %lu\n", DstMixerLine->Line.cConnections);
716             DPRINT1("cControls %lu\n", DstMixerLine->Line.cControls);
717             DPRINT1("dwComponentType %lx\n", DstMixerLine->Line.dwComponentType);
718             DPRINT1("dwDestination %lu\n", DstMixerLine->Line.dwDestination);
719             DPRINT1("dwLineID %lx\n", DstMixerLine->Line.dwLineID);
720             DPRINT1("dwSource %lx\n", DstMixerLine->Line.dwSource);
721             DPRINT1("dwUser %lu\n", DstMixerLine->Line.dwUser);
722             DPRINT1("fdwLine %lu\n", DstMixerLine->Line.fdwLine);
723             DPRINT1("szName %S\n", DstMixerLine->Line.szName);
724             DPRINT1("szShortName %S\n", DstMixerLine->Line.szShortName);
725             DPRINT1("Target.dwDeviceId %lu\n", DstMixerLine->Line.Target.dwDeviceID);
726             DPRINT1("Target.dwType %lu\n", DstMixerLine->Line.Target.dwType);
727             DPRINT1("Target.szName %S\n", DstMixerLine->Line.Target.szPname);
728             DPRINT1("Target.vDriverVersion %lx\n", DstMixerLine->Line.Target.vDriverVersion);
729             DPRINT1("Target.wMid %lx\n", DstMixerLine->Line.Target.wMid );
730             DPRINT1("Target.wPid %lx\n", DstMixerLine->Line.Target.wPid);
731             MMixerPrintMixerLineControls(DstMixerLine);
732 
733             for(SrcIndex = 0; SrcIndex < DstMixerLine->Line.cConnections; SrcIndex++)
734             {
735                 /* calculate destination line id */
736                 DestinationLineID = (SOURCE_LINE * SrcIndex) + SubIndex;
737 
738                 /* get source line */
739                 SrcMixerLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
740                 DPRINT1("//==============================================================================================\n");
741                 DPRINT1("\n");
742                 DPRINT1("SrcLineIndex : %lu\n", SrcIndex);
743                 DPRINT1("\n");
744                 DPRINT1("cChannels %lu\n", SrcMixerLine->Line.cChannels);
745                 DPRINT1("cConnections %lu\n", SrcMixerLine->Line.cConnections);
746                 DPRINT1("cControls %lu\n", SrcMixerLine->Line.cControls);
747                 DPRINT1("dwComponentType %lx\n", SrcMixerLine->Line.dwComponentType);
748                 DPRINT1("dwDestination %lu\n", SrcMixerLine->Line.dwDestination);
749                 DPRINT1("dwLineID %lx\n", SrcMixerLine->Line.dwLineID);
750                 DPRINT1("dwSource %lx\n", SrcMixerLine->Line.dwSource);
751                 DPRINT1("dwUser %lu\n", SrcMixerLine->Line.dwUser);
752                 DPRINT1("fdwLine %lu\n", SrcMixerLine->Line.fdwLine);
753                 DPRINT1("szName %S\n", SrcMixerLine->Line.szName);
754                 DPRINT1("szShortName %S\n", SrcMixerLine->Line.szShortName);
755                 DPRINT1("Target.dwDeviceId %lu\n", SrcMixerLine->Line.Target.dwDeviceID);
756                 DPRINT1("Target.dwType %lu\n", SrcMixerLine->Line.Target.dwType);
757                 DPRINT1("Target.szName %S\n", SrcMixerLine->Line.Target.szPname);
758                 DPRINT1("Target.vDriverVersion %lx\n", SrcMixerLine->Line.Target.vDriverVersion);
759                 DPRINT1("Target.wMid %lx\n", SrcMixerLine->Line.Target.wMid );
760                 DPRINT1("Target.wPid %lx\n", SrcMixerLine->Line.Target.wPid);
761                 MMixerPrintMixerLineControls(SrcMixerLine);
762             }
763         }
764     }
765 }
766 
767 MIXER_STATUS
MMixerInitialize(IN PMIXER_CONTEXT MixerContext,IN PMIXER_ENUM EnumFunction,IN PVOID EnumContext)768 MMixerInitialize(
769     IN PMIXER_CONTEXT MixerContext,
770     IN PMIXER_ENUM EnumFunction,
771     IN PVOID EnumContext)
772 {
773     MIXER_STATUS Status;
774     HANDLE hMixer, hKey;
775     ULONG DeviceIndex, Count;
776     LPWSTR DeviceName;
777     LPMIXER_DATA MixerData;
778     PMIXER_LIST MixerList;
779     PLIST_ENTRY Entry;
780 
781     if (!MixerContext || !EnumFunction || !EnumContext)
782     {
783         /* invalid parameter */
784         return MM_STATUS_INVALID_PARAMETER;
785     }
786 
787     if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free || !MixerContext->Open ||
788         !MixerContext->AllocEventData || !MixerContext->FreeEventData ||
789         !MixerContext->Close || !MixerContext->OpenKey || !MixerContext->QueryKeyValue || !MixerContext->CloseKey)
790     {
791         /* invalid parameter */
792         return MM_STATUS_INVALID_PARAMETER;
793     }
794 
795     /* allocate a mixer list */
796     MixerList = (PMIXER_LIST)MixerContext->Alloc(sizeof(MIXER_LIST));
797     if (!MixerList)
798     {
799         /* no memory */
800         return MM_STATUS_NO_MEMORY;
801     }
802 
803      /* initialize mixer list */
804      MixerList->MixerListCount = 0;
805      MixerList->MixerDataCount = 0;
806      MixerList->WaveInListCount = 0;
807      MixerList->WaveOutListCount = 0;
808      MixerList->MidiInListCount = 0;
809      MixerList->MidiOutListCount = 0;
810      InitializeListHead(&MixerList->MixerList);
811      InitializeListHead(&MixerList->MixerData);
812      InitializeListHead(&MixerList->WaveInList);
813      InitializeListHead(&MixerList->WaveOutList);
814      InitializeListHead(&MixerList->MidiInList);
815      InitializeListHead(&MixerList->MidiOutList);
816 
817      /* store mixer list */
818      MixerContext->MixerContext = (PVOID)MixerList;
819 
820     /* start enumerating all available devices */
821     Count = 0;
822     DeviceIndex = 0;
823 
824     do
825     {
826         /* enumerate a device */
827         Status = EnumFunction(EnumContext, DeviceIndex, &DeviceName, &hMixer, &hKey);
828 
829         if (Status != MM_STATUS_SUCCESS)
830         {
831             /* check error code */
832             if (Status == MM_STATUS_NO_MORE_DEVICES)
833             {
834                 /* enumeration has finished */
835                 break;
836             }
837             else
838             {
839                 DPRINT1("Failed to enumerate device %lu\n", DeviceIndex);
840 
841                 /* TODO cleanup */
842                 return Status;
843             }
844         }
845         else
846         {
847             /* create a mixer data entry */
848             Status = MMixerCreateMixerData(MixerContext, MixerList, DeviceIndex, DeviceName, hMixer, hKey);
849             if (Status != MM_STATUS_SUCCESS)
850                 break;
851         }
852 
853         /* increment device index */
854         DeviceIndex++;
855     }while(TRUE);
856 
857     /* now all filters have been pre-opened
858      * lets enumerate the filters
859      */
860     Entry = MixerList->MixerData.Flink;
861     while(Entry != &MixerList->MixerData)
862     {
863         MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
864         MMixerSetupFilter(MixerContext, MixerList, MixerData, &Count);
865         Entry = Entry->Flink;
866     }
867 
868     Entry = MixerList->MixerData.Flink;
869     while(Entry != &MixerList->MixerData)
870     {
871         MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
872 
873         /* now handle alternative mixer types */
874         MMixerHandleAlternativeMixers(MixerContext, MixerList, MixerData, MixerData->Topology);
875         Entry = Entry->Flink;
876     }
877 
878     //MMixerPrintMixers(MixerContext, MixerList);
879 
880     /* done */
881     return MM_STATUS_SUCCESS;
882 }
883