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