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}};
32 const GUID KSEVENTSETID_AudioControlChange
= {0xE85E9698L
, 0xFA2F, 0x11D1, {0x95, 0xBD, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3}};
36 IN PMIXER_CONTEXT MixerContext
)
38 if (MixerContext
->SizeOfStruct
!= sizeof(MIXER_CONTEXT
))
39 return MM_STATUS_INVALID_PARAMETER
;
41 if (!MixerContext
->Alloc
|| !MixerContext
->Control
|| !MixerContext
->Free
|| !MixerContext
->Open
||
42 !MixerContext
->AllocEventData
|| !MixerContext
->FreeEventData
||
43 !MixerContext
->Close
|| !MixerContext
->OpenKey
|| !MixerContext
->QueryKeyValue
|| !MixerContext
->CloseKey
)
44 return MM_STATUS_INVALID_PARAMETER
;
46 if (!MixerContext
->MixerContext
)
47 return MM_STATUS_INVALID_PARAMETER
;
49 return MM_STATUS_SUCCESS
;
54 IN PMIXER_CONTEXT MixerContext
,
55 IN LPMIXER_INFO MixerInfo
)
61 MixerContext
->Free((PVOID
)MixerInfo
);
65 MMixerGetMixerInfoByIndex(
66 IN PMIXER_CONTEXT MixerContext
,
69 LPMIXER_INFO MixerInfo
;
71 PMIXER_LIST MixerList
;
75 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
77 if (!MixerList
->MixerListCount
)
80 Entry
= MixerList
->MixerList
.Flink
;
82 while(Entry
!= &MixerList
->MixerList
)
84 MixerInfo
= (LPMIXER_INFO
)CONTAINING_RECORD(Entry
, MIXER_INFO
, Entry
);
86 if (Index
== MixerIndex
)
89 // move to next mixer entry
98 MMixerGetMixerControlDataById(
103 LPMIXERCONTROL_DATA Control
;
105 /* get first entry */
106 Entry
= ListHead
->Flink
;
108 while(Entry
!= ListHead
)
110 Control
= (LPMIXERCONTROL_DATA
)CONTAINING_RECORD(Entry
, MIXERCONTROL_DATA
, Entry
);
111 DPRINT("dwSource %x dwSource %x\n", Control
->dwControlID
, dwControlId
);
112 if (Control
->dwControlID
== dwControlId
)
115 Entry
= Entry
->Flink
;
121 MMixerGetSourceMixerLineByLineId(
122 LPMIXER_INFO MixerInfo
,
126 LPMIXERLINE_EXT MixerLineSrc
;
128 /* get first entry */
129 Entry
= MixerInfo
->LineList
.Flink
;
131 while(Entry
!= &MixerInfo
->LineList
)
133 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
134 DPRINT("dwLineID %x dwLineID %x MixerLineSrc %p\n", MixerLineSrc
->Line
.dwLineID
, dwLineID
, MixerLineSrc
);
135 if (MixerLineSrc
->Line
.dwLineID
== dwLineID
)
138 Entry
= Entry
->Flink
;
145 MMixerGetIndexOfGuid(
146 PKSMULTIPLE_ITEM MultipleItem
,
152 Guid
= (LPGUID
)(MultipleItem
+1);
154 /* iterate through node type array */
155 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
157 if (IsEqualGUIDAligned(NodeType
, Guid
))
159 /* found matching guid */
167 PKSTOPOLOGY_CONNECTION
168 MMixerGetConnectionByIndex(
169 IN PKSMULTIPLE_ITEM MultipleItem
,
172 PKSTOPOLOGY_CONNECTION Descriptor
;
174 ASSERT(Index
< MultipleItem
->Count
);
176 Descriptor
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
177 return &Descriptor
[Index
];
182 IN PKSMULTIPLE_ITEM MultipleItem
,
187 ASSERT(Index
< MultipleItem
->Count
);
189 NodeType
= (LPGUID
)(MultipleItem
+ 1);
190 return &NodeType
[Index
];
194 MMixerGetNodeIndexes(
195 IN PMIXER_CONTEXT MixerContext
,
196 IN PKSMULTIPLE_ITEM MultipleItem
,
200 OUT PULONG NodeReferenceCount
,
201 OUT PULONG
*NodeReference
)
203 ULONG Index
, Count
= 0;
204 PKSTOPOLOGY_CONNECTION Connection
;
207 // KSMULTIPLE_ITEM is followed by several KSTOPOLOGY_CONNECTION
208 Connection
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
210 // first count all referenced nodes
211 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
217 if (Connection
->FromNode
== NodeIndex
)
219 // node id has a connection
225 if (Connection
->ToNode
== NodeIndex
)
227 // node id has a connection
236 if (Connection
->FromNodePin
== NodeIndex
&& Connection
->FromNode
== KSFILTER_NODE
)
238 // node id has a connection
244 if (Connection
->ToNodePin
== NodeIndex
&& Connection
->ToNode
== KSFILTER_NODE
)
246 // node id has a connection
253 // move to next connection
259 *NodeReferenceCount
= 0;
260 *NodeReference
= NULL
;
261 return MM_STATUS_SUCCESS
;
266 /* now allocate node index array */
267 Refs
= (PULONG
)MixerContext
->Alloc(sizeof(ULONG
) * Count
);
271 return MM_STATUS_NO_MEMORY
;
275 Connection
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
276 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
282 if (Connection
->FromNode
== NodeIndex
)
284 /* node id has a connection */
291 if (Connection
->ToNode
== NodeIndex
)
293 /* node id has a connection */
303 if (Connection
->FromNodePin
== NodeIndex
&& Connection
->FromNode
== KSFILTER_NODE
)
305 /* node id has a connection */
312 if (Connection
->ToNodePin
== NodeIndex
&& Connection
->ToNode
== KSFILTER_NODE
)
314 /* node id has a connection */
321 /* move to next connection */
326 *NodeReference
= Refs
;
327 *NodeReferenceCount
= Count
;
329 return MM_STATUS_SUCCESS
;
334 IN PMIXER_CONTEXT MixerContext
,
335 IN PKSMULTIPLE_ITEM NodeTypes
,
336 IN PKSMULTIPLE_ITEM NodeConnections
,
338 IN ULONG bUpDirection
,
342 ULONG NodeConnectionCount
, Index
;
344 PULONG NodeConnection
;
347 ASSERT(NodeIndex
!= (ULONG
)-1);
349 /* get all node indexes referenced by that pin */
351 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, NodeIndex
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
353 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, NodeIndex
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
355 //DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex, Status, NodeConnectionCount);
357 if (Status
== MM_STATUS_SUCCESS
)
359 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
361 Status
= MMixerGetTargetPinsByNodeConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], PinCount
, Pins
);
362 ASSERT(Status
== STATUS_SUCCESS
);
364 MixerContext
->Free((PVOID
)NodeConnection
);
371 MMixerGetSourceMixerLineByComponentType(
372 LPMIXER_INFO MixerInfo
,
373 DWORD dwComponentType
)
376 LPMIXERLINE_EXT MixerLineSrc
;
378 /* get first entry */
379 Entry
= MixerInfo
->LineList
.Flink
;
381 while(Entry
!= &MixerInfo
->LineList
)
383 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
384 if (MixerLineSrc
->Line
.dwComponentType
== dwComponentType
)
387 Entry
= Entry
->Flink
;
394 MMixerGetMixerControlById(
395 LPMIXER_INFO MixerInfo
,
397 LPMIXERLINE_EXT
*MixerLine
,
398 LPMIXERCONTROLW
*MixerControl
,
402 LPMIXERLINE_EXT MixerLineSrc
;
405 /* get first entry */
406 Entry
= MixerInfo
->LineList
.Flink
;
408 while(Entry
!= &MixerInfo
->LineList
)
410 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
412 for(Index
= 0; Index
< MixerLineSrc
->Line
.cControls
; Index
++)
414 if (MixerLineSrc
->LineControls
[Index
].dwControlID
== dwControlID
)
417 *MixerLine
= MixerLineSrc
;
419 *MixerControl
= &MixerLineSrc
->LineControls
[Index
];
421 *NodeId
= MixerLineSrc
->NodeIds
[Index
];
422 return MM_STATUS_SUCCESS
;
425 Entry
= Entry
->Flink
;
428 return MM_STATUS_UNSUCCESSFUL
;
432 MMixerGetVolumeControlIndex(
433 LPMIXERVOLUME_DATA VolumeData
,
438 for(Index
= 0; Index
< VolumeData
->ValuesCount
; Index
++)
440 if (VolumeData
->Values
[Index
] > Value
)
442 return VolumeData
->InputSteppingDelta
* Index
;
445 return VolumeData
->InputSteppingDelta
* (VolumeData
->ValuesCount
-1);
449 MMixerSetGetMuteControlDetails(
450 IN PMIXER_CONTEXT MixerContext
,
454 IN LPMIXERCONTROLDETAILS MixerControlDetails
,
457 LPMIXERCONTROLDETAILS_BOOLEAN Input
;
461 if (MixerControlDetails
->cbDetails
!= sizeof(MIXERCONTROLDETAILS_BOOLEAN
))
462 return MM_STATUS_INVALID_PARAMETER
;
465 Input
= (LPMIXERCONTROLDETAILS_BOOLEAN
)MixerControlDetails
->paDetails
;
469 Value
= Input
->fValue
;
471 /* set control details */
472 Status
= MMixerSetGetControlDetails(MixerContext
, hMixer
, NodeId
, bSet
, KSPROPERTY_AUDIO_MUTE
, 0, &Value
);
474 if (Status
!= MM_STATUS_SUCCESS
)
480 Input
->fValue
= Value
;
485 // FIXME notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID
492 MMixerSetGetVolumeControlDetails(
493 IN PMIXER_CONTEXT MixerContext
,
497 LPMIXERCONTROLW MixerControl
,
498 IN LPMIXERCONTROLDETAILS MixerControlDetails
,
499 LPMIXERLINE_EXT MixerLine
)
501 LPMIXERCONTROLDETAILS_UNSIGNED Input
;
502 LONG Value
, Index
, Channel
= 0;
505 LPMIXERVOLUME_DATA VolumeData
;
507 if (MixerControlDetails
->cbDetails
!= sizeof(MIXERCONTROLDETAILS_SIGNED
))
508 return MM_STATUS_INVALID_PARAMETER
;
510 VolumeData
= (LPMIXERVOLUME_DATA
)MMixerGetMixerControlDataById(&MixerLine
->LineControlsExtraData
, MixerControl
->dwControlID
);
512 return MM_STATUS_UNSUCCESSFUL
;
515 Input
= (LPMIXERCONTROLDETAILS_UNSIGNED
)MixerControlDetails
->paDetails
;
520 Value
= Input
->dwValue
;
521 Index
= Value
/ VolumeData
->InputSteppingDelta
;
523 if (Index
>= VolumeData
->ValuesCount
)
525 DPRINT1("Index %u out of bounds %u \n", Index
, VolumeData
->ValuesCount
);
527 return MM_STATUS_INVALID_PARAMETER
;
530 Value
= VolumeData
->Values
[Index
];
533 /* set control details */
537 Status
= MMixerSetGetControlDetails(MixerContext
, hMixer
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 0, &Value
);
538 Status
= MMixerSetGetControlDetails(MixerContext
, hMixer
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 1, &Value
);
542 Status
= MMixerSetGetControlDetails(MixerContext
, hMixer
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, Channel
, &Value
);
547 dwValue
= MMixerGetVolumeControlIndex(VolumeData
, (LONG
)Value
);
549 Input
->dwValue
= dwValue
;
553 /* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */
559 MMixerGetDataByDeviceId(
560 IN PMIXER_LIST MixerList
,
564 LPMIXER_DATA MixerData
;
566 Entry
= MixerList
->MixerData
.Flink
;
567 while(Entry
!= &MixerList
->MixerData
)
569 MixerData
= (LPMIXER_DATA
)CONTAINING_RECORD(Entry
, MIXER_DATA
, Entry
);
570 if (MixerData
->DeviceId
== DeviceId
)
574 Entry
= Entry
->Flink
;
580 MMixerGetDataByDeviceName(
581 IN PMIXER_LIST MixerList
,
582 IN LPWSTR DeviceName
)
585 LPMIXER_DATA MixerData
;
587 Entry
= MixerList
->MixerData
.Flink
;
588 while(Entry
!= &MixerList
->MixerData
)
590 MixerData
= (LPMIXER_DATA
)CONTAINING_RECORD(Entry
, MIXER_DATA
, Entry
);
591 if (wcsicmp(&DeviceName
[2], &MixerData
->DeviceName
[2]) == 0)
596 Entry
= Entry
->Flink
;
602 MMixerCreateMixerData(
603 IN PMIXER_CONTEXT MixerContext
,
604 IN PMIXER_LIST MixerList
,
606 IN LPWSTR DeviceName
,
610 LPMIXER_DATA MixerData
;
612 MixerData
= (LPMIXER_DATA
)MixerContext
->Alloc(sizeof(MIXER_DATA
));
614 return MM_STATUS_NO_MEMORY
;
616 MixerData
->DeviceId
= DeviceId
;
617 MixerData
->DeviceName
= DeviceName
;
618 MixerData
->hDevice
= hDevice
;
619 MixerData
->hDeviceInterfaceKey
= hKey
;
621 InsertTailList(&MixerList
->MixerData
, &MixerData
->Entry
);
622 MixerList
->MixerDataCount
++;
623 return MM_STATUS_SUCCESS
;
628 IN PMIXER_CONTEXT MixerContext
,
629 IN LPMIXER_INFO MixerInfo
,
638 Status
= MixerContext
->QueryKeyValue(hKey
, L
"FriendlyName", (PVOID
*)&Name
, &Length
, &Type
);
639 if (Status
== MM_STATUS_SUCCESS
)
642 MixerContext
->Copy(MixerInfo
->MixCaps
.szPname
, Name
, min(wcslen(Name
), MAXPNAMELEN
-1) * sizeof(WCHAR
));
644 // make sure its null terminated
645 MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] = L
'\0';
648 MixerContext
->Free(Name
);
654 Status
= MixerContext
->OpenKey(hKey
, L
"Device Parameters", KEY_READ
, &hTemp
);
655 if (Status
!= MM_STATUS_SUCCESS
)
658 Status
= MixerContext
->QueryKeyValue(hKey
, L
"FriendlyName", (PVOID
*)&Name
, &Length
, &Type
);
659 if (Status
== MM_STATUS_SUCCESS
)
662 MixerContext
->Copy(MixerInfo
->MixCaps
.szPname
, Name
, min(wcslen(Name
), MAXPNAMELEN
-1) * sizeof(WCHAR
));
664 // make sure its null terminated
665 MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] = L
'\0';
668 MixerContext
->Free(Name
);
671 MixerContext
->CloseKey(hTemp
);