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
14 const GUID KSNODETYPE_SUM
= {0xDA441A60L
, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
15 const GUID KSNODETYPE_DAC
= {0x507AE360L
, 0xC554, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
16 const GUID KSNODETYPE_ADC
= {0x4D837FE0L
, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
17 const GUID KSNODETYPE_AGC
= {0xE88C9BA0L
, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
18 const GUID KSNODETYPE_LOUDNESS
= {0x41887440L
, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
19 const GUID KSNODETYPE_MUTE
= {0x02B223C0L
, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
20 const GUID KSNODETYPE_TONE
= {0x7607E580L
, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
21 const GUID KSNODETYPE_VOLUME
= {0x3A5ACC00L
, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
22 const GUID KSNODETYPE_PEAKMETER
= {0xa085651e, 0x5f0d, 0x4b36, {0xa8, 0x69, 0xd1, 0x95, 0xd6, 0xab, 0x4b, 0x9e}};
23 const GUID KSNODETYPE_MUX
= {0x2CEAF780, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
24 const GUID KSNODETYPE_STEREO_WIDE
= {0xA9E69800L
, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
25 const GUID KSNODETYPE_CHORUS
= {0x20173F20L
, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
26 const GUID KSNODETYPE_REVERB
= {0xEF0328E0L
, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
27 const GUID KSNODETYPE_SUPERMIX
= {0xE573ADC0L
, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
29 const GUID KSPROPSETID_Audio
= {0x45FFAAA0L
, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
30 const GUID KSPROPSETID_Pin
= {0x8C134960L
, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
31 const GUID KSPROPSETID_General
= {0x1464EDA5L
, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
32 const GUID KSPROPSETID_Topology
= {0x720D4AC0L
, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
33 const GUID KSEVENTSETID_AudioControlChange
= {0xE85E9698L
, 0xFA2F, 0x11D1, {0x95, 0xBD, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3}};
35 const GUID KSDATAFORMAT_TYPE_MUSIC
= {0xE725D360L
, 0x62CC, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
36 const GUID KSDATAFORMAT_SUBTYPE_MIDI
= {0x1D262760L
, 0xE957, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
37 const GUID KSDATAFORMAT_SPECIFIER_NONE
= {0x0F6417D6L
, 0xC318, 0x11D0, {0xA4, 0x3F, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
42 IN PMIXER_CONTEXT MixerContext
)
44 if (MixerContext
->SizeOfStruct
!= sizeof(MIXER_CONTEXT
))
45 return MM_STATUS_INVALID_PARAMETER
;
47 if (!MixerContext
->Alloc
|| !MixerContext
->Control
|| !MixerContext
->Free
|| !MixerContext
->Open
||
48 !MixerContext
->AllocEventData
|| !MixerContext
->FreeEventData
||
49 !MixerContext
->Close
|| !MixerContext
->OpenKey
|| !MixerContext
->QueryKeyValue
|| !MixerContext
->CloseKey
)
50 return MM_STATUS_INVALID_PARAMETER
;
52 if (!MixerContext
->MixerContext
)
53 return MM_STATUS_INVALID_PARAMETER
;
55 return MM_STATUS_SUCCESS
;
59 MMixerGetMixerLineContainingNodeId(
60 IN LPMIXER_INFO MixerInfo
,
63 PLIST_ENTRY Entry
, ControlEntry
;
64 LPMIXERLINE_EXT MixerLineSrc
;
65 LPMIXERCONTROL_EXT MixerControl
;
68 Entry
= MixerInfo
->LineList
.Flink
;
70 while(Entry
!= &MixerInfo
->LineList
)
72 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
74 ControlEntry
= MixerLineSrc
->ControlsList
.Flink
;
75 while(ControlEntry
!= &MixerLineSrc
->ControlsList
)
77 MixerControl
= (LPMIXERCONTROL_EXT
)CONTAINING_RECORD(ControlEntry
, MIXERCONTROL_EXT
, Entry
);
78 if (MixerControl
->NodeID
== NodeID
)
82 ControlEntry
= ControlEntry
->Flink
;
91 MMixerGetLowestLogicalTopologyPinOffsetFromArray(
92 IN ULONG LogicalPinArrayCount
,
93 IN PULONG LogicalPinArray
,
99 for(Index
= 1; Index
< LogicalPinArrayCount
; Index
++)
101 if (LogicalPinArray
[Index
] != MAXULONG
)
103 /* sanity check: logical pin id must be unique */
104 ASSERT(LogicalPinArray
[Index
] != LogicalPinArray
[LowestId
]);
107 if (LogicalPinArray
[Index
] < LogicalPinArray
[LowestId
])
112 *PinOffset
= LowestId
;
117 IN PMIXER_CONTEXT MixerContext
,
118 IN LPMIXER_INFO MixerInfo
)
125 MixerContext
->Free((PVOID
)MixerInfo
);
130 MMixerGetMixerDataByDeviceHandle(
131 IN PMIXER_CONTEXT MixerContext
,
134 LPMIXER_DATA MixerData
;
136 PMIXER_LIST MixerList
;
139 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
141 if (!MixerList
->MixerDataCount
)
144 Entry
= MixerList
->MixerData
.Flink
;
146 while(Entry
!= &MixerList
->MixerData
)
148 MixerData
= (LPMIXER_DATA
)CONTAINING_RECORD(Entry
, MIXER_DATA
, Entry
);
150 if (MixerData
->hDevice
== hDevice
)
153 /* move to next mixer entry */
154 Entry
= Entry
->Flink
;
161 MMixerGetMixerInfoByIndex(
162 IN PMIXER_CONTEXT MixerContext
,
165 LPMIXER_INFO MixerInfo
;
167 PMIXER_LIST MixerList
;
171 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
173 if (!MixerList
->MixerListCount
)
176 Entry
= MixerList
->MixerList
.Flink
;
178 while(Entry
!= &MixerList
->MixerList
)
180 MixerInfo
= (LPMIXER_INFO
)CONTAINING_RECORD(Entry
, MIXER_INFO
, Entry
);
182 if (Index
== MixerIndex
)
185 /* move to next mixer entry */
187 Entry
= Entry
->Flink
;
194 MMixerGetMixerByName(
195 IN PMIXER_LIST MixerList
,
197 OUT LPMIXER_INFO
*OutMixerInfo
)
199 LPMIXER_INFO MixerInfo
;
202 Entry
= MixerList
->MixerList
.Flink
;
203 while(Entry
!= &MixerList
->MixerList
)
205 MixerInfo
= (LPMIXER_INFO
)CONTAINING_RECORD(Entry
, MIXER_INFO
, Entry
);
207 DPRINT1("MixerName %S MixerName %S\n", MixerInfo
->MixCaps
.szPname
, MixerName
);
208 if (wcsicmp(MixerInfo
->MixCaps
.szPname
, MixerName
) == 0)
210 *OutMixerInfo
= MixerInfo
;
211 return MM_STATUS_SUCCESS
;
213 /* move to next mixer entry */
214 Entry
= Entry
->Flink
;
217 return MM_STATUS_UNSUCCESSFUL
;
221 MMixerGetSourceMixerLineByLineId(
222 LPMIXER_INFO MixerInfo
,
226 LPMIXERLINE_EXT MixerLineSrc
;
228 /* get first entry */
229 Entry
= MixerInfo
->LineList
.Flink
;
231 while(Entry
!= &MixerInfo
->LineList
)
233 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
234 DPRINT("dwLineID %x dwLineID %x MixerLineSrc %p\n", MixerLineSrc
->Line
.dwLineID
, dwLineID
, MixerLineSrc
);
235 if (MixerLineSrc
->Line
.dwLineID
== dwLineID
)
238 Entry
= Entry
->Flink
;
246 IN PKSMULTIPLE_ITEM MultipleItem
,
251 ASSERT(Index
< MultipleItem
->Count
);
253 NodeType
= (LPGUID
)(MultipleItem
+ 1);
254 return &NodeType
[Index
];
258 MMixerGetSourceMixerLineByComponentType(
259 LPMIXER_INFO MixerInfo
,
260 DWORD dwComponentType
)
263 LPMIXERLINE_EXT MixerLineSrc
;
265 /* get first entry */
266 Entry
= MixerInfo
->LineList
.Flink
;
268 while(Entry
!= &MixerInfo
->LineList
)
270 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
271 if (MixerLineSrc
->Line
.dwComponentType
== dwComponentType
)
274 Entry
= Entry
->Flink
;
281 MMixerGetMixerControlById(
282 LPMIXER_INFO MixerInfo
,
284 LPMIXERLINE_EXT
*OutMixerLine
,
285 LPMIXERCONTROL_EXT
*OutMixerControl
,
288 PLIST_ENTRY Entry
, ControlEntry
;
289 LPMIXERLINE_EXT MixerLineSrc
;
290 LPMIXERCONTROL_EXT MixerControl
;
292 /* get first entry */
293 Entry
= MixerInfo
->LineList
.Flink
;
295 while(Entry
!= &MixerInfo
->LineList
)
297 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
299 ControlEntry
= MixerLineSrc
->ControlsList
.Flink
;
300 while(ControlEntry
!= &MixerLineSrc
->ControlsList
)
302 MixerControl
= (LPMIXERCONTROL_EXT
)CONTAINING_RECORD(ControlEntry
, MIXERCONTROL_EXT
, Entry
);
303 if (MixerControl
->Control
.dwControlID
== dwControlID
)
306 *OutMixerLine
= MixerLineSrc
;
308 *OutMixerControl
= MixerControl
;
310 *NodeId
= MixerControl
->NodeID
;
311 return MM_STATUS_SUCCESS
;
313 ControlEntry
= ControlEntry
->Flink
;
315 Entry
= Entry
->Flink
;
318 return MM_STATUS_UNSUCCESSFUL
;
322 MMixerGetVolumeControlIndex(
323 LPMIXERVOLUME_DATA VolumeData
,
328 for(Index
= 0; Index
< VolumeData
->ValuesCount
; Index
++)
330 if (VolumeData
->Values
[Index
] > Value
)
332 return VolumeData
->InputSteppingDelta
* Index
;
335 return VolumeData
->InputSteppingDelta
* (VolumeData
->ValuesCount
-1);
339 MMixerNotifyControlChange(
340 IN PMIXER_CONTEXT MixerContext
,
341 IN LPMIXER_INFO MixerInfo
,
342 IN ULONG NotificationType
,
346 PEVENT_NOTIFICATION_ENTRY NotificationEntry
;
348 /* enumerate list and perform notification */
349 Entry
= MixerInfo
->EventList
.Flink
;
350 while(Entry
!= &MixerInfo
->EventList
)
352 /* get notification entry offset */
353 NotificationEntry
= (PEVENT_NOTIFICATION_ENTRY
)CONTAINING_RECORD(Entry
, EVENT_NOTIFICATION_ENTRY
, Entry
);
355 if (NotificationEntry
->MixerEventRoutine
)
357 /* now perform the callback */
358 NotificationEntry
->MixerEventRoutine(NotificationEntry
->MixerEventContext
, (HANDLE
)MixerInfo
, NotificationType
, Value
);
361 /* move to next notification entry */
362 Entry
= Entry
->Flink
;
367 MMixerSetGetMuteControlDetails(
368 IN PMIXER_CONTEXT MixerContext
,
369 IN LPMIXER_INFO MixerInfo
,
370 IN LPMIXERCONTROL_EXT MixerControl
,
372 IN LPMIXERCONTROLDETAILS MixerControlDetails
,
375 LPMIXERCONTROLDETAILS_BOOLEAN Input
;
379 if (MixerControlDetails
->cbDetails
!= sizeof(MIXERCONTROLDETAILS_BOOLEAN
))
380 return MM_STATUS_INVALID_PARAMETER
;
383 Input
= (LPMIXERCONTROLDETAILS_BOOLEAN
)MixerControlDetails
->paDetails
;
387 Value
= Input
->fValue
;
389 /* set control details */
390 Status
= MMixerSetGetControlDetails(MixerContext
, MixerControl
->hDevice
, MixerControl
->NodeID
, bSet
, KSPROPERTY_AUDIO_MUTE
, 0, &Value
);
392 if (Status
!= MM_STATUS_SUCCESS
)
398 Input
->fValue
= Value
;
403 /* notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID */
404 MMixerNotifyControlChange(MixerContext
, MixerInfo
, MM_MIXM_LINE_CHANGE
, dwLineID
);
411 MMixerSetGetMuxControlDetails(
412 IN PMIXER_CONTEXT MixerContext
,
413 IN LPMIXER_INFO MixerInfo
,
417 IN LPMIXERCONTROL_EXT MixerControl
,
418 IN LPMIXERCONTROLDETAILS MixerControlDetails
,
419 IN LPMIXERLINE_EXT MixerLine
)
422 PULONG LogicalNodes
, ConnectedNodes
;
423 ULONG LogicalNodesCount
, ConnectedNodesCount
, Index
, CurLogicalPinOffset
, BytesReturned
, OldLogicalPinOffset
;
424 LPMIXER_DATA MixerData
;
425 LPMIXERCONTROLDETAILS_LISTTEXTW ListText
;
426 LPMIXERCONTROLDETAILS_BOOLEAN Values
;
427 LPMIXERLINE_EXT SourceLine
;
428 KSNODEPROPERTY Request
;
430 DPRINT("MixerControlDetails %p\n", MixerControlDetails
);
431 DPRINT("bSet %lx\n", bSet
);
432 DPRINT("Flags %lx\n", Flags
);
433 DPRINT("NodeId %lu\n", MixerControl
->NodeID
);
434 DPRINT("MixerControlDetails dwControlID %lu\n", MixerControlDetails
->dwControlID
);
435 DPRINT("MixerControlDetails cChannels %lu\n", MixerControlDetails
->cChannels
);
436 DPRINT("MixerControlDetails cMultipleItems %lu\n", MixerControlDetails
->cMultipleItems
);
437 DPRINT("MixerControlDetails cbDetails %lu\n", MixerControlDetails
->cbDetails
);
438 DPRINT("MixerControlDetails paDetails %p\n", MixerControlDetails
->paDetails
);
440 if (MixerControl
->Control
.fdwControl
& MIXERCONTROL_CONTROLF_UNIFORM
)
442 /* control acts uniform */
443 if (MixerControlDetails
->cChannels
!= 1)
445 /* expected 1 channel */
446 DPRINT1("Expected 1 channel but got %lu\n", MixerControlDetails
->cChannels
);
447 return MM_STATUS_UNSUCCESSFUL
;
451 /* check if multiple items match */
452 if (MixerControlDetails
->cMultipleItems
!= MixerControl
->Control
.cMultipleItems
)
454 DPRINT1("MultipleItems mismatch %lu expected %lu\n", MixerControlDetails
->cMultipleItems
, MixerControl
->Control
.cMultipleItems
);
455 return MM_STATUS_UNSUCCESSFUL
;
460 if ((Flags
& MIXER_SETCONTROLDETAILSF_QUERYMASK
) == MIXER_SETCONTROLDETAILSF_CUSTOM
)
462 /* tell me when this is hit */
465 else if ((Flags
& (MIXER_SETCONTROLDETAILSF_VALUE
| MIXER_SETCONTROLDETAILSF_CUSTOM
)) == MIXER_SETCONTROLDETAILSF_VALUE
)
468 ASSERT(bSet
== TRUE
);
469 ASSERT(MixerControlDetails
->cbDetails
== sizeof(MIXERCONTROLDETAILS_BOOLEAN
));
471 Values
= (LPMIXERCONTROLDETAILS_BOOLEAN
)MixerControlDetails
->paDetails
;
472 CurLogicalPinOffset
= MAXULONG
;
473 for(Index
= 0; Index
< MixerControlDetails
->cMultipleItems
; Index
++)
475 if (Values
[Index
].fValue
)
477 /* mux can only activate one line at a time */
478 ASSERT(CurLogicalPinOffset
== MAXULONG
);
479 CurLogicalPinOffset
= Index
;
484 Request
.NodeId
= NodeId
;
485 Request
.Reserved
= 0;
486 Request
.Property
.Flags
= KSPROPERTY_TYPE_TOPOLOGY
| KSPROPERTY_TYPE_GET
;
487 Request
.Property
.Id
= KSPROPERTY_AUDIO_MUX_SOURCE
;
488 Request
.Property
.Set
= KSPROPSETID_Audio
;
490 /* perform getting source */
491 Status
= MixerContext
->Control(MixerControl
->hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSNODEPROPERTY
), &OldLogicalPinOffset
, sizeof(ULONG
), &BytesReturned
);
492 if (Status
!= MM_STATUS_SUCCESS
)
494 /* failed to get source */
498 DPRINT("OldLogicalPinOffset %lu CurLogicalPinOffset %lu\n", OldLogicalPinOffset
, CurLogicalPinOffset
);
500 if (OldLogicalPinOffset
== CurLogicalPinOffset
)
502 /* cannot be unselected */
503 return MM_STATUS_UNSUCCESSFUL
;
506 /* perform setting source */
507 Request
.Property
.Flags
= KSPROPERTY_TYPE_TOPOLOGY
| KSPROPERTY_TYPE_SET
;
508 Status
= MixerContext
->Control(MixerControl
->hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSNODEPROPERTY
), &CurLogicalPinOffset
, sizeof(ULONG
), &BytesReturned
);
509 if (Status
!= MM_STATUS_SUCCESS
)
511 /* failed to set source */
515 /* notify control change */
516 MMixerNotifyControlChange(MixerContext
, MixerInfo
, MM_MIXM_CONTROL_CHANGE
, MixerControl
->Control
.dwControlID
);
523 if ((Flags
& MIXER_GETCONTROLDETAILSF_QUERYMASK
) == MIXER_GETCONTROLDETAILSF_VALUE
)
526 Request
.NodeId
= NodeId
;
527 Request
.Reserved
= 0;
528 Request
.Property
.Flags
= KSPROPERTY_TYPE_TOPOLOGY
| KSPROPERTY_TYPE_GET
;
529 Request
.Property
.Id
= KSPROPERTY_AUDIO_MUX_SOURCE
;
530 Request
.Property
.Set
= KSPROPSETID_Audio
;
532 /* perform getting source */
533 Status
= MixerContext
->Control(MixerControl
->hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSNODEPROPERTY
), &OldLogicalPinOffset
, sizeof(ULONG
), &BytesReturned
);
534 if (Status
!= MM_STATUS_SUCCESS
)
536 /* failed to get source */
540 /* gets the corresponding mixer data */
541 MixerData
= MMixerGetMixerDataByDeviceHandle(MixerContext
, MixerControl
->hDevice
);
545 ASSERT(MixerData
->Topology
);
546 ASSERT(MixerData
->MixerInfo
== MixerInfo
);
548 /* now allocate logical pin array */
549 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, MixerData
->Topology
, &LogicalNodes
);
550 if (Status
!= MM_STATUS_SUCCESS
)
553 return MM_STATUS_NO_MEMORY
;
556 /* get logical pin nodes */
557 MMixerGetConnectedFromLogicalTopologyPins(MixerData
->Topology
, MixerControl
->NodeID
, &LogicalNodesCount
, LogicalNodes
);
560 ASSERT(LogicalNodesCount
== MixerControlDetails
->cMultipleItems
);
561 ASSERT(LogicalNodesCount
== MixerControl
->Control
.Metrics
.dwReserved
[0]);
563 Values
= (LPMIXERCONTROLDETAILS_BOOLEAN
)MixerControlDetails
->paDetails
;
564 for(Index
= 0; Index
< LogicalNodesCount
; Index
++)
566 /* getting logical pin offset */
567 MMixerGetLowestLogicalTopologyPinOffsetFromArray(LogicalNodesCount
, LogicalNodes
, &CurLogicalPinOffset
);
569 if (CurLogicalPinOffset
== OldLogicalPinOffset
)
571 /* mark index as active */
572 Values
[Index
].fValue
= TRUE
;
576 /* index not active */
577 Values
[Index
].fValue
= FALSE
;
580 /* mark offset as consumed */
581 LogicalNodes
[CurLogicalPinOffset
] = MAXULONG
;
585 MixerContext
->Free(LogicalNodes
);
588 return MM_STATUS_SUCCESS
;
590 else if ((Flags
& MIXER_GETCONTROLDETAILSF_QUERYMASK
) == MIXER_GETCONTROLDETAILSF_LISTTEXT
)
593 ASSERT(bSet
== FALSE
);
595 /* gets the corresponding mixer data */
596 MixerData
= MMixerGetMixerDataByDeviceHandle(MixerContext
, MixerControl
->hDevice
);
600 ASSERT(MixerData
->Topology
);
601 ASSERT(MixerData
->MixerInfo
== MixerInfo
);
603 /* now allocate logical pin array */
604 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, MixerData
->Topology
, &LogicalNodes
);
605 if (Status
!= MM_STATUS_SUCCESS
)
608 return MM_STATUS_NO_MEMORY
;
611 /* allocate connected node array */
612 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, MixerData
->Topology
, &ConnectedNodes
);
613 if (Status
!= MM_STATUS_SUCCESS
)
616 MixerContext
->Free(LogicalNodes
);
617 return MM_STATUS_NO_MEMORY
;
620 /* get logical pin nodes */
621 MMixerGetConnectedFromLogicalTopologyPins(MixerData
->Topology
, MixerControl
->NodeID
, &LogicalNodesCount
, LogicalNodes
);
623 /* get connected nodes */
624 MMixerGetNextNodesFromNodeIndex(MixerContext
, MixerData
->Topology
, MixerControl
->NodeID
, TRUE
, &ConnectedNodesCount
, ConnectedNodes
);
627 ASSERT(ConnectedNodesCount
== LogicalNodesCount
);
628 ASSERT(ConnectedNodesCount
== MixerControlDetails
->cMultipleItems
);
629 ASSERT(ConnectedNodesCount
== MixerControl
->Control
.Metrics
.dwReserved
[0]);
631 ListText
= (LPMIXERCONTROLDETAILS_LISTTEXTW
)MixerControlDetails
->paDetails
;
633 for(Index
= 0; Index
< ConnectedNodesCount
; Index
++)
635 /* getting logical pin offset */
636 MMixerGetLowestLogicalTopologyPinOffsetFromArray(LogicalNodesCount
, LogicalNodes
, &CurLogicalPinOffset
);
638 /* get mixer line with that node */
639 SourceLine
= MMixerGetMixerLineContainingNodeId(MixerInfo
, ConnectedNodes
[CurLogicalPinOffset
]);
644 DPRINT1("PinOffset %lu LogicalPin %lu NodeId %lu LineName %S\n", CurLogicalPinOffset
, LogicalNodes
[CurLogicalPinOffset
], ConnectedNodes
[CurLogicalPinOffset
], SourceLine
->Line
.szName
);
647 ListText
[Index
].dwParam1
= SourceLine
->Line
.dwLineID
;
648 ListText
[Index
].dwParam2
= SourceLine
->Line
.dwComponentType
;
649 MixerContext
->Copy(ListText
[Index
].szName
, SourceLine
->Line
.szName
, (wcslen(SourceLine
->Line
.szName
) + 1) * sizeof(WCHAR
));
651 /* mark offset as consumed */
652 LogicalNodes
[CurLogicalPinOffset
] = MAXULONG
;
656 MixerContext
->Free(LogicalNodes
);
657 MixerContext
->Free(ConnectedNodes
);
660 return MM_STATUS_SUCCESS
;
664 return MM_STATUS_NOT_IMPLEMENTED
;
668 MMixerSetGetVolumeControlDetails(
669 IN PMIXER_CONTEXT MixerContext
,
670 IN LPMIXER_INFO MixerInfo
,
673 LPMIXERCONTROL_EXT MixerControl
,
674 IN LPMIXERCONTROLDETAILS MixerControlDetails
,
675 LPMIXERLINE_EXT MixerLine
)
677 LPMIXERCONTROLDETAILS_UNSIGNED Input
;
679 ULONG Index
, Channel
= 0;
682 LPMIXERVOLUME_DATA VolumeData
;
684 if (MixerControlDetails
->cbDetails
!= sizeof(MIXERCONTROLDETAILS_SIGNED
))
685 return MM_STATUS_INVALID_PARAMETER
;
687 VolumeData
= (LPMIXERVOLUME_DATA
)MixerControl
->ExtraData
;
689 return MM_STATUS_UNSUCCESSFUL
;
692 Input
= (LPMIXERCONTROLDETAILS_UNSIGNED
)MixerControlDetails
->paDetails
;
694 return MM_STATUS_UNSUCCESSFUL
; /* to prevent dereferencing NULL */
699 Value
= Input
->dwValue
;
700 Index
= Value
/ VolumeData
->InputSteppingDelta
;
702 if (Index
>= VolumeData
->ValuesCount
)
704 DPRINT1("Index %u out of bounds %u \n", Index
, VolumeData
->ValuesCount
);
705 return MM_STATUS_INVALID_PARAMETER
;
708 Value
= VolumeData
->Values
[Index
];
711 /* set control details */
715 Status
= MMixerSetGetControlDetails(MixerContext
, MixerControl
->hDevice
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 0, &Value
);
716 Status
= MMixerSetGetControlDetails(MixerContext
, MixerControl
->hDevice
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 1, &Value
);
720 Status
= MMixerSetGetControlDetails(MixerContext
, MixerControl
->hDevice
, NodeId
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, Channel
, &Value
);
725 dwValue
= MMixerGetVolumeControlIndex(VolumeData
, (LONG
)Value
);
727 Input
->dwValue
= dwValue
;
731 /* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */
732 MMixerNotifyControlChange(MixerContext
, MixerInfo
, MM_MIXM_CONTROL_CHANGE
, MixerControl
->Control
.dwControlID
);
738 MMixerGetDataByDeviceId(
739 IN PMIXER_LIST MixerList
,
743 LPMIXER_DATA MixerData
;
745 Entry
= MixerList
->MixerData
.Flink
;
746 while(Entry
!= &MixerList
->MixerData
)
748 MixerData
= (LPMIXER_DATA
)CONTAINING_RECORD(Entry
, MIXER_DATA
, Entry
);
749 if (MixerData
->DeviceId
== DeviceId
)
753 Entry
= Entry
->Flink
;
759 MMixerGetDataByDeviceName(
760 IN PMIXER_LIST MixerList
,
761 IN LPWSTR DeviceName
)
764 LPMIXER_DATA MixerData
;
766 Entry
= MixerList
->MixerData
.Flink
;
767 while(Entry
!= &MixerList
->MixerData
)
769 MixerData
= (LPMIXER_DATA
)CONTAINING_RECORD(Entry
, MIXER_DATA
, Entry
);
770 if (wcsicmp(&DeviceName
[2], &MixerData
->DeviceName
[2]) == 0)
775 Entry
= Entry
->Flink
;
781 MMixerCreateMixerData(
782 IN PMIXER_CONTEXT MixerContext
,
783 IN PMIXER_LIST MixerList
,
785 IN LPWSTR DeviceName
,
789 LPMIXER_DATA MixerData
;
791 MixerData
= (LPMIXER_DATA
)MixerContext
->Alloc(sizeof(MIXER_DATA
));
793 return MM_STATUS_NO_MEMORY
;
795 MixerData
->DeviceId
= DeviceId
;
796 MixerData
->DeviceName
= DeviceName
;
797 MixerData
->hDevice
= hDevice
;
798 MixerData
->hDeviceInterfaceKey
= hKey
;
799 MixerData
->Topology
= NULL
;
801 InsertTailList(&MixerList
->MixerData
, &MixerData
->Entry
);
802 MixerList
->MixerDataCount
++;
803 return MM_STATUS_SUCCESS
;
807 MMixerGetDeviceNameWithComponentId(
808 IN PMIXER_CONTEXT MixerContext
,
810 OUT LPWSTR OutDeviceName
)
814 KSCOMPONENTID ComponentId
;
816 UNICODE_STRING GuidString
;
817 ULONG ResultLength
, KeyType
;
818 HANDLE hMediaKey
, hGuidKey
;
821 /* prepare property */
822 Property
.Flags
= KSPROPERTY_TYPE_GET
;
823 Property
.Set
= KSPROPSETID_General
;
824 Property
.Id
= KSPROPERTY_GENERAL_COMPONENTID
;
826 /* try get component id */
827 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), &ComponentId
, sizeof(KSCOMPONENTID
), &Length
);
829 if (Status
== MM_STATUS_SUCCESS
)
831 Status
= MixerContext
->OpenKey(NULL
, L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\MediaCategories", KEY_READ
, &hMediaKey
);
832 if (Status
== MM_STATUS_SUCCESS
)
834 RtlStringFromGUID(&ComponentId
.Name
, &GuidString
);
835 Status
= MixerContext
->OpenKey(hMediaKey
, GuidString
.Buffer
, KEY_READ
, &hGuidKey
);
836 RtlFreeUnicodeString(&GuidString
);
837 if (Status
== MM_STATUS_SUCCESS
)
839 Status
= MixerContext
->QueryKeyValue(hGuidKey
, L
"Name", (PVOID
*)&DeviceName
, &ResultLength
, &KeyType
);
840 if (Status
== MM_STATUS_SUCCESS
)
842 MixerContext
->Copy(OutDeviceName
, DeviceName
, min(ResultLength
, (MAXPNAMELEN
-1)*2));
843 MixerContext
->Free(DeviceName
);
846 MixerContext
->CloseKey(hGuidKey
);
848 MixerContext
->CloseKey(hMediaKey
);
856 IN PMIXER_CONTEXT MixerContext
,
857 OUT LPWSTR DeviceName
,
866 Status
= MixerContext
->QueryKeyValue(hKey
, L
"FriendlyName", (PVOID
*)&Name
, &Length
, &Type
);
867 if (Status
== MM_STATUS_SUCCESS
)
869 /* copy device name */
870 MixerContext
->Copy(DeviceName
, Name
, min(wcslen(Name
), MAXPNAMELEN
-1) * sizeof(WCHAR
));
872 /* make sure its null terminated */
873 DeviceName
[MAXPNAMELEN
-1] = L
'\0';
875 /* free device name */
876 MixerContext
->Free(Name
);
882 Status
= MixerContext
->OpenKey(hKey
, L
"Device Parameters", KEY_READ
, &hTemp
);
883 if (Status
!= MM_STATUS_SUCCESS
)
886 Status
= MixerContext
->QueryKeyValue(hTemp
, L
"FriendlyName", (PVOID
*)&Name
, &Length
, &Type
);
887 if (Status
== MM_STATUS_SUCCESS
)
889 /* copy device name */
890 MixerContext
->Copy(DeviceName
, Name
, min(wcslen(Name
), MAXPNAMELEN
-1) * sizeof(WCHAR
));
892 /* make sure its null terminated */
893 DeviceName
[MAXPNAMELEN
-1] = L
'\0';
895 /* free device name */
896 MixerContext
->Free(Name
);
899 MixerContext
->CloseKey(hTemp
);
904 MMixerInitializePinConnect(
905 IN OUT PKSPIN_CONNECT PinConnect
,
908 PinConnect
->Interface
.Set
= KSINTERFACESETID_Standard
;
909 PinConnect
->Interface
.Id
= KSINTERFACE_STANDARD_STREAMING
;
910 PinConnect
->Interface
.Flags
= 0;
911 PinConnect
->Medium
.Set
= KSMEDIUMSETID_Standard
;
912 PinConnect
->Medium
.Id
= KSMEDIUM_TYPE_ANYINSTANCE
;
913 PinConnect
->Medium
.Flags
= 0;
914 PinConnect
->PinToHandle
= NULL
;
915 PinConnect
->PinId
= PinId
;
916 PinConnect
->Priority
.PriorityClass
= KSPRIORITY_NORMAL
;
917 PinConnect
->Priority
.PrioritySubClass
= 1;