e2e0d840ea09e19441b8deb9f683270235be26a1
[reactos.git] / reactos / lib / drivers / sound / mmixer / sup.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: lib/drivers/sound/mmixer/sup.c
5 * PURPOSE: Mixer Support Functions
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9
10
11 #include "priv.h"
12
13 MIXER_STATUS
14 MMixerVerifyContext(
15 IN PMIXER_CONTEXT MixerContext)
16 {
17 if (MixerContext->SizeOfStruct != sizeof(MIXER_CONTEXT))
18 return MM_STATUS_INVALID_PARAMETER;
19
20 if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free || !MixerContext->Open || !MixerContext->Close)
21 return MM_STATUS_INVALID_PARAMETER;
22
23 if (!MixerContext->MixerContext)
24 return MM_STATUS_INVALID_PARAMETER;
25
26 return MM_STATUS_SUCCESS;
27 }
28
29 VOID
30 MMixerFreeMixerInfo(
31 IN PMIXER_CONTEXT MixerContext,
32 IN LPMIXER_INFO MixerInfo)
33 {
34 //UNIMPLEMENTED
35 // FIXME
36 // free all lines
37
38 MixerContext->Free((PVOID)MixerInfo);
39 }
40
41 LPMIXER_INFO
42 MMixerGetMixerInfoByIndex(
43 IN PMIXER_CONTEXT MixerContext,
44 IN ULONG MixerIndex)
45 {
46 LPMIXER_INFO MixerInfo;
47 PLIST_ENTRY Entry;
48 PMIXER_LIST MixerList;
49 ULONG Index = 0;
50
51 // get mixer list
52 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
53
54 if (!MixerList->MixerListCount)
55 return NULL;
56
57 Entry = MixerList->MixerList.Flink;
58
59 while(Entry != &MixerList->MixerList)
60 {
61 MixerInfo = (LPMIXER_INFO)CONTAINING_RECORD(Entry, MIXER_INFO, Entry);
62
63 if (Index == MixerIndex)
64 return MixerInfo;
65
66 // move to next mixer entry
67 Index++;
68 Entry = Entry->Flink;
69 }
70
71 return NULL;
72 }
73
74 LPMIXERCONTROL_DATA
75 MMixerGetMixerControlDataById(
76 PLIST_ENTRY ListHead,
77 DWORD dwControlId)
78 {
79 PLIST_ENTRY Entry;
80 LPMIXERCONTROL_DATA Control;
81
82 /* get first entry */
83 Entry = ListHead->Flink;
84
85 while(Entry != ListHead)
86 {
87 Control = (LPMIXERCONTROL_DATA)CONTAINING_RECORD(Entry, MIXERCONTROL_DATA, Entry);
88 DPRINT("dwSource %x dwSource %x\n", Control->dwControlID, dwControlId);
89 if (Control->dwControlID == dwControlId)
90 return Control;
91
92 Entry = Entry->Flink;
93 }
94 return NULL;
95 }
96
97 LPMIXERLINE_EXT
98 MMixerGetSourceMixerLineByLineId(
99 LPMIXER_INFO MixerInfo,
100 DWORD dwLineID)
101 {
102 PLIST_ENTRY Entry;
103 LPMIXERLINE_EXT MixerLineSrc;
104
105 /* get first entry */
106 Entry = MixerInfo->LineList.Flink;
107
108 while(Entry != &MixerInfo->LineList)
109 {
110 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
111 DPRINT("dwLineID %x dwLineID %x\n", MixerLineSrc->Line.dwLineID, dwLineID);
112 if (MixerLineSrc->Line.dwLineID == dwLineID)
113 return MixerLineSrc;
114
115 Entry = Entry->Flink;
116 }
117
118 return NULL;
119 }
120
121 ULONG
122 MMixerGetIndexOfGuid(
123 PKSMULTIPLE_ITEM MultipleItem,
124 LPCGUID NodeType)
125 {
126 ULONG Index;
127 LPGUID Guid;
128
129 Guid = (LPGUID)(MultipleItem+1);
130
131 /* iterate through node type array */
132 for(Index = 0; Index < MultipleItem->Count; Index++)
133 {
134 if (IsEqualGUIDAligned(NodeType, Guid))
135 {
136 /* found matching guid */
137 return Index;
138 }
139 Guid++;
140 }
141 return MAXULONG;
142 }
143
144 PKSTOPOLOGY_CONNECTION
145 MMixerGetConnectionByIndex(
146 IN PKSMULTIPLE_ITEM MultipleItem,
147 IN ULONG Index)
148 {
149 PKSTOPOLOGY_CONNECTION Descriptor;
150
151 ASSERT(Index < MultipleItem->Count);
152
153 Descriptor = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
154 return &Descriptor[Index];
155 }
156
157 LPGUID
158 MMixerGetNodeType(
159 IN PKSMULTIPLE_ITEM MultipleItem,
160 IN ULONG Index)
161 {
162 LPGUID NodeType;
163
164 ASSERT(Index < MultipleItem->Count);
165
166 NodeType = (LPGUID)(MultipleItem + 1);
167 return &NodeType[Index];
168 }
169
170 MIXER_STATUS
171 MMixerGetNodeIndexes(
172 IN PMIXER_CONTEXT MixerContext,
173 IN PKSMULTIPLE_ITEM MultipleItem,
174 IN ULONG NodeIndex,
175 IN ULONG bNode,
176 IN ULONG bFrom,
177 OUT PULONG NodeReferenceCount,
178 OUT PULONG *NodeReference)
179 {
180 ULONG Index, Count = 0;
181 PKSTOPOLOGY_CONNECTION Connection;
182 PULONG Refs;
183
184 // KSMULTIPLE_ITEM is followed by several KSTOPOLOGY_CONNECTION
185 Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
186
187 // first count all referenced nodes
188 for(Index = 0; Index < MultipleItem->Count; Index++)
189 {
190 if (bNode)
191 {
192 if (bFrom)
193 {
194 if (Connection->FromNode == NodeIndex)
195 {
196 // node id has a connection
197 Count++;
198 }
199 }
200 else
201 {
202 if (Connection->ToNode == NodeIndex)
203 {
204 // node id has a connection
205 Count++;
206 }
207 }
208 }
209 else
210 {
211 if (bFrom)
212 {
213 if (Connection->FromNodePin == NodeIndex && Connection->FromNode == KSFILTER_NODE)
214 {
215 // node id has a connection
216 Count++;
217 }
218 }
219 else
220 {
221 if (Connection->ToNodePin == NodeIndex && Connection->ToNode == KSFILTER_NODE)
222 {
223 // node id has a connection
224 Count++;
225 }
226 }
227 }
228
229
230 // move to next connection
231 Connection++;
232 }
233
234 ASSERT(Count != 0);
235
236 /* now allocate node index array */
237 Refs = (PULONG)MixerContext->Alloc(sizeof(ULONG) * Count);
238 if (!Refs)
239 {
240 // not enough memory
241 return MM_STATUS_NO_MEMORY;
242 }
243
244 Count = 0;
245 Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
246 for(Index = 0; Index < MultipleItem->Count; Index++)
247 {
248 if (bNode)
249 {
250 if (bFrom)
251 {
252 if (Connection->FromNode == NodeIndex)
253 {
254 /* node id has a connection */
255 Refs[Count] = Index;
256 Count++;
257 }
258 }
259 else
260 {
261 if (Connection->ToNode == NodeIndex)
262 {
263 /* node id has a connection */
264 Refs[Count] = Index;
265 Count++;
266 }
267 }
268 }
269 else
270 {
271 if (bFrom)
272 {
273 if (Connection->FromNodePin == NodeIndex && Connection->FromNode == KSFILTER_NODE)
274 {
275 /* node id has a connection */
276 Refs[Count] = Index;
277 Count++;
278 }
279 }
280 else
281 {
282 if (Connection->ToNodePin == NodeIndex && Connection->ToNode == KSFILTER_NODE)
283 {
284 /* node id has a connection */
285 Refs[Count] = Index;
286 Count++;
287 }
288 }
289 }
290
291 /* move to next connection */
292 Connection++;
293 }
294
295 /* store result */
296 *NodeReference = Refs;
297 *NodeReferenceCount = Count;
298
299 return MM_STATUS_SUCCESS;
300 }
301
302 MIXER_STATUS
303 MMixerGetTargetPins(
304 IN PMIXER_CONTEXT MixerContext,
305 IN PKSMULTIPLE_ITEM NodeTypes,
306 IN PKSMULTIPLE_ITEM NodeConnections,
307 IN ULONG NodeIndex,
308 IN ULONG bUpDirection,
309 OUT PULONG Pins,
310 IN ULONG PinCount)
311 {
312 ULONG NodeConnectionCount, Index;
313 MIXER_STATUS Status;
314 PULONG NodeConnection;
315
316 // sanity check */
317 ASSERT(NodeIndex != (ULONG)-1);
318
319 /* get all node indexes referenced by that pin */
320 if (bUpDirection)
321 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
322 else
323 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
324
325 //DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex, Status, NodeConnectionCount);
326
327 if (Status == MM_STATUS_SUCCESS)
328 {
329 for(Index = 0; Index < NodeConnectionCount; Index++)
330 {
331 Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Pins);
332 ASSERT(Status == STATUS_SUCCESS);
333 }
334 MixerContext->Free((PVOID)NodeConnection);
335 }
336
337 return Status;
338 }
339
340 LPMIXERLINE_EXT
341 MMixerGetSourceMixerLineByComponentType(
342 LPMIXER_INFO MixerInfo,
343 DWORD dwComponentType)
344 {
345 PLIST_ENTRY Entry;
346 LPMIXERLINE_EXT MixerLineSrc;
347
348 /* get first entry */
349 Entry = MixerInfo->LineList.Flink;
350
351 while(Entry != &MixerInfo->LineList)
352 {
353 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
354 if (MixerLineSrc->Line.dwComponentType == dwComponentType)
355 return MixerLineSrc;
356
357 Entry = Entry->Flink;
358 }
359
360 return NULL;
361 }
362
363 MIXER_STATUS
364 MMixerGetMixerControlById(
365 LPMIXER_INFO MixerInfo,
366 DWORD dwControlID,
367 LPMIXERLINE_EXT *MixerLine,
368 LPMIXERCONTROLW *MixerControl,
369 PULONG NodeId)
370 {
371 PLIST_ENTRY Entry;
372 LPMIXERLINE_EXT MixerLineSrc;
373 ULONG Index;
374
375 /* get first entry */
376 Entry = MixerInfo->LineList.Flink;
377
378 while(Entry != &MixerInfo->LineList)
379 {
380 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
381
382 for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
383 {
384 if (MixerLineSrc->LineControls[Index].dwControlID == dwControlID)
385 {
386 if (MixerLine)
387 *MixerLine = MixerLineSrc;
388 if (MixerControl)
389 *MixerControl = &MixerLineSrc->LineControls[Index];
390 if (NodeId)
391 *NodeId = MixerLineSrc->NodeIds[Index];
392 return MM_STATUS_SUCCESS;
393 }
394 }
395 Entry = Entry->Flink;
396 }
397
398 return MM_STATUS_UNSUCCESSFUL;
399 }
400
401 ULONG
402 MMixerGetVolumeControlIndex(
403 LPMIXERVOLUME_DATA VolumeData,
404 LONG Value)
405 {
406 ULONG Index;
407
408 for(Index = 0; Index < VolumeData->ValuesCount; Index++)
409 {
410 if (VolumeData->Values[Index] > Value)
411 {
412 return VolumeData->InputSteppingDelta * Index;
413 }
414 }
415 return VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1);
416 }
417
418 MIXER_STATUS
419 MMixerSetGetMuteControlDetails(
420 IN PMIXER_CONTEXT MixerContext,
421 IN HANDLE hMixer,
422 IN ULONG NodeId,
423 IN ULONG dwLineID,
424 IN LPMIXERCONTROLDETAILS MixerControlDetails,
425 IN ULONG bSet)
426 {
427 LPMIXERCONTROLDETAILS_BOOLEAN Input;
428 LONG Value;
429 MIXER_STATUS Status;
430
431 if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
432 return MM_STATUS_INVALID_PARAMETER;
433
434 /* get input */
435 Input = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
436
437 /* FIXME SEH */
438 if (bSet)
439 Value = Input->fValue;
440
441 /* set control details */
442 Status = MMixerSetGetControlDetails(MixerContext, hMixer, NodeId, bSet, KSPROPERTY_AUDIO_MUTE, 0, &Value);
443
444 if (Status != MM_STATUS_SUCCESS)
445 return Status;
446
447 /* FIXME SEH */
448 if (!bSet)
449 {
450 Input->fValue = Value;
451 return Status;
452 }
453 else
454 {
455 // FIXME notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID
456 }
457
458 return Status;
459 }
460
461 MIXER_STATUS
462 MMixerSetGetVolumeControlDetails(
463 IN PMIXER_CONTEXT MixerContext,
464 IN HANDLE hMixer,
465 IN ULONG NodeId,
466 IN ULONG bSet,
467 LPMIXERCONTROLW MixerControl,
468 IN LPMIXERCONTROLDETAILS MixerControlDetails,
469 LPMIXERLINE_EXT MixerLine)
470 {
471 LPMIXERCONTROLDETAILS_UNSIGNED Input;
472 LONG Value, Index, Channel = 0;
473 ULONG dwValue;
474 MIXER_STATUS Status;
475 LPMIXERVOLUME_DATA VolumeData;
476
477 if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_SIGNED))
478 return MM_STATUS_INVALID_PARAMETER;
479
480 VolumeData = (LPMIXERVOLUME_DATA)MMixerGetMixerControlDataById(&MixerLine->LineControlsExtraData, MixerControl->dwControlID);
481 if (!VolumeData)
482 return MM_STATUS_UNSUCCESSFUL;
483
484 /* get input */
485 Input = (LPMIXERCONTROLDETAILS_UNSIGNED)MixerControlDetails->paDetails;
486
487 if (bSet)
488 {
489 /* FIXME SEH */
490 Value = Input->dwValue;
491 Index = Value / VolumeData->InputSteppingDelta;
492
493 if (Index >= VolumeData->ValuesCount)
494 {
495 DPRINT1("Index %u out of bounds %u \n", Index, VolumeData->ValuesCount);
496 DbgBreakPoint();
497 return MM_STATUS_INVALID_PARAMETER;
498 }
499
500 Value = VolumeData->Values[Index];
501 }
502
503 /* set control details */
504 if (bSet)
505 {
506 Status = MMixerSetGetControlDetails(MixerContext, hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value);
507 Status = MMixerSetGetControlDetails(MixerContext, hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value);
508 }
509 else
510 {
511 Status = MMixerSetGetControlDetails(MixerContext, hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value);
512 }
513
514 if (!bSet)
515 {
516 dwValue = MMixerGetVolumeControlIndex(VolumeData, (LONG)Value);
517 /* FIXME SEH */
518 Input->dwValue = dwValue;
519 }
520 else
521 {
522 /* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */
523 }
524 return Status;
525 }