2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: lib/drivers/sound/mmixer/controls.c
5 * PURPOSE: Mixer Control Iteration Functions
6 * PROGRAMMER: Johannes Anderwald
12 MMixerGetTargetPinsByNodeConnectionIndex(
13 IN PMIXER_CONTEXT MixerContext
,
14 IN PKSMULTIPLE_ITEM NodeConnections
,
15 IN PKSMULTIPLE_ITEM NodeTypes
,
16 IN ULONG bUpDirection
,
17 IN ULONG NodeConnectionIndex
,
20 PKSTOPOLOGY_CONNECTION Connection
;
21 ULONG PinId
, NodeConnectionCount
, Index
;
22 PULONG NodeConnection
;
27 ASSERT(NodeConnectionIndex
< NodeConnections
->Count
);
29 Connection
= (PKSTOPOLOGY_CONNECTION
)(NodeConnections
+ 1);
31 //DPRINT("FromNode %u FromNodePin %u -> ToNode %u ToNodePin %u\n", Connection[NodeConnectionIndex].FromNode, Connection[NodeConnectionIndex].FromNodePin, Connection[NodeConnectionIndex].ToNode, Connection[NodeConnectionIndex].ToNodePin );
33 if ((Connection
[NodeConnectionIndex
].ToNode
== KSFILTER_NODE
&& bUpDirection
== FALSE
) ||
34 (Connection
[NodeConnectionIndex
].FromNode
== KSFILTER_NODE
&& bUpDirection
== TRUE
))
36 /* iteration stops here */
38 PinId
= Connection
[NodeConnectionIndex
].FromNodePin
;
40 PinId
= Connection
[NodeConnectionIndex
].ToNodePin
;
42 //DPRINT("GetTargetPinsByNodeIndex FOUND Target Pin %u Parsed %u\n", PinId, Pins[PinId]);
44 /* mark pin index as a target pin */
46 return MM_STATUS_SUCCESS
;
49 // get all node indexes referenced by that node
52 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, Connection
[NodeConnectionIndex
].FromNode
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
56 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, Connection
[NodeConnectionIndex
].ToNode
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
59 if (Status
== MM_STATUS_SUCCESS
)
61 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
63 // iterate recursively into the nodes
64 Status
= MMixerGetTargetPinsByNodeConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Pins
);
65 ASSERT(Status
== MM_STATUS_SUCCESS
);
67 // free node connection indexes
68 MixerContext
->Free(NodeConnection
);
75 MMixerGetControlsFromPinByConnectionIndex(
76 IN PMIXER_CONTEXT MixerContext
,
77 IN PKSMULTIPLE_ITEM NodeConnections
,
78 IN PKSMULTIPLE_ITEM NodeTypes
,
79 IN ULONG bUpDirection
,
80 IN ULONG NodeConnectionIndex
,
83 PKSTOPOLOGY_CONNECTION CurConnection
;
87 ULONG NodeConnectionCount
, Index
;
88 PULONG NodeConnection
;
91 /* get current connection */
92 CurConnection
= MMixerGetConnectionByIndex(NodeConnections
, NodeConnectionIndex
);
95 NodeIndex
= CurConnection
->FromNode
;
97 NodeIndex
= CurConnection
->ToNode
;
99 if (NodeIndex
> NodeTypes
->Count
)
101 // reached end of pin connection
102 return MM_STATUS_SUCCESS
;
105 /* get target node type of current connection */
106 NodeType
= MMixerGetNodeType(NodeTypes
, NodeIndex
);
108 if (IsEqualGUIDAligned(NodeType
, &KSNODETYPE_SUM
) || IsEqualGUIDAligned(NodeType
, &KSNODETYPE_MUX
))
112 /* add the sum / mux node to destination line */
113 Nodes
[NodeIndex
] = TRUE
;
116 return MM_STATUS_SUCCESS
;
119 /* now add the node */
120 Nodes
[NodeIndex
] = TRUE
;
123 /* get all node indexes referenced by that node */
126 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, NodeIndex
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
130 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, NodeIndex
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
133 if (Status
== MM_STATUS_SUCCESS
)
135 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
137 /* iterate recursively into the nodes */
138 Status
= MMixerGetControlsFromPinByConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Nodes
);
139 ASSERT(Status
== MM_STATUS_SUCCESS
);
141 /* free node connection indexes */
142 MixerContext
->Free(NodeConnection
);
149 MMixerAddMixerControl(
150 IN PMIXER_CONTEXT MixerContext
,
151 IN LPMIXER_INFO MixerInfo
,
153 IN PKSMULTIPLE_ITEM NodeTypes
,
155 IN LPMIXERLINE_EXT MixerLine
,
156 OUT LPMIXERCONTROLW MixerControl
)
164 /* initialize mixer control */
165 MixerControl
->cbStruct
= sizeof(MIXERCONTROLW
);
166 MixerControl
->dwControlID
= MixerInfo
->ControlId
;
169 NodeType
= MMixerGetNodeType(NodeTypes
, NodeIndex
);
170 /* store control type */
171 MixerControl
->dwControlType
= MMixerGetControlTypeFromTopologyNode(NodeType
);
173 MixerControl
->fdwControl
= MIXERCONTROL_CONTROLF_UNIFORM
; //FIXME
174 MixerControl
->cMultipleItems
= 0; //FIXME
176 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
178 MixerControl
->Bounds
.dwMinimum
= 0;
179 MixerControl
->Bounds
.dwMaximum
= 1;
181 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
183 MixerControl
->Bounds
.dwMinimum
= 0;
184 MixerControl
->Bounds
.dwMaximum
= 0xFFFF;
185 MixerControl
->Metrics
.cSteps
= 0xC0; //FIXME
188 /* setup request to retrieve name */
189 Node
.NodeId
= NodeIndex
;
190 Node
.Property
.Id
= KSPROPERTY_TOPOLOGY_NAME
;
191 Node
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
192 Node
.Property
.Set
= KSPROPSETID_Topology
;
195 /* get node name size */
196 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), NULL
, 0, &BytesReturned
);
198 if (Status
== MM_STATUS_MORE_ENTRIES
)
200 ASSERT(BytesReturned
!= 0);
201 Name
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
204 /* not enough memory */
205 return MM_STATUS_NO_MEMORY
;
209 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), (LPVOID
)Name
, BytesReturned
, &BytesReturned
);
211 if (Status
== MM_STATUS_SUCCESS
)
213 MixerContext
->Copy(MixerControl
->szShortName
, Name
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
214 MixerControl
->szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
216 MixerContext
->Copy(MixerControl
->szName
, Name
, (min(MIXER_LONG_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
217 MixerControl
->szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
220 /* free name buffer */
221 MixerContext
->Free(Name
);
224 MixerInfo
->ControlId
++;
226 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUX
)
228 KSNODEPROPERTY Property
;
231 /* setup the request */
232 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY
));
234 Property
.NodeId
= NodeIndex
;
235 Property
.Property
.Id
= KSPROPERTY_AUDIO_MUX_SOURCE
;
236 Property
.Property
.Flags
= KSPROPERTY_TYPE_SET
;
237 Property
.Property
.Set
= KSPROPSETID_Audio
;
239 /* get node volume level info */
240 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY
), (PVOID
)&PinId
, sizeof(ULONG
), &BytesReturned
);
242 DPRINT1("Status %x NodeIndex %u PinId %u\n", Status
, NodeIndex
, PinId
);
246 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
248 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
250 PKSPROPERTY_DESCRIPTION Desc
;
251 PKSPROPERTY_MEMBERSHEADER Members
;
252 PKSPROPERTY_STEPPING_LONG Range
;
254 Length
= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) + sizeof(KSPROPERTY_STEPPING_LONG
);
255 Desc
= (PKSPROPERTY_DESCRIPTION
)MixerContext
->Alloc(Length
);
258 /* setup the request */
259 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
261 Property
.NodeProperty
.NodeId
= NodeIndex
;
262 Property
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
263 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
;
264 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
266 /* get node volume level info */
267 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), Desc
, Length
, &BytesReturned
);
269 if (Status
== MM_STATUS_SUCCESS
)
271 LPMIXERVOLUME_DATA VolumeData
;
272 ULONG Steps
, MaxRange
, Index
;
275 Members
= (PKSPROPERTY_MEMBERSHEADER
)(Desc
+ 1);
276 Range
= (PKSPROPERTY_STEPPING_LONG
)(Members
+ 1);
278 DPRINT("NodeIndex %u Range Min %d Max %d Steps %x UMin %x UMax %x\n", NodeIndex
, Range
->Bounds
.SignedMinimum
, Range
->Bounds
.SignedMaximum
, Range
->SteppingDelta
, Range
->Bounds
.UnsignedMinimum
, Range
->Bounds
.UnsignedMaximum
);
280 MaxRange
= Range
->Bounds
.UnsignedMaximum
- Range
->Bounds
.UnsignedMinimum
;
285 VolumeData
= (LPMIXERVOLUME_DATA
)MixerContext
->Alloc(sizeof(MIXERVOLUME_DATA
));
287 return MM_STATUS_NO_MEMORY
;
289 Steps
= MaxRange
/ Range
->SteppingDelta
+ 1;
291 /* store mixer control info there */
292 VolumeData
->Header
.dwControlID
= MixerControl
->dwControlID
;
293 VolumeData
->SignedMaximum
= Range
->Bounds
.SignedMaximum
;
294 VolumeData
->SignedMinimum
= Range
->Bounds
.SignedMinimum
;
295 VolumeData
->SteppingDelta
= Range
->SteppingDelta
;
296 VolumeData
->ValuesCount
= Steps
;
297 VolumeData
->InputSteppingDelta
= 0x10000 / Steps
;
299 VolumeData
->Values
= (PLONG
)MixerContext
->Alloc(sizeof(LONG
) * Steps
);
300 if (!VolumeData
->Values
)
302 MixerContext
->Free(Desc
);
303 MixerContext
->Free(VolumeData
);
304 return MM_STATUS_NO_MEMORY
;
307 Value
= Range
->Bounds
.SignedMinimum
;
308 for(Index
= 0; Index
< Steps
; Index
++)
310 VolumeData
->Values
[Index
] = Value
;
311 Value
+= Range
->SteppingDelta
;
313 InsertTailList(&MixerLine
->LineControlsExtraData
, &VolumeData
->Header
.Entry
);
316 MixerContext
->Free(Desc
);
319 DPRINT("Status %x Name %S\n", Status
, MixerControl
->szName
);
320 return MM_STATUS_SUCCESS
;
324 MMixerAddMixerSourceLine(
325 IN PMIXER_CONTEXT MixerContext
,
326 IN OUT LPMIXER_INFO MixerInfo
,
328 IN PKSMULTIPLE_ITEM NodeConnections
,
329 IN PKSMULTIPLE_ITEM NodeTypes
,
334 LPMIXERLINE_EXT SrcLine
, DstLine
;
339 ULONG BytesReturned
, ControlCount
, Index
;
345 /* allocate src mixer line */
346 SrcLine
= (LPMIXERLINE_EXT
)MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
349 return MM_STATUS_NO_MEMORY
;
352 RtlZeroMemory(SrcLine
, sizeof(MIXERLINE_EXT
));
357 ASSERT(!IsListEmpty(&MixerInfo
->LineList
));
358 SrcLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
361 /* get destination line */
362 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
368 /* initialize mixer src line */
369 SrcLine
->hDevice
= hDevice
;
370 SrcLine
->PinId
= PinId
;
371 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
373 /* initialize mixer destination line */
374 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
375 SrcLine
->Line
.dwDestination
= 0;
376 SrcLine
->Line
.dwSource
= DstLine
->Line
.cConnections
;
377 SrcLine
->Line
.dwLineID
= (DstLine
->Line
.cConnections
* 0x10000);
378 SrcLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
| MIXERLINE_LINEF_SOURCE
;
379 SrcLine
->Line
.dwUser
= 0;
380 SrcLine
->Line
.cChannels
= DstLine
->Line
.cChannels
;
381 SrcLine
->Line
.cConnections
= 0;
382 SrcLine
->Line
.Target
.dwType
= 1;
383 SrcLine
->Line
.Target
.dwDeviceID
= DstLine
->Line
.Target
.dwDeviceID
;
384 SrcLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
385 SrcLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
386 SrcLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
387 InitializeListHead(&SrcLine
->LineControlsExtraData
);
388 wcscpy(SrcLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
392 /* allocate a node arrary */
393 Nodes
= (PULONG
)MixerContext
->Alloc(sizeof(ULONG
) * NodeTypes
->Count
);
397 /* not enough memory */
400 MixerContext
->Free(SrcLine
);
402 return MM_STATUS_NO_MEMORY
;
405 Status
= MMixerGetControlsFromPin(MixerContext
, NodeConnections
, NodeTypes
, PinId
, bTargetPin
, Nodes
);
406 if (Status
!= MM_STATUS_SUCCESS
)
408 /* something went wrong */
411 MixerContext
->Free(SrcLine
);
413 MixerContext
->Free(Nodes
);
417 /* now count all nodes controlled by that pin */
419 for(Index
= 0; Index
< NodeTypes
->Count
; Index
++)
424 Node
= MMixerGetNodeType(NodeTypes
, Index
);
426 if (MMixerGetControlTypeFromTopologyNode(Node
))
428 // found a node which can be resolved to a type
434 /* now allocate the line controls */
437 SrcLine
->LineControls
= (LPMIXERCONTROLW
)MixerContext
->Alloc(sizeof(MIXERCONTROLW
) * ControlCount
);
439 if (!SrcLine
->LineControls
)
441 /* no memory available */
444 MixerContext
->Free(SrcLine
);
446 MixerContext
->Free(Nodes
);
447 return MM_STATUS_NO_MEMORY
;
450 SrcLine
->NodeIds
= (PULONG
)MixerContext
->Alloc(sizeof(ULONG
) * ControlCount
);
451 if (!SrcLine
->NodeIds
)
453 /* no memory available */
454 MixerContext
->Free(SrcLine
->LineControls
);
457 MixerContext
->Free(SrcLine
);
459 MixerContext
->Free(Nodes
);
460 return MM_STATUS_NO_MEMORY
;
463 /* zero line controls */
464 RtlZeroMemory(SrcLine
->LineControls
, sizeof(MIXERCONTROLW
) * ControlCount
);
465 RtlZeroMemory(SrcLine
->NodeIds
, sizeof(ULONG
) * ControlCount
);
468 for(Index
= 0; Index
< NodeTypes
->Count
; Index
++)
473 Node
= MMixerGetNodeType(NodeTypes
, Index
);
475 if (MMixerGetControlTypeFromTopologyNode(Node
))
477 /* store the node index for retrieving / setting details */
478 SrcLine
->NodeIds
[ControlCount
] = Index
;
480 Status
= MMixerAddMixerControl(MixerContext
, MixerInfo
, hDevice
, NodeTypes
, Index
, SrcLine
, &SrcLine
->LineControls
[ControlCount
]);
481 if (Status
== MM_STATUS_SUCCESS
)
483 /* increment control count on success */
489 /* store control count */
490 SrcLine
->Line
.cControls
= ControlCount
;
493 /* release nodes array */
494 MixerContext
->Free(Nodes
);
496 /* get pin category */
499 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
500 Pin
.Property
.Set
= KSPROPSETID_Pin
;
501 Pin
.Property
.Id
= KSPROPERTY_PIN_CATEGORY
;
503 /* try get pin category */
504 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (LPVOID
)&NodeType
, sizeof(GUID
), &BytesReturned
);
505 if (Status
!= MM_STATUS_SUCCESS
)
511 /* retrieve pin name */
514 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
515 Pin
.Property
.Set
= KSPROPSETID_Pin
;
516 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
518 /* try get pin name size */
519 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
521 if (Status
== MM_STATUS_MORE_ENTRIES
)
523 PinName
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
526 /* try get pin name */
527 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (LPVOID
)PinName
, BytesReturned
, &BytesReturned
);
529 if (Status
== MM_STATUS_SUCCESS
)
531 MixerContext
->Copy(SrcLine
->Line
.szShortName
, PinName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
532 SrcLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
534 MixerContext
->Copy(SrcLine
->Line
.szName
, PinName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
535 SrcLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
537 MixerContext
->Free(PinName
);
541 /* insert src line */
544 InsertTailList(&MixerInfo
->LineList
, &SrcLine
->Entry
);
545 DstLine
->Line
.cConnections
++;
548 return MM_STATUS_SUCCESS
;
552 MMixerCreateDestinationLine(
553 IN PMIXER_CONTEXT MixerContext
,
554 IN LPMIXER_INFO MixerInfo
,
555 IN ULONG bInputMixer
,
558 LPMIXERLINE_EXT DestinationLine
;
560 // allocate a mixer destination line
561 DestinationLine
= (LPMIXERLINE_EXT
) MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
565 return MM_STATUS_NO_MEMORY
;
568 /* initialize mixer destination line */
569 DestinationLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
570 DestinationLine
->Line
.dwSource
= MAXULONG
;
571 DestinationLine
->Line
.dwLineID
= DESTINATION_LINE
;
572 DestinationLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
;
573 DestinationLine
->Line
.dwUser
= 0;
574 DestinationLine
->Line
.dwComponentType
= (bInputMixer
== 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
);
575 DestinationLine
->Line
.cChannels
= 2; //FIXME
579 MixerContext
->Copy(DestinationLine
->Line
.szShortName
, LineName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
580 DestinationLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
582 MixerContext
->Copy(DestinationLine
->Line
.szName
, LineName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
583 DestinationLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
588 /* FIXME no name was found for pin */
589 wcscpy(DestinationLine
->Line
.szShortName
, L
"Summe");
590 wcscpy(DestinationLine
->Line
.szName
, L
"Summe");
593 DestinationLine
->Line
.Target
.dwType
= (bInputMixer
== 0 ? MIXERLINE_TARGETTYPE_WAVEOUT
: MIXERLINE_TARGETTYPE_WAVEIN
);
594 DestinationLine
->Line
.Target
.dwDeviceID
= !bInputMixer
;
595 DestinationLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
596 DestinationLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
597 DestinationLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
598 wcscpy(DestinationLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
600 // initialize extra line
601 InitializeListHead(&DestinationLine
->LineControlsExtraData
);
603 // insert into mixer info
604 InsertHeadList(&MixerInfo
->LineList
, &DestinationLine
->Entry
);
607 return MM_STATUS_SUCCESS
;
611 MMixerGetControlsFromPin(
612 IN PMIXER_CONTEXT MixerContext
,
613 IN PKSMULTIPLE_ITEM NodeConnections
,
614 IN PKSMULTIPLE_ITEM NodeTypes
,
616 IN ULONG bUpDirection
,
619 ULONG NodeConnectionCount
, Index
;
621 PULONG NodeConnection
;
624 ASSERT(PinId
!= (ULONG
)-1);
626 /* get all node indexes referenced by that pin */
628 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, PinId
, FALSE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
630 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, PinId
, FALSE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
632 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
634 /* get all associated controls */
635 Status
= MMixerGetControlsFromPinByConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Nodes
);
638 MixerContext
->Free(NodeConnection
);
647 MMixerAddMixerSourceLines(
648 IN PMIXER_CONTEXT MixerContext
,
649 IN OUT LPMIXER_INFO MixerInfo
,
651 IN PKSMULTIPLE_ITEM NodeConnections
,
652 IN PKSMULTIPLE_ITEM NodeTypes
,
654 IN ULONG BridgePinIndex
,
655 IN ULONG TargetPinIndex
,
660 for(Index
= PinsCount
; Index
> 0; Index
--)
662 DPRINT("MMixerAddMixerSourceLines Index %lu Pin %lu\n", Index
-1, Pins
[Index
-1]);
665 MMixerAddMixerSourceLine(MixerContext
, MixerInfo
, hDevice
, NodeConnections
, NodeTypes
, Index
-1, (Index
-1 == BridgePinIndex
), (Index
-1 == TargetPinIndex
));
668 return MM_STATUS_SUCCESS
;
673 MMixerHandlePhysicalConnection(
674 IN PMIXER_CONTEXT MixerContext
,
675 IN PMIXER_LIST MixerList
,
676 IN OUT LPMIXER_INFO MixerInfo
,
678 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
680 PULONG PinsRef
= NULL
, PinConnectionIndex
= NULL
, PinsSrcRef
;
681 ULONG PinsRefCount
, Index
, PinConnectionIndexCount
;
683 PKSMULTIPLE_ITEM NodeTypes
= NULL
;
684 PKSMULTIPLE_ITEM NodeConnections
= NULL
;
685 PULONG MixerControls
;
686 ULONG MixerControlsCount
;
687 LPMIXER_DATA MixerData
;
690 // open the connected filter
691 OutConnection
->SymbolicLinkName
[1] = L
'\\';
692 MixerData
= MMixerGetDataByDeviceName(MixerList
, OutConnection
->SymbolicLinkName
);
695 // store connected mixer handle
696 MixerInfo
->hMixer
= MixerData
->hDevice
;
698 // get connected filter pin count
699 PinsRefCount
= MMixerGetFilterPinCount(MixerContext
, MixerData
->hDevice
);
700 ASSERT(PinsRefCount
);
702 PinsRef
= (PULONG
)MixerContext
->Alloc(sizeof(ULONG
) * PinsRefCount
);
706 return MM_STATUS_UNSUCCESSFUL
;
709 // get topology node types
710 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
711 if (Status
!= MM_STATUS_SUCCESS
)
713 MixerContext
->Free(PinsRef
);
717 // get topology connections
718 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
719 if (Status
!= MM_STATUS_SUCCESS
)
721 MixerContext
->Free(PinsRef
);
722 MixerContext
->Free(NodeTypes
);
725 // gets connection index of the bridge pin which connects to a node
726 DPRINT("Pin %lu\n", OutConnection
->Pin
);
728 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, OutConnection
->Pin
, FALSE
, !bInput
, &PinConnectionIndexCount
, &PinConnectionIndex
);
729 if (Status
!= MM_STATUS_SUCCESS
)
731 MixerContext
->Free(PinsRef
);
732 MixerContext
->Free(NodeTypes
);
733 MixerContext
->Free(NodeConnections
);
737 /* there should be no split in the bride pin */
738 ASSERT(PinConnectionIndexCount
== 1);
740 /* find all target pins of this connection */
741 Status
= MMixerGetTargetPinsByNodeConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, FALSE
, PinConnectionIndex
[0], PinsRef
);
742 if (Status
!= MM_STATUS_SUCCESS
)
744 MixerContext
->Free(PinsRef
);
745 MixerContext
->Free(NodeTypes
);
746 MixerContext
->Free(NodeConnections
);
747 MixerContext
->Free(PinConnectionIndex
);
751 for(Index
= 0; Index
< PinsRefCount
; Index
++)
753 DPRINT("PinsRefCount %lu Index %lu Value %lu\n", PinsRefCount
, Index
, PinsRef
[Index
]);
756 // found a target pin, now get all references
757 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, Index
, FALSE
, FALSE
, &MixerControlsCount
, &MixerControls
);
758 if (Status
!= MM_STATUS_SUCCESS
)
760 DPRINT("MMixerGetNodeIndexes failed with %u\n", Status
);
765 ASSERT(MixerControlsCount
== 1);
767 PinsSrcRef
= (PULONG
)MixerContext
->Alloc(PinsRefCount
* sizeof(ULONG
));
771 MixerContext
->Free(PinsRef
);
772 MixerContext
->Free(NodeTypes
);
773 MixerContext
->Free(NodeConnections
);
774 MixerContext
->Free(PinConnectionIndex
);
775 MixerContext
->Free(MixerControls
);
776 return MM_STATUS_NO_MEMORY
;
779 // now get all connected source pins
780 Status
= MMixerGetTargetPinsByNodeConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, TRUE
, MixerControls
[0], PinsSrcRef
);
781 if (Status
!= MM_STATUS_SUCCESS
)
784 MixerContext
->Free(PinsRef
);
785 MixerContext
->Free(NodeTypes
);
786 MixerContext
->Free(NodeConnections
);
787 MixerContext
->Free(PinConnectionIndex
);
788 MixerContext
->Free(MixerControls
);
789 MixerContext
->Free(PinsSrcRef
);
793 /* add pins from target line */
796 // dont add bridge pin for input mixers
797 PinsSrcRef
[Index
] = TRUE
;
798 PinsSrcRef
[OutConnection
->Pin
] = TRUE
;
800 PinsSrcRef
[OutConnection
->Pin
] = TRUE
;
802 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, NodeConnections
, NodeTypes
, PinsRefCount
, OutConnection
->Pin
, Index
, PinsSrcRef
);
804 MixerContext
->Free(MixerControls
);
805 MixerContext
->Free(PinsSrcRef
);
814 MMixerInitializeFilter(
815 IN PMIXER_CONTEXT MixerContext
,
816 IN PMIXER_LIST MixerList
,
817 IN LPMIXER_DATA MixerData
,
818 IN PKSMULTIPLE_ITEM NodeTypes
,
819 IN PKSMULTIPLE_ITEM NodeConnections
,
822 IN ULONG bInputMixer
)
824 LPMIXER_INFO MixerInfo
;
826 PKSPIN_PHYSICALCONNECTION OutConnection
;
832 LPWSTR Buffer
= NULL
;
835 // allocate a mixer info struct
836 MixerInfo
= (LPMIXER_INFO
) MixerContext
->Alloc(sizeof(MIXER_INFO
));
840 return MM_STATUS_NO_MEMORY
;
843 // intialize mixer caps */
844 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; //FIXME
845 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; //FIXME
846 MixerInfo
->MixCaps
.vDriverVersion
= 1; //FIXME
847 MixerInfo
->MixCaps
.fdwSupport
= 0;
848 MixerInfo
->MixCaps
.cDestinations
= 1;
849 MixerInfo
->hMixer
= MixerData
->hDevice
;
852 MMixerGetDeviceName(MixerContext
, MixerInfo
, MixerData
->hDeviceInterfaceKey
);
854 // initialize line list
855 InitializeListHead(&MixerInfo
->LineList
);
856 InitializeListHead(&MixerInfo
->EventList
);
858 // now allocate an array which will receive the indices of the pin
859 // which has a ADC / DAC nodetype in its path
860 Pins
= (PULONG
)MixerContext
->Alloc(PinCount
* sizeof(ULONG
));
865 MMixerFreeMixerInfo(MixerContext
, MixerInfo
);
866 return MM_STATUS_NO_MEMORY
;
869 // now get the target pins of the ADC / DAC node
870 Status
= MMixerGetTargetPins(MixerContext
, NodeTypes
, NodeConnections
, NodeIndex
, !bInputMixer
, Pins
, PinCount
);
872 // find a target pin with a name
874 for(Index
= 0; Index
< PinCount
; Index
++)
878 // store index of pin
881 /* retrieve pin name */
884 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
885 Pin
.Property
.Set
= KSPROPSETID_Pin
;
886 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
888 /* try get pin name size */
889 Status
= MixerContext
->Control(MixerData
->hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
891 if (Status
== MM_STATUS_MORE_ENTRIES
)
893 Buffer
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
896 /* try get pin name */
897 Status
= MixerContext
->Control(MixerData
->hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Buffer
, BytesReturned
, &BytesReturned
);
898 if (Status
!= MM_STATUS_SUCCESS
)
900 MixerContext
->Free((PVOID
)Buffer
);
913 if (PinId
< PinCount
)
915 // create an wave info struct
916 MMixerInitializeWaveInfo(MixerContext
, MixerList
, MixerData
, MixerInfo
->MixCaps
.szPname
, bInputMixer
, PinId
);
919 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInputMixer
, Buffer
);
924 MixerContext
->Free(Buffer
);
927 if (Status
!= MM_STATUS_SUCCESS
)
929 // failed to create destination line
930 MixerContext
->Free(MixerInfo
);
931 MixerContext
->Free(Pins
);
936 RtlZeroMemory(Pins
, sizeof(ULONG
) * PinCount
);
937 // now get the target pins of the ADC / DAC node
938 Status
= MMixerGetTargetPins(MixerContext
, NodeTypes
, NodeConnections
, NodeIndex
, bInputMixer
, Pins
, PinCount
);
940 if (Status
!= MM_STATUS_SUCCESS
)
942 // failed to locate target pins
943 MixerContext
->Free(Pins
);
944 MMixerFreeMixerInfo(MixerContext
, MixerInfo
);
945 DPRINT("MMixerGetTargetPins failed with %u\n", Status
);
949 // filter hasnt been used
952 // now check all pins and generate new lines for destination lines
953 for(Index
= 0; Index
< PinCount
; Index
++)
955 DPRINT("Index %lu TargetPin %lu\n", Index
, Pins
[Index
]);
956 // is the current index a target pin
959 // check if the pin has a physical connection
960 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Index
, &OutConnection
);
961 if (Status
== MM_STATUS_SUCCESS
)
963 // the pin has a physical connection
964 Status
= MMixerHandlePhysicalConnection(MixerContext
, MixerList
, MixerInfo
, bInputMixer
, OutConnection
);
965 DPRINT("MMixerHandlePhysicalConnection status %u\n", Status
);
966 MixerContext
->Free(OutConnection
);
971 // filter exposes the topology on the same filter
972 MMixerAddMixerSourceLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, NodeConnections
, NodeTypes
, Index
, FALSE
, FALSE
);
977 MixerContext
->Free(Pins
);
981 // store mixer info in list
982 if (!bInputMixer
&& MixerList
->MixerListCount
== 1)
984 //FIXME preferred device should be inserted at front
985 //windows always inserts output mixer in front
986 InsertHeadList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
990 InsertTailList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
992 MixerList
->MixerListCount
++;
993 DPRINT("New MixerCount %lu\n", MixerList
->MixerListCount
);
997 // failed to create a mixer topology
998 MMixerFreeMixerInfo(MixerContext
, MixerInfo
);
1007 IN PMIXER_CONTEXT MixerContext
,
1008 IN PMIXER_LIST MixerList
,
1009 IN LPMIXER_DATA MixerData
,
1010 IN PULONG DeviceCount
)
1012 PKSMULTIPLE_ITEM NodeTypes
= NULL
, NodeConnections
= NULL
;
1013 MIXER_STATUS Status
;
1017 // get number of pins
1018 PinCount
= MMixerGetFilterPinCount(MixerContext
, MixerData
->hDevice
);
1020 DPRINT("NumOfPins: %lu\n", PinCount
);
1022 // get filter node types
1023 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
1024 if (Status
!= MM_STATUS_SUCCESS
)
1030 // get filter node connections
1031 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
1032 if (Status
!= MM_STATUS_SUCCESS
)
1035 MixerContext
->Free(NodeTypes
);
1039 // check if the filter has an wave out node
1041 NodeIndex
= MMixerGetIndexOfGuid(NodeTypes
, &KSNODETYPE_DAC
);
1042 if (NodeIndex
!= MAXULONG
)
1045 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, NodeTypes
, NodeConnections
, PinCount
, NodeIndex
, FALSE
);
1046 DPRINT("MMixerInitializeFilter Status %u\n", Status
);
1047 // check for success
1048 if (Status
== MM_STATUS_SUCCESS
)
1050 // increment mixer count
1056 // check if the filter has an wave in node
1057 NodeIndex
= MMixerGetIndexOfGuid(NodeTypes
, &KSNODETYPE_ADC
);
1058 if (NodeIndex
!= MAXULONG
)
1061 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, NodeTypes
, NodeConnections
, PinCount
, NodeIndex
, TRUE
);
1062 DPRINT("MMixerInitializeFilter Status %u\n", Status
);
1063 // check for success
1064 if (Status
== MM_STATUS_SUCCESS
)
1066 // increment mixer count
1073 MixerContext
->Free((PVOID
)NodeTypes
);
1074 MixerContext
->Free((PVOID
)NodeConnections
);
1083 IN PMIXER_CONTEXT MixerContext
,
1084 IN OUT LPMIXER_INFO MixerInfo
,
1088 LPEVENT_ITEM EventData
;
1089 ULONG BytesReturned
;
1090 MIXER_STATUS Status
;
1092 EventData
= (LPEVENT_ITEM
)MixerContext
->AllocEventData(sizeof(LIST_ENTRY
));
1095 // not enough memory
1096 return MM_STATUS_NO_MEMORY
;
1100 Property
.Event
.Set
= KSEVENTSETID_AudioControlChange
;
1101 Property
.Event
.Flags
= KSEVENT_TYPE_TOPOLOGY
|KSEVENT_TYPE_ENABLE
;
1102 Property
.Event
.Id
= KSEVENT_CONTROL_CHANGE
;
1104 Property
.NodeId
= NodeId
;
1105 Property
.Reserved
= 0;
1107 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSP_NODE
), (PVOID
)EventData
, sizeof(KSEVENTDATA
), &BytesReturned
);
1108 if (Status
!= MM_STATUS_SUCCESS
)
1110 // failed to add event
1111 MixerContext
->FreeEventData(EventData
);
1116 InsertTailList(&MixerInfo
->EventList
, &EventData
->Entry
);
1122 IN PMIXER_CONTEXT MixerContext
,
1123 IN OUT LPMIXER_INFO MixerInfo
)
1125 PKSMULTIPLE_ITEM NodeTypes
;
1127 MIXER_STATUS Status
;
1130 // get filter node types
1131 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerInfo
->hMixer
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
1133 if (Status
!= MM_STATUS_SUCCESS
)
1139 for(Index
= 0; Index
< NodeTypes
->Count
; Index
++)
1141 Guid
= MMixerGetNodeType(NodeTypes
, Index
);
1142 if (IsEqualGUID(&KSNODETYPE_VOLUME
, Guid
) || IsEqualGUID(&KSNODETYPE_MUTE
, Guid
))
1144 //add an event for volume / mute controls
1145 //TODO: extra control types
1146 MMixerAddEvent(MixerContext
, MixerInfo
, Index
);
1151 MixerContext
->Free(NodeTypes
);
1153 return MM_STATUS_SUCCESS
;