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