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