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