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
||
41 !MixerContext
->Close
|| !MixerContext
->OpenKey
|| !MixerContext
->QueryKeyValue
|| !MixerContext
->CloseKey
)
42 return MM_STATUS_INVALID_PARAMETER
;
44 if (!MixerContext
->MixerContext
)
45 return MM_STATUS_INVALID_PARAMETER
;
47 return MM_STATUS_SUCCESS
;
52 IN PMIXER_CONTEXT MixerContext
,
53 IN LPMIXER_INFO MixerInfo
)
59 MixerContext
->Free((PVOID
)MixerInfo
);
63 MMixerGetMixerInfoByIndex(
64 IN PMIXER_CONTEXT MixerContext
,
67 LPMIXER_INFO MixerInfo
;
69 PMIXER_LIST MixerList
;
73 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
75 if (!MixerList
->MixerListCount
)
78 Entry
= MixerList
->MixerList
.Flink
;
80 while(Entry
!= &MixerList
->MixerList
)
82 MixerInfo
= (LPMIXER_INFO
)CONTAINING_RECORD(Entry
, MIXER_INFO
, Entry
);
84 if (Index
== MixerIndex
)
87 // move to next mixer entry
96 MMixerGetMixerControlDataById(
101 LPMIXERCONTROL_DATA Control
;
103 /* get first entry */
104 Entry
= ListHead
->Flink
;
106 while(Entry
!= ListHead
)
108 Control
= (LPMIXERCONTROL_DATA
)CONTAINING_RECORD(Entry
, MIXERCONTROL_DATA
, Entry
);
109 DPRINT("dwSource %x dwSource %x\n", Control
->dwControlID
, dwControlId
);
110 if (Control
->dwControlID
== dwControlId
)
113 Entry
= Entry
->Flink
;
119 MMixerGetSourceMixerLineByLineId(
120 LPMIXER_INFO MixerInfo
,
124 LPMIXERLINE_EXT MixerLineSrc
;
126 /* get first entry */
127 Entry
= MixerInfo
->LineList
.Flink
;
129 while(Entry
!= &MixerInfo
->LineList
)
131 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
132 DPRINT("dwLineID %x dwLineID %x\n", MixerLineSrc
->Line
.dwLineID
, dwLineID
);
133 if (MixerLineSrc
->Line
.dwLineID
== dwLineID
)
136 Entry
= Entry
->Flink
;
143 MMixerGetIndexOfGuid(
144 PKSMULTIPLE_ITEM MultipleItem
,
150 Guid
= (LPGUID
)(MultipleItem
+1);
152 /* iterate through node type array */
153 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
155 if (IsEqualGUIDAligned(NodeType
, Guid
))
157 /* found matching guid */
165 PKSTOPOLOGY_CONNECTION
166 MMixerGetConnectionByIndex(
167 IN PKSMULTIPLE_ITEM MultipleItem
,
170 PKSTOPOLOGY_CONNECTION Descriptor
;
172 ASSERT(Index
< MultipleItem
->Count
);
174 Descriptor
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
175 return &Descriptor
[Index
];
180 IN PKSMULTIPLE_ITEM MultipleItem
,
185 ASSERT(Index
< MultipleItem
->Count
);
187 NodeType
= (LPGUID
)(MultipleItem
+ 1);
188 return &NodeType
[Index
];
192 MMixerGetNodeIndexes(
193 IN PMIXER_CONTEXT MixerContext
,
194 IN PKSMULTIPLE_ITEM MultipleItem
,
198 OUT PULONG NodeReferenceCount
,
199 OUT PULONG
*NodeReference
)
201 ULONG Index
, Count
= 0;
202 PKSTOPOLOGY_CONNECTION Connection
;
205 // KSMULTIPLE_ITEM is followed by several KSTOPOLOGY_CONNECTION
206 Connection
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
208 // first count all referenced nodes
209 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
215 if (Connection
->FromNode
== NodeIndex
)
217 // node id has a connection
223 if (Connection
->ToNode
== NodeIndex
)
225 // node id has a connection
234 if (Connection
->FromNodePin
== NodeIndex
&& Connection
->FromNode
== KSFILTER_NODE
)
236 // node id has a connection
242 if (Connection
->ToNodePin
== NodeIndex
&& Connection
->ToNode
== KSFILTER_NODE
)
244 // node id has a connection
251 // move to next connection
257 *NodeReferenceCount
= 0;
258 *NodeReference
= NULL
;
259 return MM_STATUS_SUCCESS
;
264 /* now allocate node index array */
265 Refs
= (PULONG
)MixerContext
->Alloc(sizeof(ULONG
) * Count
);
269 return MM_STATUS_NO_MEMORY
;
273 Connection
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
274 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
280 if (Connection
->FromNode
== NodeIndex
)
282 /* node id has a connection */
289 if (Connection
->ToNode
== NodeIndex
)
291 /* node id has a connection */
301 if (Connection
->FromNodePin
== NodeIndex
&& Connection
->FromNode
== KSFILTER_NODE
)
303 /* node id has a connection */
310 if (Connection
->ToNodePin
== NodeIndex
&& Connection
->ToNode
== KSFILTER_NODE
)
312 /* node id has a connection */
319 /* move to next connection */
324 *NodeReference
= Refs
;
325 *NodeReferenceCount
= Count
;
327 return MM_STATUS_SUCCESS
;
332 IN PMIXER_CONTEXT MixerContext
,
333 IN PKSMULTIPLE_ITEM NodeTypes
,
334 IN PKSMULTIPLE_ITEM NodeConnections
,
336 IN ULONG bUpDirection
,
340 ULONG NodeConnectionCount
, Index
;
342 PULONG NodeConnection
;
345 ASSERT(NodeIndex
!= (ULONG
)-1);
347 /* get all node indexes referenced by that pin */
349 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, NodeIndex
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
351 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, NodeIndex
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
353 //DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex, Status, NodeConnectionCount);
355 if (Status
== MM_STATUS_SUCCESS
)
357 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
359 Status
= MMixerGetTargetPinsByNodeConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Pins
);
360 ASSERT(Status
== STATUS_SUCCESS
);
362 MixerContext
->Free((PVOID
)NodeConnection
);
369 MMixerGetSourceMixerLineByComponentType(
370 LPMIXER_INFO MixerInfo
,
371 DWORD dwComponentType
)
374 LPMIXERLINE_EXT MixerLineSrc
;
376 /* get first entry */
377 Entry
= MixerInfo
->LineList
.Flink
;
379 while(Entry
!= &MixerInfo
->LineList
)
381 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
382 if (MixerLineSrc
->Line
.dwComponentType
== dwComponentType
)
385 Entry
= Entry
->Flink
;
392 MMixerGetMixerControlById(
393 LPMIXER_INFO MixerInfo
,
395 LPMIXERLINE_EXT
*MixerLine
,
396 LPMIXERCONTROLW
*MixerControl
,
400 LPMIXERLINE_EXT MixerLineSrc
;
403 /* get first entry */
404 Entry
= MixerInfo
->LineList
.Flink
;
406 while(Entry
!= &MixerInfo
->LineList
)
408 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
410 for(Index
= 0; Index
< MixerLineSrc
->Line
.cControls
; Index
++)
412 if (MixerLineSrc
->LineControls
[Index
].dwControlID
== dwControlID
)
415 *MixerLine
= MixerLineSrc
;
417 *MixerControl
= &MixerLineSrc
->LineControls
[Index
];
419 *NodeId
= MixerLineSrc
->NodeIds
[Index
];
420 return MM_STATUS_SUCCESS
;
423 Entry
= Entry
->Flink
;
426 return MM_STATUS_UNSUCCESSFUL
;
430 MMixerGetVolumeControlIndex(
431 LPMIXERVOLUME_DATA VolumeData
,
436 for(Index
= 0; Index
< VolumeData
->ValuesCount
; Index
++)
438 if (VolumeData
->Values
[Index
] > Value
)
440 return VolumeData
->InputSteppingDelta
* Index
;
443 return VolumeData
->InputSteppingDelta
* (VolumeData
->ValuesCount
-1);
447 MMixerSetGetMuteControlDetails(
448 IN PMIXER_CONTEXT MixerContext
,
452 IN LPMIXERCONTROLDETAILS MixerControlDetails
,
455 LPMIXERCONTROLDETAILS_BOOLEAN Input
;
459 if (MixerControlDetails
->cbDetails
!= sizeof(MIXERCONTROLDETAILS_BOOLEAN
))
460 return MM_STATUS_INVALID_PARAMETER
;
463 Input
= (LPMIXERCONTROLDETAILS_BOOLEAN
)MixerControlDetails
->paDetails
;
467 Value
= Input
->fValue
;
469 /* set control details */
470 Status
= MMixerSetGetControlDetails(MixerContext
, hMixer
, NodeId
, bSet
, KSPROPERTY_AUDIO_MUTE
, 0, &Value
);
472 if (Status
!= MM_STATUS_SUCCESS
)
478 Input
->fValue
= Value
;
483 // FIXME notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID
490 MMixerSetGetVolumeControlDetails(
491 IN PMIXER_CONTEXT MixerContext
,
495 LPMIXERCONTROLW MixerControl
,
496 IN LPMIXERCONTROLDETAILS MixerControlDetails
,
497 LPMIXERLINE_EXT MixerLine
)
499 LPMIXERCONTROLDETAILS_UNSIGNED Input
;
500 LONG Value
, Index
, Channel
= 0;
503 LPMIXERVOLUME_DATA VolumeData
;
505 if (MixerControlDetails
->cbDetails
!= sizeof(MIXERCONTROLDETAILS_SIGNED
))
506 return MM_STATUS_INVALID_PARAMETER
;
508 VolumeData
= (LPMIXERVOLUME_DATA
)MMixerGetMixerControlDataById(&MixerLine
->LineControlsExtraData
, MixerControl
->dwControlID
);
510 return MM_STATUS_UNSUCCESSFUL
;
513 Input
= (LPMIXERCONTROLDETAILS_UNSIGNED
)MixerControlDetails
->paDetails
;
518 Value
= Input
->dwValue
;
519 Index
= Value
/ VolumeData
->InputSteppingDelta
;
521 if (Index
>= VolumeData
->ValuesCount
)
523 DPRINT1("Index %u out of bounds %u \n", Index
, VolumeData
->ValuesCount
);
525 return MM_STATUS_INVALID_PARAMETER
;
528 Value
= VolumeData
->Values
[Index
];
531 /* set control details */
535 Status
= MMixerSetGetControlDetails(MixerContext
, hMixer
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 0, &Value
);
536 Status
= MMixerSetGetControlDetails(MixerContext
, hMixer
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 1, &Value
);
540 Status
= MMixerSetGetControlDetails(MixerContext
, hMixer
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, Channel
, &Value
);
545 dwValue
= MMixerGetVolumeControlIndex(VolumeData
, (LONG
)Value
);
547 Input
->dwValue
= dwValue
;
551 /* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */
557 MMixerGetDataByDeviceId(
558 IN PMIXER_LIST MixerList
,
562 LPMIXER_DATA MixerData
;
564 Entry
= MixerList
->MixerData
.Flink
;
565 while(Entry
!= &MixerList
->MixerData
)
567 MixerData
= (LPMIXER_DATA
)CONTAINING_RECORD(Entry
, MIXER_DATA
, Entry
);
568 if (MixerData
->DeviceId
== DeviceId
)
572 Entry
= Entry
->Flink
;
578 MMixerGetDataByDeviceName(
579 IN PMIXER_LIST MixerList
,
580 IN LPWSTR DeviceName
)
583 LPMIXER_DATA MixerData
;
585 Entry
= MixerList
->MixerData
.Flink
;
586 while(Entry
!= &MixerList
->MixerData
)
588 MixerData
= (LPMIXER_DATA
)CONTAINING_RECORD(Entry
, MIXER_DATA
, Entry
);
589 if (wcsicmp(DeviceName
, MixerData
->DeviceName
) == 0)
594 Entry
= Entry
->Flink
;
600 MMixerCreateMixerData(
601 IN PMIXER_CONTEXT MixerContext
,
602 IN PMIXER_LIST MixerList
,
604 IN LPWSTR DeviceName
,
608 LPMIXER_DATA MixerData
;
610 MixerData
= (LPMIXER_DATA
)MixerContext
->Alloc(sizeof(MIXER_DATA
));
612 return MM_STATUS_NO_MEMORY
;
614 MixerData
->DeviceId
= DeviceId
;
615 MixerData
->DeviceName
= DeviceName
;
616 MixerData
->hDevice
= hDevice
;
617 MixerData
->hDeviceInterfaceKey
= hKey
;
619 InsertTailList(&MixerList
->MixerData
, &MixerData
->Entry
);
620 MixerList
->MixerDataCount
++;
621 return MM_STATUS_SUCCESS
;
626 IN PMIXER_CONTEXT MixerContext
,
627 IN LPMIXER_INFO MixerInfo
,
636 Status
= MixerContext
->QueryKeyValue(hKey
, L
"FriendlyName", (PVOID
*)&Name
, &Length
, &Type
);
637 if (Status
== MM_STATUS_SUCCESS
)
639 wcscpy(MixerInfo
->MixCaps
.szPname
, Name
);
640 MixerContext
->Free(Name
);
644 Status
= MixerContext
->OpenKey(hKey
, L
"Device Parameters", KEY_READ
, &hTemp
);
645 if (Status
!= MM_STATUS_SUCCESS
)
648 Status
= MixerContext
->QueryKeyValue(hKey
, L
"FriendlyName", (PVOID
*)&Name
, &Length
, &Type
);
649 if (Status
== MM_STATUS_SUCCESS
)
651 wcscpy(MixerInfo
->MixCaps
.szPname
, Name
);
652 MixerContext
->Free(Name
);
655 MixerContext
->CloseKey(hTemp
);