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