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