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
13 const GUID KSNODETYPE_SUM
= {0xDA441A60L
, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
14 const GUID KSNODETYPE_DAC
= {0x507AE360L
, 0xC554, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
15 const GUID KSNODETYPE_ADC
= {0x4D837FE0L
, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
16 const GUID KSNODETYPE_AGC
= {0xE88C9BA0L
, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
17 const GUID KSNODETYPE_LOUDNESS
= {0x41887440L
, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
18 const GUID KSNODETYPE_MUTE
= {0x02B223C0L
, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
19 const GUID KSNODETYPE_TONE
= {0x7607E580L
, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
20 const GUID KSNODETYPE_VOLUME
= {0x3A5ACC00L
, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
21 const GUID KSNODETYPE_PEAKMETER
= {0xa085651e, 0x5f0d, 0x4b36, {0xa8, 0x69, 0xd1, 0x95, 0xd6, 0xab, 0x4b, 0x9e}};
22 const GUID KSNODETYPE_MUX
= {0x2CEAF780, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
23 const GUID KSNODETYPE_STEREO_WIDE
= {0xA9E69800L
, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
24 const GUID KSNODETYPE_CHORUS
= {0x20173F20L
, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
25 const GUID KSNODETYPE_REVERB
= {0xEF0328E0L
, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
26 const GUID KSNODETYPE_SUPERMIX
= {0xE573ADC0L
, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
28 const GUID KSPROPSETID_Audio
= {0x45FFAAA0L
, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
29 const GUID KSPROPSETID_Pin
= {0x8C134960L
, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
30 const GUID KSPROPSETID_General
= {0x1464EDA5L
, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
31 const GUID KSPROPSETID_Topology
= {0x720D4AC0L
, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
35 IN PMIXER_CONTEXT MixerContext
)
37 if (MixerContext
->SizeOfStruct
!= sizeof(MIXER_CONTEXT
))
38 return MM_STATUS_INVALID_PARAMETER
;
40 if (!MixerContext
->Alloc
|| !MixerContext
->Control
|| !MixerContext
->Free
|| !MixerContext
->Open
|| !MixerContext
->Close
)
41 return MM_STATUS_INVALID_PARAMETER
;
43 if (!MixerContext
->MixerContext
)
44 return MM_STATUS_INVALID_PARAMETER
;
46 return MM_STATUS_SUCCESS
;
51 IN PMIXER_CONTEXT MixerContext
,
52 IN LPMIXER_INFO MixerInfo
)
58 MixerContext
->Free((PVOID
)MixerInfo
);
62 MMixerGetMixerInfoByIndex(
63 IN PMIXER_CONTEXT MixerContext
,
66 LPMIXER_INFO MixerInfo
;
68 PMIXER_LIST MixerList
;
72 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
74 if (!MixerList
->MixerListCount
)
77 Entry
= MixerList
->MixerList
.Flink
;
79 while(Entry
!= &MixerList
->MixerList
)
81 MixerInfo
= (LPMIXER_INFO
)CONTAINING_RECORD(Entry
, MIXER_INFO
, Entry
);
83 if (Index
== MixerIndex
)
86 // move to next mixer entry
95 MMixerGetMixerControlDataById(
100 LPMIXERCONTROL_DATA Control
;
102 /* get first entry */
103 Entry
= ListHead
->Flink
;
105 while(Entry
!= ListHead
)
107 Control
= (LPMIXERCONTROL_DATA
)CONTAINING_RECORD(Entry
, MIXERCONTROL_DATA
, Entry
);
108 DPRINT("dwSource %x dwSource %x\n", Control
->dwControlID
, dwControlId
);
109 if (Control
->dwControlID
== dwControlId
)
112 Entry
= Entry
->Flink
;
118 MMixerGetSourceMixerLineByLineId(
119 LPMIXER_INFO MixerInfo
,
123 LPMIXERLINE_EXT MixerLineSrc
;
125 /* get first entry */
126 Entry
= MixerInfo
->LineList
.Flink
;
128 while(Entry
!= &MixerInfo
->LineList
)
130 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
131 DPRINT("dwLineID %x dwLineID %x\n", MixerLineSrc
->Line
.dwLineID
, dwLineID
);
132 if (MixerLineSrc
->Line
.dwLineID
== dwLineID
)
135 Entry
= Entry
->Flink
;
142 MMixerGetIndexOfGuid(
143 PKSMULTIPLE_ITEM MultipleItem
,
149 Guid
= (LPGUID
)(MultipleItem
+1);
151 /* iterate through node type array */
152 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
154 if (IsEqualGUIDAligned(NodeType
, Guid
))
156 /* found matching guid */
164 PKSTOPOLOGY_CONNECTION
165 MMixerGetConnectionByIndex(
166 IN PKSMULTIPLE_ITEM MultipleItem
,
169 PKSTOPOLOGY_CONNECTION Descriptor
;
171 ASSERT(Index
< MultipleItem
->Count
);
173 Descriptor
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
174 return &Descriptor
[Index
];
179 IN PKSMULTIPLE_ITEM MultipleItem
,
184 ASSERT(Index
< MultipleItem
->Count
);
186 NodeType
= (LPGUID
)(MultipleItem
+ 1);
187 return &NodeType
[Index
];
191 MMixerGetNodeIndexes(
192 IN PMIXER_CONTEXT MixerContext
,
193 IN PKSMULTIPLE_ITEM MultipleItem
,
197 OUT PULONG NodeReferenceCount
,
198 OUT PULONG
*NodeReference
)
200 ULONG Index
, Count
= 0;
201 PKSTOPOLOGY_CONNECTION Connection
;
204 // KSMULTIPLE_ITEM is followed by several KSTOPOLOGY_CONNECTION
205 Connection
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
207 // first count all referenced nodes
208 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
214 if (Connection
->FromNode
== NodeIndex
)
216 // node id has a connection
222 if (Connection
->ToNode
== NodeIndex
)
224 // node id has a connection
233 if (Connection
->FromNodePin
== NodeIndex
&& Connection
->FromNode
== KSFILTER_NODE
)
235 // node id has a connection
241 if (Connection
->ToNodePin
== NodeIndex
&& Connection
->ToNode
== KSFILTER_NODE
)
243 // node id has a connection
250 // move to next connection
256 *NodeReferenceCount
= 0;
257 *NodeReference
= NULL
;
258 return MM_STATUS_SUCCESS
;
263 /* now allocate node index array */
264 Refs
= (PULONG
)MixerContext
->Alloc(sizeof(ULONG
) * Count
);
268 return MM_STATUS_NO_MEMORY
;
272 Connection
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
273 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
279 if (Connection
->FromNode
== NodeIndex
)
281 /* node id has a connection */
288 if (Connection
->ToNode
== NodeIndex
)
290 /* node id has a connection */
300 if (Connection
->FromNodePin
== NodeIndex
&& Connection
->FromNode
== KSFILTER_NODE
)
302 /* node id has a connection */
309 if (Connection
->ToNodePin
== NodeIndex
&& Connection
->ToNode
== KSFILTER_NODE
)
311 /* node id has a connection */
318 /* move to next connection */
323 *NodeReference
= Refs
;
324 *NodeReferenceCount
= Count
;
326 return MM_STATUS_SUCCESS
;
331 IN PMIXER_CONTEXT MixerContext
,
332 IN PKSMULTIPLE_ITEM NodeTypes
,
333 IN PKSMULTIPLE_ITEM NodeConnections
,
335 IN ULONG bUpDirection
,
339 ULONG NodeConnectionCount
, Index
;
341 PULONG NodeConnection
;
344 ASSERT(NodeIndex
!= (ULONG
)-1);
346 /* get all node indexes referenced by that pin */
348 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, NodeIndex
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
350 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, NodeIndex
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
352 //DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex, Status, NodeConnectionCount);
354 if (Status
== MM_STATUS_SUCCESS
)
356 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
358 Status
= MMixerGetTargetPinsByNodeConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Pins
);
359 ASSERT(Status
== STATUS_SUCCESS
);
361 MixerContext
->Free((PVOID
)NodeConnection
);
368 MMixerGetSourceMixerLineByComponentType(
369 LPMIXER_INFO MixerInfo
,
370 DWORD dwComponentType
)
373 LPMIXERLINE_EXT MixerLineSrc
;
375 /* get first entry */
376 Entry
= MixerInfo
->LineList
.Flink
;
378 while(Entry
!= &MixerInfo
->LineList
)
380 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
381 if (MixerLineSrc
->Line
.dwComponentType
== dwComponentType
)
384 Entry
= Entry
->Flink
;
391 MMixerGetMixerControlById(
392 LPMIXER_INFO MixerInfo
,
394 LPMIXERLINE_EXT
*MixerLine
,
395 LPMIXERCONTROLW
*MixerControl
,
399 LPMIXERLINE_EXT MixerLineSrc
;
402 /* get first entry */
403 Entry
= MixerInfo
->LineList
.Flink
;
405 while(Entry
!= &MixerInfo
->LineList
)
407 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
409 for(Index
= 0; Index
< MixerLineSrc
->Line
.cControls
; Index
++)
411 if (MixerLineSrc
->LineControls
[Index
].dwControlID
== dwControlID
)
414 *MixerLine
= MixerLineSrc
;
416 *MixerControl
= &MixerLineSrc
->LineControls
[Index
];
418 *NodeId
= MixerLineSrc
->NodeIds
[Index
];
419 return MM_STATUS_SUCCESS
;
422 Entry
= Entry
->Flink
;
425 return MM_STATUS_UNSUCCESSFUL
;
429 MMixerGetVolumeControlIndex(
430 LPMIXERVOLUME_DATA VolumeData
,
435 for(Index
= 0; Index
< VolumeData
->ValuesCount
; Index
++)
437 if (VolumeData
->Values
[Index
] > Value
)
439 return VolumeData
->InputSteppingDelta
* Index
;
442 return VolumeData
->InputSteppingDelta
* (VolumeData
->ValuesCount
-1);
446 MMixerSetGetMuteControlDetails(
447 IN PMIXER_CONTEXT MixerContext
,
451 IN LPMIXERCONTROLDETAILS MixerControlDetails
,
454 LPMIXERCONTROLDETAILS_BOOLEAN Input
;
458 if (MixerControlDetails
->cbDetails
!= sizeof(MIXERCONTROLDETAILS_BOOLEAN
))
459 return MM_STATUS_INVALID_PARAMETER
;
462 Input
= (LPMIXERCONTROLDETAILS_BOOLEAN
)MixerControlDetails
->paDetails
;
466 Value
= Input
->fValue
;
468 /* set control details */
469 Status
= MMixerSetGetControlDetails(MixerContext
, hMixer
, NodeId
, bSet
, KSPROPERTY_AUDIO_MUTE
, 0, &Value
);
471 if (Status
!= MM_STATUS_SUCCESS
)
477 Input
->fValue
= Value
;
482 // FIXME notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID
489 MMixerSetGetVolumeControlDetails(
490 IN PMIXER_CONTEXT MixerContext
,
494 LPMIXERCONTROLW MixerControl
,
495 IN LPMIXERCONTROLDETAILS MixerControlDetails
,
496 LPMIXERLINE_EXT MixerLine
)
498 LPMIXERCONTROLDETAILS_UNSIGNED Input
;
499 LONG Value
, Index
, Channel
= 0;
502 LPMIXERVOLUME_DATA VolumeData
;
504 if (MixerControlDetails
->cbDetails
!= sizeof(MIXERCONTROLDETAILS_SIGNED
))
505 return MM_STATUS_INVALID_PARAMETER
;
507 VolumeData
= (LPMIXERVOLUME_DATA
)MMixerGetMixerControlDataById(&MixerLine
->LineControlsExtraData
, MixerControl
->dwControlID
);
509 return MM_STATUS_UNSUCCESSFUL
;
512 Input
= (LPMIXERCONTROLDETAILS_UNSIGNED
)MixerControlDetails
->paDetails
;
517 Value
= Input
->dwValue
;
518 Index
= Value
/ VolumeData
->InputSteppingDelta
;
520 if (Index
>= VolumeData
->ValuesCount
)
522 DPRINT1("Index %u out of bounds %u \n", Index
, VolumeData
->ValuesCount
);
524 return MM_STATUS_INVALID_PARAMETER
;
527 Value
= VolumeData
->Values
[Index
];
530 /* set control details */
533 Status
= MMixerSetGetControlDetails(MixerContext
, hMixer
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 0, &Value
);
534 Status
= MMixerSetGetControlDetails(MixerContext
, hMixer
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 1, &Value
);
538 Status
= MMixerSetGetControlDetails(MixerContext
, hMixer
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, Channel
, &Value
);
543 dwValue
= MMixerGetVolumeControlIndex(VolumeData
, (LONG
)Value
);
545 Input
->dwValue
= dwValue
;
549 /* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */