[AUDIO-BRINGUP]
[reactos.git] / 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
10
11 #include "priv.h"
12
13 ULONG
14 MMixerGetCount(
15 IN PMIXER_CONTEXT MixerContext)
16 {
17 PMIXER_LIST MixerList;
18 MIXER_STATUS Status;
19
20 /* verify mixer context */
21 Status = MMixerVerifyContext(MixerContext);
22
23 if (Status != MM_STATUS_SUCCESS)
24 {
25 /* invalid context passed */
26 return Status;
27 }
28
29 /* grab mixer list */
30 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
31
32 // return number of mixers
33 return MixerList->MixerListCount;
34 }
35
36 MIXER_STATUS
37 MMixerGetCapabilities(
38 IN PMIXER_CONTEXT MixerContext,
39 IN ULONG MixerIndex,
40 OUT LPMIXERCAPSW MixerCaps)
41 {
42 MIXER_STATUS Status;
43 LPMIXER_INFO MixerInfo;
44
45 /* verify mixer context */
46 Status = MMixerVerifyContext(MixerContext);
47
48 if (Status != MM_STATUS_SUCCESS)
49 {
50 /* invalid context passed */
51 return Status;
52 }
53
54 /* get mixer info */
55 MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, MixerIndex);
56
57 if (!MixerInfo)
58 {
59 // invalid device index
60 return MM_STATUS_INVALID_PARAMETER;
61 }
62
63 MixerCaps->wMid = MixerInfo->MixCaps.wMid;
64 MixerCaps->wPid = MixerInfo->MixCaps.wPid;
65 MixerCaps->vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
66 MixerCaps->fdwSupport = MixerInfo->MixCaps.fdwSupport;
67 MixerCaps->cDestinations = MixerInfo->MixCaps.cDestinations;
68
69 ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == 0);
70 wcscpy(MixerCaps->szPname, MixerInfo->MixCaps.szPname);
71
72 return MM_STATUS_SUCCESS;
73 }
74
75 MIXER_STATUS
76 MMixerOpen(
77 IN PMIXER_CONTEXT MixerContext,
78 IN ULONG MixerId,
79 IN PVOID MixerEventContext,
80 IN PMIXER_EVENT MixerEventRoutine,
81 OUT PHANDLE MixerHandle)
82 {
83 MIXER_STATUS Status;
84 LPMIXER_INFO MixerInfo;
85
86 /* verify mixer context */
87 Status = MMixerVerifyContext(MixerContext);
88
89 if (Status != MM_STATUS_SUCCESS)
90 {
91 /* invalid context passed */
92 DPRINT1("invalid context\n");
93 return Status;
94 }
95
96 /* get mixer info */
97 MixerInfo = (LPMIXER_INFO)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
98 if (!MixerInfo)
99 {
100 /* invalid mixer id */
101 DPRINT1("invalid mixer id %lu\n", MixerId);
102 return MM_STATUS_INVALID_PARAMETER;
103 }
104
105 /* add the event */
106 Status = MMixerAddEvent(MixerContext, MixerInfo, MixerEventContext, MixerEventRoutine);
107
108
109 /* store result */
110 *MixerHandle = (HANDLE)MixerInfo;
111
112 return MM_STATUS_SUCCESS;
113 }
114
115 MIXER_STATUS
116 MMixerGetLineInfo(
117 IN PMIXER_CONTEXT MixerContext,
118 IN HANDLE MixerHandle,
119 IN ULONG MixerId,
120 IN ULONG Flags,
121 OUT LPMIXERLINEW MixerLine)
122 {
123 MIXER_STATUS Status;
124 LPMIXER_INFO MixerInfo;
125 LPMIXERLINE_EXT MixerLineSrc;
126 ULONG DestinationLineID;
127
128 /* verify mixer context */
129 Status = MMixerVerifyContext(MixerContext);
130
131 if (Status != MM_STATUS_SUCCESS)
132 {
133 /* invalid context passed */
134 return Status;
135 }
136 if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
137 {
138 /* caller passed mixer id */
139 MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
140
141 if (!MixerHandle)
142 {
143 /* invalid parameter */
144 return MM_STATUS_INVALID_PARAMETER;
145 }
146 }
147
148 if (MixerLine->cbStruct != sizeof(MIXERLINEW))
149 {
150 DPRINT1("MixerLine Expected %lu but got %lu\n", sizeof(MIXERLINEW), MixerLine->cbStruct);
151 return MM_STATUS_INVALID_PARAMETER;
152 }
153
154
155 /* clear hmixer from flags */
156 Flags &=~MIXER_OBJECTF_HMIXER;
157
158 DPRINT1("MMixerGetLineInfo MixerId %lu Flags %lu\n", MixerId, Flags);
159
160 if (Flags == MIXER_GETLINEINFOF_DESTINATION)
161 {
162 /* cast to mixer info */
163 MixerInfo = (LPMIXER_INFO)MixerHandle;
164
165 /* calculate destination line id */
166 DestinationLineID = (MixerLine->dwDestination + DESTINATION_LINE);
167
168 /* get destination line */
169 MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
170
171 if (MixerLineSrc == NULL)
172 {
173 DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination);
174 return MM_STATUS_UNSUCCESSFUL;
175 }
176 /* copy mixer line */
177 MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
178
179 /* make sure it is null terminated */
180 MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
181 MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
182 MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
183
184 /* done */
185 return MM_STATUS_SUCCESS;
186 }
187 else if (Flags == MIXER_GETLINEINFOF_SOURCE)
188 {
189 /* cast to mixer info */
190 MixerInfo = (LPMIXER_INFO)MixerHandle;
191
192 /* calculate destination line id */
193 DestinationLineID = (MixerLine->dwDestination + DESTINATION_LINE);
194
195 /* get destination line */
196 MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
197
198 if (MixerLineSrc == NULL)
199 {
200 DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination);
201 return MM_STATUS_UNSUCCESSFUL;
202 }
203
204 /* check if dwSource is out of bounds */
205 if (MixerLine->dwSource >= MixerLineSrc->Line.cConnections)
206 {
207 DPRINT1("MixerCaps Name %S MixerLineName %S Connections %lu dwSource %lu not found\n", MixerInfo->MixCaps.szPname, MixerLineSrc->Line.szName, MixerLineSrc->Line.cConnections, MixerLine->dwSource);
208 return MM_STATUS_UNSUCCESSFUL;
209 }
210
211 /* calculate destination line id */
212 DestinationLineID = (MixerLine->dwSource * DESTINATION_LINE) + MixerLine->dwDestination;
213
214 /* get target destination line id */
215 MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
216
217 /* sanity check */
218 ASSERT(MixerLineSrc);
219
220 DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
221
222 /* copy mixer line */
223 MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
224
225 /* make sure it is null terminated */
226 MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
227 MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
228 MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
229
230 /* done */
231 return MM_STATUS_SUCCESS;
232 }
233 else if (Flags == MIXER_GETLINEINFOF_LINEID)
234 {
235 /* cast to mixer info */
236 MixerInfo = (LPMIXER_INFO)MixerHandle;
237
238 /* try to find line */
239 MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLine->dwLineID);
240 if (!MixerLineSrc)
241 {
242 /* invalid parameter */
243 DPRINT1("MixerName %S Line not found %lu\n", MixerInfo->MixCaps.szPname, MixerLine->dwLineID);
244 return MM_STATUS_INVALID_PARAMETER;
245 }
246
247 DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
248
249 /* copy mixer line*/
250 MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
251
252 /* make sure it is null terminated */
253 MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
254 MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
255 MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
256
257 return MM_STATUS_SUCCESS;
258 }
259 else if (Flags == MIXER_GETLINEINFOF_COMPONENTTYPE)
260 {
261 /* cast to mixer info */
262 MixerInfo = (LPMIXER_INFO)MixerHandle;
263
264 /* find mixer line by component type */
265 MixerLineSrc = MMixerGetSourceMixerLineByComponentType(MixerInfo, MixerLine->dwComponentType);
266 if (!MixerLineSrc)
267 {
268 DPRINT1("Failed to find component type %x\n", MixerLine->dwComponentType);
269 return MM_STATUS_UNSUCCESSFUL;
270 }
271
272 /* copy mixer line */
273 MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
274
275 /* make sure it is null terminated */
276 MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
277 MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
278 MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
279
280 /* done */
281 return MM_STATUS_SUCCESS;
282 }
283 else if (Flags == MIXER_GETLINEINFOF_TARGETTYPE)
284 {
285 DPRINT1("MIXER_GETLINEINFOF_TARGETTYPE handling is unimplemented\n");
286 }
287 else
288 {
289 DPRINT1("Unknown Flags %lx handling is unimplemented\n", Flags);
290 }
291
292 return MM_STATUS_NOT_IMPLEMENTED;
293 }
294
295 MIXER_STATUS
296 MMixerGetLineControls(
297 IN PMIXER_CONTEXT MixerContext,
298 IN HANDLE MixerHandle,
299 IN ULONG MixerId,
300 IN ULONG Flags,
301 OUT LPMIXERLINECONTROLSW MixerLineControls)
302 {
303 LPMIXER_INFO MixerInfo;
304 LPMIXERLINE_EXT MixerLineSrc;
305 LPMIXERCONTROLW MixerControl;
306 MIXER_STATUS Status;
307 ULONG Index;
308
309 /* verify mixer context */
310 Status = MMixerVerifyContext(MixerContext);
311
312 if (Status != MM_STATUS_SUCCESS)
313 {
314 /* invalid context passed */
315 return Status;
316 }
317
318 if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
319 {
320 /* caller passed mixer id */
321 MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
322
323 if (!MixerHandle)
324 {
325 /* invalid parameter */
326 return MM_STATUS_INVALID_PARAMETER;
327 }
328 }
329
330 Flags &= ~MIXER_OBJECTF_HMIXER;
331
332 if (Flags == MIXER_GETLINECONTROLSF_ALL)
333 {
334 /* cast to mixer info */
335 MixerInfo = (LPMIXER_INFO)MixerHandle;
336
337 MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
338
339 if (!MixerLineSrc)
340 {
341 /* invalid line id */
342 return MM_STATUS_INVALID_PARAMETER;
343 }
344 /* copy line control(s) */
345 MixerContext->Copy(MixerLineControls->pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, MixerLineControls->cControls) * sizeof(MIXERCONTROLW));
346
347 return MM_STATUS_SUCCESS;
348 }
349 else if (Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
350 {
351 /* cast to mixer info */
352 MixerInfo = (LPMIXER_INFO)MixerHandle;
353
354 MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
355
356 if (!MixerLineSrc)
357 {
358 /* invalid line id */
359 return MM_STATUS_INVALID_PARAMETER;
360 }
361
362 ASSERT(MixerLineSrc);
363
364 Index = 0;
365 for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
366 {
367 DPRINT("dwControlType %x\n", MixerLineSrc->LineControls[Index].dwControlType);
368 if (MixerLineControls->dwControlType == MixerLineSrc->LineControls[Index].dwControlType)
369 {
370 /* found a control with that type */
371 MixerContext->Copy(MixerLineControls->pamxctrl, &MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW));
372 return MM_STATUS_SUCCESS;
373 }
374 }
375 DPRINT("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x cControls %u \n", MixerLineControls->dwControlType, MixerLineControls->dwLineID, MixerLineSrc->Line.cControls);
376 return MM_STATUS_UNSUCCESSFUL;
377 }
378 else if (Flags == MIXER_GETLINECONTROLSF_ONEBYID)
379 {
380 /* cast to mixer info */
381 MixerInfo = (LPMIXER_INFO)MixerHandle;
382
383 Status = MMixerGetMixerControlById(MixerInfo, MixerLineControls->dwControlID, NULL, &MixerControl, NULL);
384
385 if (Status != MM_STATUS_SUCCESS)
386 {
387 /* invalid parameter */
388 return MM_STATUS_INVALID_PARAMETER;
389 }
390
391 /* copy the controls */
392 MixerContext->Copy(MixerLineControls->pamxctrl, MixerControl, sizeof(MIXERCONTROLW));
393 return MM_STATUS_SUCCESS;
394 }
395
396
397 return MM_STATUS_NOT_IMPLEMENTED;
398 }
399
400 MIXER_STATUS
401 MMixerSetControlDetails(
402 IN PMIXER_CONTEXT MixerContext,
403 IN HANDLE MixerHandle,
404 IN ULONG MixerId,
405 IN ULONG Flags,
406 OUT LPMIXERCONTROLDETAILS MixerControlDetails)
407 {
408 MIXER_STATUS Status;
409 ULONG NodeId;
410 LPMIXER_INFO MixerInfo;
411 LPMIXERLINE_EXT MixerLine;
412 LPMIXERCONTROLW MixerControl;
413
414 /* verify mixer context */
415 Status = MMixerVerifyContext(MixerContext);
416
417 if (Status != MM_STATUS_SUCCESS)
418 {
419 /* invalid context passed */
420 return Status;
421 }
422
423 if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
424 {
425 /* caller passed mixer id */
426 MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
427
428 if (!MixerHandle)
429 {
430 /* invalid parameter */
431 return MM_STATUS_INVALID_PARAMETER;
432 }
433 }
434
435 /* get mixer info */
436 MixerInfo = (LPMIXER_INFO)MixerHandle;
437
438 /* get mixer control */
439 Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);
440
441 /* check for success */
442 if (Status != MM_STATUS_SUCCESS)
443 {
444 /* failed to find control id */
445 return MM_STATUS_INVALID_PARAMETER;
446 }
447
448 switch(MixerControl->dwControlType)
449 {
450 case MIXERCONTROL_CONTROLTYPE_MUTE:
451 Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo->hMixer, NodeId, MixerLine->Line.dwLineID, MixerControlDetails, TRUE);
452 break;
453 case MIXERCONTROL_CONTROLTYPE_VOLUME:
454 Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo->hMixer, NodeId, TRUE, MixerControl, MixerControlDetails, MixerLine);
455 break;
456 default:
457 Status = MM_STATUS_NOT_IMPLEMENTED;
458 }
459
460 return Status;
461 }
462
463 MIXER_STATUS
464 MMixerGetControlDetails(
465 IN PMIXER_CONTEXT MixerContext,
466 IN HANDLE MixerHandle,
467 IN ULONG MixerId,
468 IN ULONG Flags,
469 OUT LPMIXERCONTROLDETAILS MixerControlDetails)
470 {
471 MIXER_STATUS Status;
472 ULONG NodeId;
473 LPMIXER_INFO MixerInfo;
474 LPMIXERLINE_EXT MixerLine;
475 LPMIXERCONTROLW MixerControl;
476
477 /* verify mixer context */
478 Status = MMixerVerifyContext(MixerContext);
479
480 if (Status != MM_STATUS_SUCCESS)
481 {
482 /* invalid context passed */
483 return Status;
484 }
485
486 if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
487 {
488 /* caller passed mixer id */
489 MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
490
491 if (!MixerHandle)
492 {
493 /* invalid parameter */
494 return MM_STATUS_INVALID_PARAMETER;
495 }
496 }
497
498 /* get mixer info */
499 MixerInfo = (LPMIXER_INFO)MixerHandle;
500
501 /* get mixer control */
502 Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);
503
504 /* check for success */
505 if (Status != MM_STATUS_SUCCESS)
506 {
507 /* failed to find control id */
508 return MM_STATUS_INVALID_PARAMETER;
509 }
510
511 switch(MixerControl->dwControlType)
512 {
513 case MIXERCONTROL_CONTROLTYPE_MUTE:
514 Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo, NodeId, MixerLine->Line.dwLineID, MixerControlDetails, FALSE);
515 break;
516 case MIXERCONTROL_CONTROLTYPE_VOLUME:
517 Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo, NodeId, FALSE, MixerControl, MixerControlDetails, MixerLine);
518 break;
519 default:
520 Status = MM_STATUS_NOT_IMPLEMENTED;
521 }
522
523 return Status;
524 }
525
526 VOID
527 MMixerPrintMixers(
528 IN PMIXER_CONTEXT MixerContext,
529 IN PMIXER_LIST MixerList)
530 {
531 ULONG Index, SubIndex, DestinationLineID;
532 LPMIXER_INFO MixerInfo;
533 LPMIXERLINE_EXT DstMixerLine;
534
535 DPRINT1("MixerList %p\n", MixerList);
536 DPRINT1("MidiInCount %lu\n", MixerList->MidiInListCount);
537 DPRINT1("MidiOutCount %lu\n", MixerList->MidiOutListCount);
538 DPRINT1("WaveInCount %lu\n", MixerList->WaveInListCount);
539 DPRINT1("WaveOutCount %lu\n", MixerList->WaveOutListCount);
540 DPRINT1("MixerCount %p\n", MixerList->MixerListCount);
541
542
543 for(Index = 0; Index < MixerList->MixerListCount; Index++)
544 {
545 /* get mixer info */
546 MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, Index);
547
548 ASSERT(MixerInfo);
549 DPRINT1("\n");
550 DPRINT1("Name :%S\n", MixerInfo->MixCaps.szPname);
551 DPRINT1("cDestinations: %lu\n", MixerInfo->MixCaps.cDestinations);
552 DPRINT1("fdwSupport %lu\n", MixerInfo->MixCaps.fdwSupport);
553 DPRINT1("vDriverVersion %lx\n", MixerInfo->MixCaps.vDriverVersion);
554 DPRINT1("wMid %lx\n", MixerInfo->MixCaps.wMid);
555 DPRINT1("wPid %lx\n", MixerInfo->MixCaps.wPid);
556
557 for(SubIndex = 0; SubIndex < MixerInfo->MixCaps.cDestinations; SubIndex++)
558 {
559 /* calculate destination line id */
560 DestinationLineID = (SubIndex + DESTINATION_LINE);
561
562 /* get destination line */
563 DstMixerLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
564 DPRINT1("\n");
565 DPRINT1("cChannels %lu\n", DstMixerLine->Line.cChannels);
566 DPRINT1("cConnections %lu\n", DstMixerLine->Line.cConnections);
567 DPRINT1("cControls %lu\n", DstMixerLine->Line.cControls);
568 DPRINT1("dwComponentType %lx\n", DstMixerLine->Line.dwComponentType);
569 DPRINT1("dwDestination %lu\n", DstMixerLine->Line.dwDestination);
570 DPRINT1("dwLineID %lx\n", DstMixerLine->Line.dwLineID);
571 DPRINT1("dwSource %lx\n", DstMixerLine->Line.dwSource);
572 DPRINT1("dwUser %lu\n", DstMixerLine->Line.dwUser);
573 DPRINT1("fdwLine %lu\n", DstMixerLine->Line.fdwLine);
574 DPRINT1("szName %S\n", DstMixerLine->Line.szName);
575 DPRINT1("szShortName %S\n", DstMixerLine->Line.szShortName);
576 DPRINT1("Target.dwDeviceId %lu\n", DstMixerLine->Line.Target.dwDeviceID);
577 DPRINT1("Target.dwType %lu\n", DstMixerLine->Line.Target.dwType);
578 DPRINT1("Target.szName %S\n", DstMixerLine->Line.Target.szPname);
579 DPRINT1("Target.vDriverVersion %lx\n", DstMixerLine->Line.Target.vDriverVersion);
580 DPRINT1("Target.wMid %lx\n", DstMixerLine->Line.Target.wMid );
581 DPRINT1("Target.wPid %lx\n", DstMixerLine->Line.Target.wPid);
582 }
583 }
584 }
585
586 MIXER_STATUS
587 MMixerInitialize(
588 IN PMIXER_CONTEXT MixerContext,
589 IN PMIXER_ENUM EnumFunction,
590 IN PVOID EnumContext)
591 {
592 MIXER_STATUS Status;
593 HANDLE hMixer, hKey;
594 ULONG DeviceIndex, Count;
595 LPWSTR DeviceName;
596 LPMIXER_DATA MixerData;
597 PMIXER_LIST MixerList;
598 PLIST_ENTRY Entry;
599
600 if (!MixerContext || !EnumFunction || !EnumContext)
601 {
602 /* invalid parameter */
603 return MM_STATUS_INVALID_PARAMETER;
604 }
605
606 if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free || !MixerContext->Open ||
607 !MixerContext->AllocEventData || !MixerContext->FreeEventData ||
608 !MixerContext->Close || !MixerContext->OpenKey || !MixerContext->QueryKeyValue || !MixerContext->CloseKey)
609 {
610 /* invalid parameter */
611 return MM_STATUS_INVALID_PARAMETER;
612 }
613
614 /* allocate a mixer list */
615 MixerList = (PMIXER_LIST)MixerContext->Alloc(sizeof(MIXER_LIST));
616 if (!MixerList)
617 {
618 /* no memory */
619 return MM_STATUS_NO_MEMORY;
620 }
621
622 /* initialize mixer list */
623 MixerList->MixerListCount = 0;
624 MixerList->MixerDataCount = 0;
625 MixerList->WaveInListCount = 0;
626 MixerList->WaveOutListCount = 0;
627 MixerList->MidiInListCount = 0;
628 MixerList->MidiOutListCount = 0;
629 InitializeListHead(&MixerList->MixerList);
630 InitializeListHead(&MixerList->MixerData);
631 InitializeListHead(&MixerList->WaveInList);
632 InitializeListHead(&MixerList->WaveOutList);
633 InitializeListHead(&MixerList->MidiInList);
634 InitializeListHead(&MixerList->MidiOutList);
635
636 /* store mixer list */
637 MixerContext->MixerContext = (PVOID)MixerList;
638
639 /* start enumerating all available devices */
640 Count = 0;
641 DeviceIndex = 0;
642
643 do
644 {
645 /* enumerate a device */
646 Status = EnumFunction(EnumContext, DeviceIndex, &DeviceName, &hMixer, &hKey);
647
648 if (Status != MM_STATUS_SUCCESS)
649 {
650 /* check error code */
651 if (Status == MM_STATUS_NO_MORE_DEVICES)
652 {
653 /* enumeration has finished */
654 break;
655 }
656 else
657 {
658 DPRINT1("Failed to enumerate device %lu\n", DeviceIndex);
659
660 /* TODO cleanup */
661 return Status;
662 }
663 }
664 else
665 {
666 /* create a mixer data entry */
667 Status = MMixerCreateMixerData(MixerContext, MixerList, DeviceIndex, DeviceName, hMixer, hKey);
668 if (Status != MM_STATUS_SUCCESS)
669 break;
670 }
671
672 /* increment device index */
673 DeviceIndex++;
674 }while(TRUE);
675
676 /* now all filters have been pre-opened
677 * lets enumerate the filters
678 */
679 Entry = MixerList->MixerData.Flink;
680 while(Entry != &MixerList->MixerData)
681 {
682 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
683 MMixerSetupFilter(MixerContext, MixerList, MixerData, &Count);
684 Entry = Entry->Flink;
685 }
686
687 MMixerPrintMixers(MixerContext, MixerList);
688
689 /* done */
690 return MM_STATUS_SUCCESS;
691 }