[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
127 /* verify mixer context */
128 Status = MMixerVerifyContext(MixerContext);
129
130 if (Status != MM_STATUS_SUCCESS)
131 {
132 /* invalid context passed */
133 return Status;
134 }
135 if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
136 {
137 /* caller passed mixer id */
138 MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
139
140 if (!MixerHandle)
141 {
142 /* invalid parameter */
143 return MM_STATUS_INVALID_PARAMETER;
144 }
145 }
146
147 /* clear hmixer from flags */
148 Flags &=~MIXER_OBJECTF_HMIXER;
149
150 if (Flags == MIXER_GETLINEINFOF_DESTINATION)
151 {
152 /* cast to mixer info */
153 MixerInfo = (LPMIXER_INFO)MixerHandle;
154
155 if (MixerLine->dwDestination != 0)
156 {
157 /* destination line member must be zero */
158 return MM_STATUS_INVALID_PARAMETER;
159 }
160
161 MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
162 ASSERT(MixerLineSrc);
163 MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
164
165 return MM_STATUS_SUCCESS;
166 }
167 else if (Flags == MIXER_GETLINEINFOF_SOURCE)
168 {
169 /* cast to mixer info */
170 MixerInfo = (LPMIXER_INFO)MixerHandle;
171
172
173 MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
174 ASSERT(MixerLineSrc);
175
176 if (MixerLine->dwSource >= MixerLineSrc->Line.cConnections)
177 {
178 DPRINT("dwSource %u > Destinations %u\n", MixerLine->dwSource, MixerLineSrc->Line.cConnections);
179
180 /* invalid parameter */
181 return MM_STATUS_INVALID_PARAMETER;
182 }
183
184 MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLine->dwSource * 0x10000);
185 if (MixerLineSrc)
186 {
187 DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
188 MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
189 return MM_STATUS_SUCCESS;
190 }
191 return MM_STATUS_UNSUCCESSFUL;
192 }
193 else if (Flags == MIXER_GETLINEINFOF_LINEID)
194 {
195 /* cast to mixer info */
196 MixerInfo = (LPMIXER_INFO)MixerHandle;
197
198 MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLine->dwLineID);
199 if (!MixerLineSrc)
200 {
201 /* invalid parameter */
202 return MM_STATUS_INVALID_PARAMETER;
203 }
204
205 /* copy cached data */
206 MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
207 return MM_STATUS_SUCCESS;
208 }
209 else if (Flags == MIXER_GETLINEINFOF_COMPONENTTYPE)
210 {
211 /* cast to mixer info */
212 MixerInfo = (LPMIXER_INFO)MixerHandle;
213
214 MixerLineSrc = MMixerGetSourceMixerLineByComponentType(MixerInfo, MixerLine->dwComponentType);
215 if (!MixerLineSrc)
216 {
217 DPRINT1("Failed to find component type %x\n", MixerLine->dwComponentType);
218 return MM_STATUS_UNSUCCESSFUL;
219 }
220
221 ASSERT(MixerLineSrc);
222
223 /* copy cached data */
224 MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
225 return MM_STATUS_SUCCESS;
226 }
227
228 return MM_STATUS_NOT_IMPLEMENTED;
229 }
230
231 MIXER_STATUS
232 MMixerGetLineControls(
233 IN PMIXER_CONTEXT MixerContext,
234 IN HANDLE MixerHandle,
235 IN ULONG MixerId,
236 IN ULONG Flags,
237 OUT LPMIXERLINECONTROLSW MixerLineControls)
238 {
239 LPMIXER_INFO MixerInfo;
240 LPMIXERLINE_EXT MixerLineSrc;
241 LPMIXERCONTROLW MixerControl;
242 MIXER_STATUS Status;
243 ULONG Index;
244
245 /* verify mixer context */
246 Status = MMixerVerifyContext(MixerContext);
247
248 if (Status != MM_STATUS_SUCCESS)
249 {
250 /* invalid context passed */
251 return Status;
252 }
253
254 if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
255 {
256 /* caller passed mixer id */
257 MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
258
259 if (!MixerHandle)
260 {
261 /* invalid parameter */
262 return MM_STATUS_INVALID_PARAMETER;
263 }
264 }
265
266 Flags &= ~MIXER_OBJECTF_HMIXER;
267
268 if (Flags == MIXER_GETLINECONTROLSF_ALL)
269 {
270 /* cast to mixer info */
271 MixerInfo = (LPMIXER_INFO)MixerHandle;
272
273 MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
274
275 if (!MixerLineSrc)
276 {
277 /* invalid line id */
278 return MM_STATUS_INVALID_PARAMETER;
279 }
280 /* copy line control(s) */
281 MixerContext->Copy(MixerLineControls->pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, MixerLineControls->cControls) * sizeof(MIXERCONTROLW));
282
283 return MM_STATUS_SUCCESS;
284 }
285 else if (Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
286 {
287 /* cast to mixer info */
288 MixerInfo = (LPMIXER_INFO)MixerHandle;
289
290 MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
291
292 if (!MixerLineSrc)
293 {
294 /* invalid line id */
295 return MM_STATUS_INVALID_PARAMETER;
296 }
297
298 ASSERT(MixerLineSrc);
299
300 Index = 0;
301 for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
302 {
303 DPRINT("dwControlType %x\n", MixerLineSrc->LineControls[Index].dwControlType);
304 if (MixerLineControls->dwControlType == MixerLineSrc->LineControls[Index].dwControlType)
305 {
306 /* found a control with that type */
307 MixerContext->Copy(MixerLineControls->pamxctrl, &MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW));
308 return MM_STATUS_SUCCESS;
309 }
310 }
311 DPRINT("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x cControls %u \n", MixerLineControls->dwControlType, MixerLineControls->dwLineID, MixerLineSrc->Line.cControls);
312 return MM_STATUS_UNSUCCESSFUL;
313 }
314 else if (Flags == MIXER_GETLINECONTROLSF_ONEBYID)
315 {
316 /* cast to mixer info */
317 MixerInfo = (LPMIXER_INFO)MixerHandle;
318
319 Status = MMixerGetMixerControlById(MixerInfo, MixerLineControls->dwControlID, NULL, &MixerControl, NULL);
320
321 if (Status != MM_STATUS_SUCCESS)
322 {
323 /* invalid parameter */
324 return MM_STATUS_INVALID_PARAMETER;
325 }
326
327 /* copy the controls */
328 MixerContext->Copy(MixerLineControls->pamxctrl, MixerControl, sizeof(MIXERCONTROLW));
329 return MM_STATUS_SUCCESS;
330 }
331
332
333 return MM_STATUS_NOT_IMPLEMENTED;
334 }
335
336 MIXER_STATUS
337 MMixerSetControlDetails(
338 IN PMIXER_CONTEXT MixerContext,
339 IN HANDLE MixerHandle,
340 IN ULONG MixerId,
341 IN ULONG Flags,
342 OUT LPMIXERCONTROLDETAILS MixerControlDetails)
343 {
344 MIXER_STATUS Status;
345 ULONG NodeId;
346 LPMIXER_INFO MixerInfo;
347 LPMIXERLINE_EXT MixerLine;
348 LPMIXERCONTROLW MixerControl;
349
350 /* verify mixer context */
351 Status = MMixerVerifyContext(MixerContext);
352
353 if (Status != MM_STATUS_SUCCESS)
354 {
355 /* invalid context passed */
356 return Status;
357 }
358
359 if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
360 {
361 /* caller passed mixer id */
362 MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
363
364 if (!MixerHandle)
365 {
366 /* invalid parameter */
367 return MM_STATUS_INVALID_PARAMETER;
368 }
369 }
370
371 /* get mixer info */
372 MixerInfo = (LPMIXER_INFO)MixerHandle;
373
374 /* get mixer control */
375 Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);
376
377 /* check for success */
378 if (Status != MM_STATUS_SUCCESS)
379 {
380 /* failed to find control id */
381 return MM_STATUS_INVALID_PARAMETER;
382 }
383
384 switch(MixerControl->dwControlType)
385 {
386 case MIXERCONTROL_CONTROLTYPE_MUTE:
387 Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo->hMixer, NodeId, MixerLine->Line.dwLineID, MixerControlDetails, TRUE);
388 break;
389 case MIXERCONTROL_CONTROLTYPE_VOLUME:
390 Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo->hMixer, NodeId, TRUE, MixerControl, MixerControlDetails, MixerLine);
391 break;
392 default:
393 Status = MM_STATUS_NOT_IMPLEMENTED;
394 }
395
396 return Status;
397 }
398
399 MIXER_STATUS
400 MMixerGetControlDetails(
401 IN PMIXER_CONTEXT MixerContext,
402 IN HANDLE MixerHandle,
403 IN ULONG MixerId,
404 IN ULONG Flags,
405 OUT LPMIXERCONTROLDETAILS MixerControlDetails)
406 {
407 MIXER_STATUS Status;
408 ULONG NodeId;
409 LPMIXER_INFO MixerInfo;
410 LPMIXERLINE_EXT MixerLine;
411 LPMIXERCONTROLW MixerControl;
412
413 /* verify mixer context */
414 Status = MMixerVerifyContext(MixerContext);
415
416 if (Status != MM_STATUS_SUCCESS)
417 {
418 /* invalid context passed */
419 return Status;
420 }
421
422 if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
423 {
424 /* caller passed mixer id */
425 MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
426
427 if (!MixerHandle)
428 {
429 /* invalid parameter */
430 return MM_STATUS_INVALID_PARAMETER;
431 }
432 }
433
434 /* get mixer info */
435 MixerInfo = (LPMIXER_INFO)MixerHandle;
436
437 /* get mixer control */
438 Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);
439
440 /* check for success */
441 if (Status != MM_STATUS_SUCCESS)
442 {
443 /* failed to find control id */
444 return MM_STATUS_INVALID_PARAMETER;
445 }
446
447 switch(MixerControl->dwControlType)
448 {
449 case MIXERCONTROL_CONTROLTYPE_MUTE:
450 Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo, NodeId, MixerLine->Line.dwLineID, MixerControlDetails, FALSE);
451 break;
452 case MIXERCONTROL_CONTROLTYPE_VOLUME:
453 Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo, NodeId, FALSE, MixerControl, MixerControlDetails, MixerLine);
454 break;
455 default:
456 Status = MM_STATUS_NOT_IMPLEMENTED;
457 }
458
459 return Status;
460 }
461
462 MIXER_STATUS
463 MMixerInitialize(
464 IN PMIXER_CONTEXT MixerContext,
465 IN PMIXER_ENUM EnumFunction,
466 IN PVOID EnumContext)
467 {
468 MIXER_STATUS Status;
469 HANDLE hMixer, hKey;
470 ULONG DeviceIndex, Count;
471 LPWSTR DeviceName;
472 LPMIXER_DATA MixerData;
473 PMIXER_LIST MixerList;
474 PLIST_ENTRY Entry;
475
476 if (!MixerContext || !EnumFunction || !EnumContext)
477 {
478 /* invalid parameter */
479 return MM_STATUS_INVALID_PARAMETER;
480 }
481
482 if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free || !MixerContext->Open ||
483 !MixerContext->AllocEventData || !MixerContext->FreeEventData ||
484 !MixerContext->Close || !MixerContext->OpenKey || !MixerContext->QueryKeyValue || !MixerContext->CloseKey)
485 {
486 /* invalid parameter */
487 return MM_STATUS_INVALID_PARAMETER;
488 }
489
490 /* allocate a mixer list */
491 MixerList = (PMIXER_LIST)MixerContext->Alloc(sizeof(MIXER_LIST));
492 if (!MixerList)
493 {
494 /* no memory */
495 return MM_STATUS_NO_MEMORY;
496 }
497
498 /* initialize mixer list */
499 MixerList->MixerListCount = 0;
500 MixerList->MixerDataCount = 0;
501 MixerList->WaveInListCount = 0;
502 MixerList->WaveOutListCount = 0;
503 MixerList->MidiInListCount = 0;
504 MixerList->MidiOutListCount = 0;
505 InitializeListHead(&MixerList->MixerList);
506 InitializeListHead(&MixerList->MixerData);
507 InitializeListHead(&MixerList->WaveInList);
508 InitializeListHead(&MixerList->WaveOutList);
509 InitializeListHead(&MixerList->MidiInList);
510 InitializeListHead(&MixerList->MidiOutList);
511
512 /* store mixer list */
513 MixerContext->MixerContext = (PVOID)MixerList;
514
515 /* start enumerating all available devices */
516 Count = 0;
517 DeviceIndex = 0;
518
519 do
520 {
521 /* enumerate a device */
522 Status = EnumFunction(EnumContext, DeviceIndex, &DeviceName, &hMixer, &hKey);
523
524 if (Status != MM_STATUS_SUCCESS)
525 {
526 /* check error code */
527 if (Status == MM_STATUS_NO_MORE_DEVICES)
528 {
529 /* enumeration has finished */
530 break;
531 }
532 else
533 {
534 DPRINT1("Failed to enumerate device %lu\n", DeviceIndex);
535
536 /* TODO cleanup */
537 return Status;
538 }
539 }
540 else
541 {
542 /* create a mixer data entry */
543 Status = MMixerCreateMixerData(MixerContext, MixerList, DeviceIndex, DeviceName, hMixer, hKey);
544 if (Status != MM_STATUS_SUCCESS)
545 break;
546 }
547
548 /* increment device index */
549 DeviceIndex++;
550 }while(TRUE);
551
552 /* now all filters have been pre-opened
553 * lets enumerate the filters
554 */
555 Entry = MixerList->MixerData.Flink;
556 while(Entry != &MixerList->MixerData)
557 {
558 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
559 MMixerSetupFilter(MixerContext, MixerList, MixerData, &Count);
560 Entry = Entry->Flink;
561 }
562
563 /* done */
564 return MM_STATUS_SUCCESS;
565 }