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}};
34 const GUID KSDATAFORMAT_TYPE_MUSIC
= {0xE725D360L
, 0x62CC, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
35 const GUID KSDATAFORMAT_SUBTYPE_MIDI
= {0x1D262760L
, 0xE957, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
36 const GUID KSDATAFORMAT_SPECIFIER_NONE
= {0x0F6417D6L
, 0xC318, 0x11D0, {0xA4, 0x3F, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
41 IN PMIXER_CONTEXT MixerContext
)
43 if (MixerContext
->SizeOfStruct
!= sizeof(MIXER_CONTEXT
))
44 return MM_STATUS_INVALID_PARAMETER
;
46 if (!MixerContext
->Alloc
|| !MixerContext
->Control
|| !MixerContext
->Free
|| !MixerContext
->Open
||
47 !MixerContext
->AllocEventData
|| !MixerContext
->FreeEventData
||
48 !MixerContext
->Close
|| !MixerContext
->OpenKey
|| !MixerContext
->QueryKeyValue
|| !MixerContext
->CloseKey
)
49 return MM_STATUS_INVALID_PARAMETER
;
51 if (!MixerContext
->MixerContext
)
52 return MM_STATUS_INVALID_PARAMETER
;
54 return MM_STATUS_SUCCESS
;
59 IN PMIXER_CONTEXT MixerContext
,
60 IN LPMIXER_INFO MixerInfo
)
67 MixerContext
->Free((PVOID
)MixerInfo
);
71 MMixerGetMixerInfoByIndex(
72 IN PMIXER_CONTEXT MixerContext
,
75 LPMIXER_INFO MixerInfo
;
77 PMIXER_LIST MixerList
;
81 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
83 if (!MixerList
->MixerListCount
)
86 Entry
= MixerList
->MixerList
.Flink
;
88 while(Entry
!= &MixerList
->MixerList
)
90 MixerInfo
= (LPMIXER_INFO
)CONTAINING_RECORD(Entry
, MIXER_INFO
, Entry
);
92 if (Index
== MixerIndex
)
95 /* move to next mixer entry */
104 MMixerGetMixerByName(
105 IN PMIXER_LIST MixerList
,
107 OUT LPMIXER_INFO
*OutMixerInfo
)
109 LPMIXER_INFO MixerInfo
;
112 Entry
= MixerList
->MixerList
.Flink
;
113 while(Entry
!= &MixerList
->MixerList
)
115 MixerInfo
= (LPMIXER_INFO
)CONTAINING_RECORD(Entry
, MIXER_INFO
, Entry
);
117 DPRINT1("MixerName %S MixerName %S\n", MixerInfo
->MixCaps
.szPname
, MixerName
);
118 if (wcsicmp(MixerInfo
->MixCaps
.szPname
, MixerName
) == 0)
120 *OutMixerInfo
= MixerInfo
;
121 return MM_STATUS_SUCCESS
;
123 /* move to next mixer entry */
124 Entry
= Entry
->Flink
;
127 return MM_STATUS_UNSUCCESSFUL
;
131 MMixerGetSourceMixerLineByLineId(
132 LPMIXER_INFO MixerInfo
,
136 LPMIXERLINE_EXT MixerLineSrc
;
138 /* get first entry */
139 Entry
= MixerInfo
->LineList
.Flink
;
141 while(Entry
!= &MixerInfo
->LineList
)
143 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
144 DPRINT("dwLineID %x dwLineID %x MixerLineSrc %p\n", MixerLineSrc
->Line
.dwLineID
, dwLineID
, MixerLineSrc
);
145 if (MixerLineSrc
->Line
.dwLineID
== dwLineID
)
148 Entry
= Entry
->Flink
;
156 IN PKSMULTIPLE_ITEM MultipleItem
,
161 ASSERT(Index
< MultipleItem
->Count
);
163 NodeType
= (LPGUID
)(MultipleItem
+ 1);
164 return &NodeType
[Index
];
168 MMixerGetSourceMixerLineByComponentType(
169 LPMIXER_INFO MixerInfo
,
170 DWORD dwComponentType
)
173 LPMIXERLINE_EXT MixerLineSrc
;
175 /* get first entry */
176 Entry
= MixerInfo
->LineList
.Flink
;
178 while(Entry
!= &MixerInfo
->LineList
)
180 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
181 if (MixerLineSrc
->Line
.dwComponentType
== dwComponentType
)
184 Entry
= Entry
->Flink
;
191 MMixerGetMixerControlById(
192 LPMIXER_INFO MixerInfo
,
194 LPMIXERLINE_EXT
*OutMixerLine
,
195 LPMIXERCONTROL_EXT
*OutMixerControl
,
198 PLIST_ENTRY Entry
, ControlEntry
;
199 LPMIXERLINE_EXT MixerLineSrc
;
200 LPMIXERCONTROL_EXT MixerControl
;
202 /* get first entry */
203 Entry
= MixerInfo
->LineList
.Flink
;
205 while(Entry
!= &MixerInfo
->LineList
)
207 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
209 ControlEntry
= MixerLineSrc
->ControlsList
.Flink
;
210 while(ControlEntry
!= &MixerLineSrc
->ControlsList
)
212 MixerControl
= (LPMIXERCONTROL_EXT
)CONTAINING_RECORD(ControlEntry
, MIXERCONTROL_EXT
, Entry
);
213 if (MixerControl
->Control
.dwControlID
== dwControlID
)
216 *OutMixerLine
= MixerLineSrc
;
218 *OutMixerControl
= MixerControl
;
220 *NodeId
= MixerControl
->NodeID
;
221 return MM_STATUS_SUCCESS
;
223 ControlEntry
= ControlEntry
->Flink
;
225 Entry
= Entry
->Flink
;
228 return MM_STATUS_UNSUCCESSFUL
;
232 MMixerGetVolumeControlIndex(
233 LPMIXERVOLUME_DATA VolumeData
,
238 for(Index
= 0; Index
< VolumeData
->ValuesCount
; Index
++)
240 if (VolumeData
->Values
[Index
] > Value
)
242 return VolumeData
->InputSteppingDelta
* Index
;
245 return VolumeData
->InputSteppingDelta
* (VolumeData
->ValuesCount
-1);
249 MMixerNotifyControlChange(
250 IN PMIXER_CONTEXT MixerContext
,
251 IN LPMIXER_INFO MixerInfo
,
252 IN ULONG NotificationType
,
256 PEVENT_NOTIFICATION_ENTRY NotificationEntry
;
258 /* enumerate list and add a notification entry */
259 Entry
= MixerInfo
->EventList
.Flink
;
260 while(Entry
!= &MixerInfo
->EventList
)
262 /* get notification entry offset */
263 NotificationEntry
= (PEVENT_NOTIFICATION_ENTRY
)CONTAINING_RECORD(Entry
, EVENT_NOTIFICATION_ENTRY
, Entry
);
265 if (NotificationEntry
->MixerEventRoutine
)
267 /* now perform the callback */
268 NotificationEntry
->MixerEventRoutine(NotificationEntry
->MixerEventContext
, (HANDLE
)MixerInfo
, NotificationType
, Value
);
271 /* move to next notification entry */
272 Entry
= Entry
->Flink
;
277 MMixerSetGetMuteControlDetails(
278 IN PMIXER_CONTEXT MixerContext
,
279 IN LPMIXER_INFO MixerInfo
,
280 IN LPMIXERCONTROL_EXT MixerControl
,
282 IN LPMIXERCONTROLDETAILS MixerControlDetails
,
285 LPMIXERCONTROLDETAILS_BOOLEAN Input
;
289 if (MixerControlDetails
->cbDetails
!= sizeof(MIXERCONTROLDETAILS_BOOLEAN
))
290 return MM_STATUS_INVALID_PARAMETER
;
293 Input
= (LPMIXERCONTROLDETAILS_BOOLEAN
)MixerControlDetails
->paDetails
;
297 Value
= Input
->fValue
;
299 /* set control details */
300 Status
= MMixerSetGetControlDetails(MixerContext
, MixerControl
->hDevice
, MixerControl
->NodeID
, bSet
, KSPROPERTY_AUDIO_MUTE
, 0, &Value
);
302 if (Status
!= MM_STATUS_SUCCESS
)
308 Input
->fValue
= Value
;
313 /* notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID */
314 MMixerNotifyControlChange(MixerContext
, MixerInfo
, MM_MIXM_LINE_CHANGE
, dwLineID
);
321 MMixerSetGetVolumeControlDetails(
322 IN PMIXER_CONTEXT MixerContext
,
323 IN LPMIXER_INFO MixerInfo
,
326 LPMIXERCONTROL_EXT MixerControl
,
327 IN LPMIXERCONTROLDETAILS MixerControlDetails
,
328 LPMIXERLINE_EXT MixerLine
)
330 LPMIXERCONTROLDETAILS_UNSIGNED Input
;
331 LONG Value
, Index
, Channel
= 0;
334 LPMIXERVOLUME_DATA VolumeData
;
336 if (MixerControlDetails
->cbDetails
!= sizeof(MIXERCONTROLDETAILS_SIGNED
))
337 return MM_STATUS_INVALID_PARAMETER
;
339 VolumeData
= (LPMIXERVOLUME_DATA
)MixerControl
->ExtraData
;
341 return MM_STATUS_UNSUCCESSFUL
;
344 Input
= (LPMIXERCONTROLDETAILS_UNSIGNED
)MixerControlDetails
->paDetails
;
349 Value
= Input
->dwValue
;
350 Index
= Value
/ VolumeData
->InputSteppingDelta
;
352 if (Index
>= VolumeData
->ValuesCount
)
354 DPRINT1("Index %u out of bounds %u \n", Index
, VolumeData
->ValuesCount
);
355 return MM_STATUS_INVALID_PARAMETER
;
358 Value
= VolumeData
->Values
[Index
];
361 /* set control details */
365 Status
= MMixerSetGetControlDetails(MixerContext
, MixerControl
->hDevice
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 0, &Value
);
366 Status
= MMixerSetGetControlDetails(MixerContext
, MixerControl
->hDevice
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 1, &Value
);
370 Status
= MMixerSetGetControlDetails(MixerContext
, MixerControl
->hDevice
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, Channel
, &Value
);
375 dwValue
= MMixerGetVolumeControlIndex(VolumeData
, (LONG
)Value
);
377 Input
->dwValue
= dwValue
;
381 /* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */
382 MMixerNotifyControlChange(MixerContext
, MixerInfo
, MM_MIXM_CONTROL_CHANGE
, MixerControl
->Control
.dwControlID
);
388 MMixerGetDataByDeviceId(
389 IN PMIXER_LIST MixerList
,
393 LPMIXER_DATA MixerData
;
395 Entry
= MixerList
->MixerData
.Flink
;
396 while(Entry
!= &MixerList
->MixerData
)
398 MixerData
= (LPMIXER_DATA
)CONTAINING_RECORD(Entry
, MIXER_DATA
, Entry
);
399 if (MixerData
->DeviceId
== DeviceId
)
403 Entry
= Entry
->Flink
;
409 MMixerGetDataByDeviceName(
410 IN PMIXER_LIST MixerList
,
411 IN LPWSTR DeviceName
)
414 LPMIXER_DATA MixerData
;
416 Entry
= MixerList
->MixerData
.Flink
;
417 while(Entry
!= &MixerList
->MixerData
)
419 MixerData
= (LPMIXER_DATA
)CONTAINING_RECORD(Entry
, MIXER_DATA
, Entry
);
420 if (wcsicmp(&DeviceName
[2], &MixerData
->DeviceName
[2]) == 0)
425 Entry
= Entry
->Flink
;
431 MMixerCreateMixerData(
432 IN PMIXER_CONTEXT MixerContext
,
433 IN PMIXER_LIST MixerList
,
435 IN LPWSTR DeviceName
,
439 LPMIXER_DATA MixerData
;
441 MixerData
= (LPMIXER_DATA
)MixerContext
->Alloc(sizeof(MIXER_DATA
));
443 return MM_STATUS_NO_MEMORY
;
445 MixerData
->DeviceId
= DeviceId
;
446 MixerData
->DeviceName
= DeviceName
;
447 MixerData
->hDevice
= hDevice
;
448 MixerData
->hDeviceInterfaceKey
= hKey
;
449 MixerData
->Topology
= NULL
;
451 InsertTailList(&MixerList
->MixerData
, &MixerData
->Entry
);
452 MixerList
->MixerDataCount
++;
453 return MM_STATUS_SUCCESS
;
458 IN PMIXER_CONTEXT MixerContext
,
459 OUT LPWSTR DeviceName
,
468 Status
= MixerContext
->QueryKeyValue(hKey
, L
"FriendlyName", (PVOID
*)&Name
, &Length
, &Type
);
469 if (Status
== MM_STATUS_SUCCESS
)
471 /* copy device name */
472 MixerContext
->Copy(DeviceName
, Name
, min(wcslen(Name
), MAXPNAMELEN
-1) * sizeof(WCHAR
));
474 /* make sure its null terminated */
475 DeviceName
[MAXPNAMELEN
-1] = L
'\0';
477 /* free device name */
478 MixerContext
->Free(Name
);
484 Status
= MixerContext
->OpenKey(hKey
, L
"Device Parameters", KEY_READ
, &hTemp
);
485 if (Status
!= MM_STATUS_SUCCESS
)
488 Status
= MixerContext
->QueryKeyValue(hTemp
, L
"FriendlyName", (PVOID
*)&Name
, &Length
, &Type
);
489 if (Status
== MM_STATUS_SUCCESS
)
491 /* copy device name */
492 MixerContext
->Copy(DeviceName
, Name
, min(wcslen(Name
), MAXPNAMELEN
-1) * sizeof(WCHAR
));
494 /* make sure its null terminated */
495 DeviceName
[MAXPNAMELEN
-1] = L
'\0';
497 /* free device name */
498 MixerContext
->Free(Name
);
501 MixerContext
->CloseKey(hTemp
);
506 MMixerInitializePinConnect(
507 IN OUT PKSPIN_CONNECT PinConnect
,
510 PinConnect
->Interface
.Set
= KSINTERFACESETID_Standard
;
511 PinConnect
->Interface
.Id
= KSINTERFACE_STANDARD_STREAMING
;
512 PinConnect
->Interface
.Flags
= 0;
513 PinConnect
->Medium
.Set
= KSMEDIUMSETID_Standard
;
514 PinConnect
->Medium
.Id
= KSMEDIUM_TYPE_ANYINSTANCE
;
515 PinConnect
->Medium
.Flags
= 0;
516 PinConnect
->PinToHandle
= NULL
;
517 PinConnect
->PinId
= PinId
;
518 PinConnect
->Priority
.PriorityClass
= KSPRIORITY_NORMAL
;
519 PinConnect
->Priority
.PrioritySubClass
= 1;