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 MMixerAddMixerControl(
13 IN PMIXER_CONTEXT MixerContext
,
14 IN LPMIXER_INFO MixerInfo
,
15 IN PTOPOLOGY Topology
,
17 IN LPMIXERLINE_EXT MixerLine
,
18 OUT LPMIXERCONTROLW MixerControl
)
26 /* initialize mixer control */
27 MixerControl
->cbStruct
= sizeof(MIXERCONTROLW
);
28 MixerControl
->dwControlID
= MixerInfo
->ControlId
;
31 NodeType
= MMixerGetNodeTypeFromTopology(Topology
, NodeIndex
);
32 /* store control type */
33 MixerControl
->dwControlType
= MMixerGetControlTypeFromTopologyNode(NodeType
);
35 MixerControl
->fdwControl
= MIXERCONTROL_CONTROLF_UNIFORM
; /* FIXME */
36 MixerControl
->cMultipleItems
= 0; /* FIXME */
38 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
40 MixerControl
->Bounds
.dwMinimum
= 0;
41 MixerControl
->Bounds
.dwMaximum
= 1;
43 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
45 MixerControl
->Bounds
.dwMinimum
= 0;
46 MixerControl
->Bounds
.dwMaximum
= 0xFFFF;
47 MixerControl
->Metrics
.cSteps
= 0xC0; /* FIXME */
50 /* setup request to retrieve name */
51 Node
.NodeId
= NodeIndex
;
52 Node
.Property
.Id
= KSPROPERTY_TOPOLOGY_NAME
;
53 Node
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
54 Node
.Property
.Set
= KSPROPSETID_Topology
;
57 /* get node name size */
58 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), NULL
, 0, &BytesReturned
);
60 if (Status
== MM_STATUS_MORE_ENTRIES
)
62 ASSERT(BytesReturned
!= 0);
63 Name
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
66 /* not enough memory */
67 return MM_STATUS_NO_MEMORY
;
71 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), (LPVOID
)Name
, BytesReturned
, &BytesReturned
);
73 if (Status
== MM_STATUS_SUCCESS
)
75 MixerContext
->Copy(MixerControl
->szShortName
, Name
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
76 MixerControl
->szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
78 MixerContext
->Copy(MixerControl
->szName
, Name
, (min(MIXER_LONG_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
79 MixerControl
->szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
82 /* free name buffer */
83 MixerContext
->Free(Name
);
86 MixerInfo
->ControlId
++;
88 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUX
)
90 KSNODEPROPERTY Property
;
93 /* setup the request */
94 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY
));
96 Property
.NodeId
= NodeIndex
;
97 Property
.Property
.Id
= KSPROPERTY_AUDIO_MUX_SOURCE
;
98 Property
.Property
.Flags
= KSPROPERTY_TYPE_SET
;
99 Property
.Property
.Set
= KSPROPSETID_Audio
;
101 /* get node volume level info */
102 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY
), (PVOID
)&PinId
, sizeof(ULONG
), &BytesReturned
);
104 DPRINT1("Status %x NodeIndex %u PinId %u\n", Status
, NodeIndex
, PinId
);
108 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
110 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
112 PKSPROPERTY_DESCRIPTION Desc
;
113 PKSPROPERTY_MEMBERSHEADER Members
;
114 PKSPROPERTY_STEPPING_LONG Range
;
116 Length
= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) + sizeof(KSPROPERTY_STEPPING_LONG
);
117 Desc
= (PKSPROPERTY_DESCRIPTION
)MixerContext
->Alloc(Length
);
120 /* setup the request */
121 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
123 Property
.NodeProperty
.NodeId
= NodeIndex
;
124 Property
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
125 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
;
126 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
128 /* get node volume level info */
129 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), Desc
, Length
, &BytesReturned
);
131 if (Status
== MM_STATUS_SUCCESS
)
133 LPMIXERVOLUME_DATA VolumeData
;
134 ULONG Steps
, MaxRange
, Index
;
137 Members
= (PKSPROPERTY_MEMBERSHEADER
)(Desc
+ 1);
138 Range
= (PKSPROPERTY_STEPPING_LONG
)(Members
+ 1);
140 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
);
142 MaxRange
= Range
->Bounds
.UnsignedMaximum
- Range
->Bounds
.UnsignedMinimum
;
147 VolumeData
= (LPMIXERVOLUME_DATA
)MixerContext
->Alloc(sizeof(MIXERVOLUME_DATA
));
149 return MM_STATUS_NO_MEMORY
;
151 Steps
= MaxRange
/ Range
->SteppingDelta
+ 1;
153 /* store mixer control info there */
154 VolumeData
->Header
.dwControlID
= MixerControl
->dwControlID
;
155 VolumeData
->SignedMaximum
= Range
->Bounds
.SignedMaximum
;
156 VolumeData
->SignedMinimum
= Range
->Bounds
.SignedMinimum
;
157 VolumeData
->SteppingDelta
= Range
->SteppingDelta
;
158 VolumeData
->ValuesCount
= Steps
;
159 VolumeData
->InputSteppingDelta
= 0x10000 / Steps
;
161 VolumeData
->Values
= (PLONG
)MixerContext
->Alloc(sizeof(LONG
) * Steps
);
162 if (!VolumeData
->Values
)
164 MixerContext
->Free(Desc
);
165 MixerContext
->Free(VolumeData
);
166 return MM_STATUS_NO_MEMORY
;
169 Value
= Range
->Bounds
.SignedMinimum
;
170 for(Index
= 0; Index
< Steps
; Index
++)
172 VolumeData
->Values
[Index
] = Value
;
173 Value
+= Range
->SteppingDelta
;
175 InsertTailList(&MixerLine
->LineControlsExtraData
, &VolumeData
->Header
.Entry
);
178 MixerContext
->Free(Desc
);
181 DPRINT("Status %x Name %S\n", Status
, MixerControl
->szName
);
182 return MM_STATUS_SUCCESS
;
186 MMixerCreateDestinationLine(
187 IN PMIXER_CONTEXT MixerContext
,
188 IN LPMIXER_INFO MixerInfo
,
189 IN ULONG bInputMixer
,
192 LPMIXERLINE_EXT DestinationLine
;
194 /* allocate a mixer destination line */
195 DestinationLine
= (LPMIXERLINE_EXT
) MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
199 return MM_STATUS_NO_MEMORY
;
202 /* initialize mixer destination line */
203 DestinationLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
204 DestinationLine
->Line
.dwSource
= MAXULONG
;
205 DestinationLine
->Line
.dwLineID
= DESTINATION_LINE
;
206 DestinationLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
;
207 DestinationLine
->Line
.dwUser
= 0;
208 DestinationLine
->Line
.dwComponentType
= (bInputMixer
== 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
);
209 DestinationLine
->Line
.cChannels
= 2; /* FIXME */
213 MixerContext
->Copy(DestinationLine
->Line
.szShortName
, LineName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
214 DestinationLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
216 MixerContext
->Copy(DestinationLine
->Line
.szName
, LineName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
217 DestinationLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
221 DestinationLine
->Line
.Target
.dwType
= (bInputMixer
== 0 ? MIXERLINE_TARGETTYPE_WAVEOUT
: MIXERLINE_TARGETTYPE_WAVEIN
);
222 DestinationLine
->Line
.Target
.dwDeviceID
= !bInputMixer
;
223 DestinationLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
224 DestinationLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
225 DestinationLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
227 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == 0);
228 wcscpy(DestinationLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
230 /* initialize extra line */
231 InitializeListHead(&DestinationLine
->LineControlsExtraData
);
233 /* insert into mixer info */
234 InsertHeadList(&MixerInfo
->LineList
, &DestinationLine
->Entry
);
237 return MM_STATUS_SUCCESS
;
242 IN PMIXER_CONTEXT MixerContext
,
243 IN LPMIXER_INFO MixerInfo
,
245 IN OUT LPWSTR
* OutBuffer
)
255 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
256 Pin
.Property
.Set
= KSPROPSETID_Pin
;
257 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
259 /* try get pin name size */
260 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
262 /* check if buffer overflowed */
263 if (Status
== MM_STATUS_MORE_ENTRIES
)
265 /* allocate buffer */
266 Buffer
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
270 return MM_STATUS_NO_MEMORY
;
273 /* try get pin name */
274 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Buffer
, BytesReturned
, &BytesReturned
);
275 if (Status
!= MM_STATUS_SUCCESS
)
277 /* failed to get pin name */
278 MixerContext
->Free((PVOID
)Buffer
);
282 /* successfully obtained pin name */
284 return MM_STATUS_SUCCESS
;
287 /* failed to get pin name */
292 MMixerBuildMixerDestinationLine(
293 IN PMIXER_CONTEXT MixerContext
,
294 IN OUT LPMIXER_INFO MixerInfo
,
301 /* try get pin name */
302 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, PinId
, &PinName
);
303 if (Status
== MM_STATUS_SUCCESS
)
305 /* create mixer destination line */
307 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, PinName
);
310 MixerContext
->Free(PinName
);
314 /* create mixer destination line unlocalized */
315 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, L
"No Name");
323 IN PMIXER_CONTEXT MixerContext
,
324 IN LPMIXER_DATA MixerData
,
325 OUT PTOPOLOGY
* OutTopology
)
328 PKSMULTIPLE_ITEM NodeTypes
= NULL
;
329 PKSMULTIPLE_ITEM NodeConnections
= NULL
;
332 if (MixerData
->Topology
)
334 /* re-use existing topology */
335 *OutTopology
= MixerData
->Topology
;
337 return MM_STATUS_SUCCESS
;
340 /* get connected filter pin count */
341 PinsCount
= MMixerGetFilterPinCount(MixerContext
, MixerData
->hDevice
);
345 /* referenced filter does not have any pins */
346 return MM_STATUS_UNSUCCESSFUL
;
349 /* get topology node types */
350 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
351 if (Status
!= MM_STATUS_SUCCESS
)
353 /* failed to get topology node types */
357 /* get topology connections */
358 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
359 if (Status
!= MM_STATUS_SUCCESS
)
361 /* failed to get topology connections */
362 MixerContext
->Free(NodeTypes
);
366 /* create a topology */
367 Status
= MMixerCreateTopology(MixerContext
, PinsCount
, NodeConnections
, NodeTypes
, OutTopology
);
369 /* free node types & connections */
370 MixerContext
->Free(NodeConnections
);
371 MixerContext
->Free(NodeTypes
);
373 if (Status
== MM_STATUS_SUCCESS
)
375 /* store topology object */
376 MixerData
->Topology
= *OutTopology
;
384 MMixerCountMixerControls(
385 IN PMIXER_CONTEXT MixerContext
,
386 IN PTOPOLOGY Topology
,
389 OUT PULONG OutNodesCount
,
391 OUT PULONG OutLineTerminator
)
394 ULONG NodesCount
, NodeIndex
, Count
, bTerminator
;
397 /* allocate an array to store all nodes which are upstream of this pin */
398 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
400 if (Status
!= MM_STATUS_SUCCESS
)
403 return STATUS_NO_MEMORY
;
406 /* mark result array as zero */
410 MMixerGetNextNodesFromPinIndex(MixerContext
, Topology
, PinId
, bUpStream
, &NodesCount
, Nodes
);
412 /* assume no topology split before getting line terminator */
413 ASSERT(NodesCount
== 1);
416 NodeIndex
= Nodes
[0];
421 /* check if the node is a terminator */
422 MMixerIsNodeTerminator(Topology
, NodeIndex
, &bTerminator
);
426 /* found terminator */
431 OutNodes
[Count
] = NodeIndex
;
433 /* increment node count */
436 /* get next nodes upstream */
437 MMixerGetNextNodesFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bUpStream
, &NodesCount
, Nodes
);
439 /* assume there is a node connected */
440 ASSERT(NodesCount
!= 0);
441 ASSERT(NodesCount
== 1);
443 /* use first index */
444 NodeIndex
= Nodes
[0];
448 /* free node index */
449 MixerContext
->Free(Nodes
);
451 /* store nodes count */
452 *OutNodesCount
= Count
;
454 /* store line terminator */
455 *OutLineTerminator
= NodeIndex
;
458 return MM_STATUS_SUCCESS
;
462 MMixerAddMixerControlsToMixerLineByNodeIndexArray(
463 IN PMIXER_CONTEXT MixerContext
,
464 IN LPMIXER_INFO MixerInfo
,
465 IN PTOPOLOGY Topology
,
466 IN OUT LPMIXERLINE_EXT DstLine
,
470 ULONG Index
, Count
, bReserved
;
473 /* store nodes array */
474 DstLine
->NodeIds
= Nodes
;
476 /* allocate MIXERCONTROLSW array */
477 DstLine
->LineControls
= MixerContext
->Alloc(NodesCount
* sizeof(MIXERCONTROLW
));
479 if (!DstLine
->LineControls
)
482 return MM_STATUS_NO_MEMORY
;
485 /* initialize control count */
488 for(Index
= 0; Index
< NodesCount
; Index
++)
490 /* check if the node has already been reserved to a line */
491 MMixerIsTopologyNodeReserved(Topology
, Nodes
[Index
], &bReserved
);
495 /* node is already used, skip it */
499 /* set node status as used */
500 MMixerSetTopologyNodeReserved(Topology
, Nodes
[Index
]);
502 /* now add the mixer control */
503 Status
= MMixerAddMixerControl(MixerContext
, MixerInfo
, Topology
, Nodes
[Index
], DstLine
, &DstLine
->LineControls
[Count
]);
505 if (Status
== MM_STATUS_SUCCESS
)
507 /* increment control count */
512 /* store control count */
513 DstLine
->Line
.cControls
= Count
;
516 return MM_STATUS_SUCCESS
;
520 MMixerBuildMixerSourceLine(
521 IN PMIXER_CONTEXT MixerContext
,
522 IN OUT LPMIXER_INFO MixerInfo
,
523 IN PTOPOLOGY Topology
,
527 OUT LPMIXERLINE_EXT
* OutSrcLine
)
529 LPMIXERLINE_EXT SrcLine
, DstLine
;
533 /* construct source line */
534 SrcLine
= (LPMIXERLINE_EXT
)MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
539 return MM_STATUS_NO_MEMORY
;
542 /* get destination line */
543 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
546 /* initialize mixer src line */
547 SrcLine
->hDevice
= MixerInfo
->hMixer
;
548 SrcLine
->PinId
= PinId
;
549 SrcLine
->NodeIds
= Nodes
;
551 /* initialize mixer line */
552 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
553 SrcLine
->Line
.dwDestination
= 0;
554 SrcLine
->Line
.dwSource
= DstLine
->Line
.cConnections
;
555 SrcLine
->Line
.dwLineID
= (DstLine
->Line
.cConnections
* 0x10000);
556 SrcLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
| MIXERLINE_LINEF_SOURCE
;
557 SrcLine
->Line
.dwUser
= 0;
558 SrcLine
->Line
.cChannels
= DstLine
->Line
.cChannels
;
559 SrcLine
->Line
.cConnections
= 0;
560 SrcLine
->Line
.Target
.dwType
= 1;
561 SrcLine
->Line
.Target
.dwDeviceID
= DstLine
->Line
.Target
.dwDeviceID
;
562 SrcLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
563 SrcLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
564 SrcLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
565 InitializeListHead(&SrcLine
->LineControlsExtraData
);
568 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == L
'\0');
569 wcscpy(SrcLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
572 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, PinId
, &PinName
);
574 if (Status
== MM_STATUS_SUCCESS
)
576 /* store pin name as line name */
577 MixerContext
->Copy(SrcLine
->Line
.szShortName
, PinName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
578 SrcLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
580 MixerContext
->Copy(SrcLine
->Line
.szName
, PinName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
581 SrcLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
583 /* free pin name buffer */
584 MixerContext
->Free(PinName
);
587 /* add the controls to mixer line */
588 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, Topology
, SrcLine
, NodesCount
, Nodes
);
589 if (Status
!= MM_STATUS_SUCCESS
)
596 *OutSrcLine
= SrcLine
;
598 return MM_STATUS_SUCCESS
;
602 MMixerAddMixerSourceLines(
603 IN PMIXER_CONTEXT MixerContext
,
604 IN OUT LPMIXER_INFO MixerInfo
,
605 IN PTOPOLOGY Topology
,
606 IN ULONG LineTerminator
)
608 PULONG AllNodes
, AllPins
, AllPinNodes
;
609 ULONG AllNodesCount
, AllPinsCount
, AllPinNodesCount
;
610 ULONG Index
, SubIndex
, PinId
, CurNode
, bConnected
;
612 LPMIXERLINE_EXT DstLine
, SrcLine
;
614 /* get destination line */
615 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
618 /* allocate an array to store all nodes which are upstream of the line terminator */
619 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllNodes
);
621 /* check for success */
622 if (Status
!= MM_STATUS_SUCCESS
)
625 return MM_STATUS_NO_MEMORY
;
628 /* allocate an array to store all nodes which are downstream of a particular pin */
629 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllPinNodes
);
631 /* allocate an array to store all pins which are upstream of this pin */
632 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &AllPins
);
634 /* check for success */
635 if (Status
!= MM_STATUS_SUCCESS
)
638 MixerContext
->Free(AllNodes
);
639 return MM_STATUS_NO_MEMORY
;
642 /* get all nodes which indirectly / directly connect to this node */
644 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllNodesCount
, AllNodes
);
646 /* get all pins which indirectly / directly connect to this node */
648 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllPinsCount
, AllPins
);
650 DPRINT("LineTerminator %lu\n", LineTerminator
);
651 DPRINT("PinCount %lu\n", AllPinsCount
);
652 DPRINT("AllNodesCount %lu\n", AllNodesCount
);
654 /* now construct the source lines which are attached to the destination line */
655 Index
= AllPinsCount
;
659 /* get current pin id */
660 PinId
= AllPins
[Index
- 1];
662 /* reset nodes count */
663 AllPinNodesCount
= 0;
665 /* now scan all nodes and add them to AllPinNodes array when they are connected to this pin */
666 for(SubIndex
= 0; SubIndex
< AllNodesCount
; SubIndex
++)
668 /* get current node index */
669 CurNode
= AllNodes
[SubIndex
];
671 if (CurNode
!= MAXULONG
&& CurNode
!= LineTerminator
)
673 /* check if that node is connected in some way to the current pin */
674 Status
= MMixerIsNodeConnectedToPin(MixerContext
, Topology
, CurNode
, PinId
, TRUE
, &bConnected
);
676 if (Status
!= MM_STATUS_SUCCESS
)
681 /* it is connected */
682 AllPinNodes
[AllPinNodesCount
] = CurNode
;
685 /* clear current index */
686 AllNodes
[SubIndex
] = MAXULONG
;
691 /* decrement pin index */
694 if (AllPinNodesCount
)
696 /* now build the mixer source line */
697 Status
= MMixerBuildMixerSourceLine(MixerContext
, MixerInfo
, Topology
, PinId
, AllPinNodesCount
, AllPinNodes
, &SrcLine
);
699 if (Status
== MM_STATUS_SUCCESS
)
701 /* insert into line list */
702 InsertTailList(&MixerInfo
->LineList
, &SrcLine
->Entry
);
704 /* increment destination line count */
705 DstLine
->Line
.cConnections
++;
711 return MM_STATUS_SUCCESS
;
716 MMixerAddMixerControlsToDestinationLine(
717 IN PMIXER_CONTEXT MixerContext
,
718 IN OUT LPMIXER_INFO MixerInfo
,
719 IN PTOPOLOGY Topology
,
722 OUT PULONG OutLineTerminator
)
725 ULONG NodesCount
, LineTerminator
;
727 LPMIXERLINE_EXT DstLine
;
729 /* allocate nodes index array */
730 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
732 /* check for success */
733 if (Status
!= MM_STATUS_SUCCESS
)
736 return MM_STATUS_NO_MEMORY
;
739 /* get all destination line controls */
740 Status
= MMixerCountMixerControls(MixerContext
, Topology
, PinId
, TRUE
, &NodesCount
, Nodes
, &LineTerminator
);
742 /* check for success */
743 if (Status
!= MM_STATUS_SUCCESS
)
745 /* failed to count controls */
746 MixerContext
->Free(Nodes
);
750 /* get destination mixer line */
751 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
758 /* add all nodes as mixer controls to the destination line */
759 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, Topology
, DstLine
, NodesCount
, Nodes
);
760 if (Status
!= MM_STATUS_SUCCESS
)
762 /* failed to add controls */
763 MixerContext
->Free(Nodes
);
769 *OutLineTerminator
= LineTerminator
;
776 MMixerApplyOutputFilterHack(
777 IN PMIXER_CONTEXT MixerContext
,
778 IN LPMIXER_DATA MixerData
,
779 IN OUT PULONG PinsCount
,
782 ULONG Count
= 0, Index
;
784 PKSPIN_PHYSICALCONNECTION Connection
;
786 for(Index
= 0; Index
< *PinsCount
; Index
++)
788 /* check if it has a physical connection */
789 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Pins
[Index
], &Connection
);
791 if (Status
== MM_STATUS_SUCCESS
)
794 MixerContext
->Copy(&Pins
[Index
], &Pins
[Index
+ 1], (*PinsCount
- (Index
+ 1)) * sizeof(ULONG
));
796 /* free physical connection */
797 MixerContext
->Free(Connection
);
799 /* decrement index */
802 /* decrement pin count */
817 MMixerHandlePhysicalConnection(
818 IN PMIXER_CONTEXT MixerContext
,
819 IN PMIXER_LIST MixerList
,
820 IN LPMIXER_DATA MixerData
,
821 IN OUT LPMIXER_INFO MixerInfo
,
823 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
826 ULONG PinsCount
, LineTerminator
;
830 /* first try to open the connected filter */
831 OutConnection
->SymbolicLinkName
[1] = L
'\\';
832 MixerData
= MMixerGetDataByDeviceName(MixerList
, OutConnection
->SymbolicLinkName
);
834 /* check if the linked connection is found */
837 /* filter references invalid physical connection */
838 return MM_STATUS_UNSUCCESSFUL
;
841 DPRINT("Name %S, Pin %lu bInput %lu\n", OutConnection
->SymbolicLinkName
, OutConnection
->Pin
, bInput
);
843 /* store connected mixer handle */
844 MixerInfo
->hMixer
= MixerData
->hDevice
;
847 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
848 if (Status
!= MM_STATUS_SUCCESS
)
850 /* failed to create topology */
854 /* allocate pin index array which will hold all referenced pins */
855 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
856 ASSERT(Status
== MM_STATUS_SUCCESS
);
860 /* the mixer is an output mixer
861 * find end pin of the node path
864 Status
= MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext
, Topology
, OutConnection
->Pin
, FALSE
, &PinsCount
, Pins
);
866 /* check for success */
867 if (Status
!= MM_STATUS_SUCCESS
)
869 /* failed to get end pin */
870 MixerContext
->Free(Pins
);
871 //MMixerFreeTopology(Topology);
873 /* return error code */
877 * some topologies do not have strict boundaries
878 * WorkArround: remove all pin ids which have a physical connection
879 * because bridge pins may belong to different render paths
881 MMixerApplyOutputFilterHack(MixerContext
, MixerData
, &PinsCount
, Pins
);
884 ASSERT(PinsCount
!= 0);
885 ASSERT(PinsCount
== 1);
887 /* create destination line */
888 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, Pins
[0], bInput
);
890 if (Status
!= MM_STATUS_SUCCESS
)
892 MixerContext
->Free(Pins
);
893 //MMixerFreeTopology(Topology);
895 /* return error code */
899 /* add mixer controls to destination line */
900 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, Topology
, Pins
[0], bInput
, &LineTerminator
);
902 if (Status
== MM_STATUS_SUCCESS
)
904 /* now add the rest of the source lines */
905 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, Topology
, LineTerminator
);
910 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, Topology
, OutConnection
->Pin
, bInput
, &LineTerminator
);
912 if (Status
== MM_STATUS_SUCCESS
)
914 /* now add the rest of the source lines */
915 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, Topology
, LineTerminator
);
920 //MMixerFreeTopology(Topology);
927 MMixerInitializeFilter(
928 IN PMIXER_CONTEXT MixerContext
,
929 IN PMIXER_LIST MixerList
,
930 IN LPMIXER_DATA MixerData
,
931 IN PTOPOLOGY Topology
,
933 IN ULONG bInputMixer
)
935 LPMIXER_INFO MixerInfo
;
937 PKSPIN_PHYSICALCONNECTION OutConnection
;
941 /* allocate a mixer info struct */
942 MixerInfo
= (LPMIXER_INFO
) MixerContext
->Alloc(sizeof(MIXER_INFO
));
946 return MM_STATUS_NO_MEMORY
;
949 /* intialize mixer caps */
950 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; /* FIXME */
951 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; /* FIXME */
952 MixerInfo
->MixCaps
.vDriverVersion
= 1; /* FIXME */
953 MixerInfo
->MixCaps
.fdwSupport
= 0;
954 MixerInfo
->MixCaps
.cDestinations
= 1;
955 MixerInfo
->hMixer
= MixerData
->hDevice
;
958 MMixerGetDeviceName(MixerContext
, MixerInfo
, MixerData
->hDeviceInterfaceKey
);
960 /* initialize line list */
961 InitializeListHead(&MixerInfo
->LineList
);
962 InitializeListHead(&MixerInfo
->EventList
);
964 /* now allocate an array which will receive the indices of the pin
965 * which has a ADC / DAC nodetype in its path
967 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
968 ASSERT(Status
== MM_STATUS_SUCCESS
);
972 /* now get all sink / source pins, which are attached to the ADC / DAC node
973 * For sink pins (wave out) search up stream
974 * For source pins (wave in) search down stream
975 * The search direction is always the opposite of the current mixer type
978 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, !bInputMixer
, &PinsFound
, Pins
);
980 /* if there is now pin found, we have a broken topology */
981 ASSERT(PinsFound
!= 0);
983 /* now create a wave info struct */
984 Status
= MMixerInitializeWaveInfo(MixerContext
, MixerList
, MixerData
, MixerInfo
->MixCaps
.szPname
, bInputMixer
, PinsFound
, Pins
);
985 if (Status
!= MM_STATUS_SUCCESS
)
987 /* failed to create wave info struct */
988 MixerContext
->Free(MixerInfo
);
989 MixerContext
->Free(Pins
);
995 /* pre create the mixer destination line for input mixers */
996 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, Pins
[0], bInputMixer
);
998 if (Status
!= MM_STATUS_SUCCESS
)
1000 /* failed to create mixer destination line */
1006 /* now get the bridge pin which is at the end of node path
1007 * For sink pins (wave out) search down stream
1008 * For source pins (wave in) search up stream
1010 MixerContext
->Free(Pins
);
1011 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1012 ASSERT(Status
== MM_STATUS_SUCCESS
);
1015 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bInputMixer
, &PinsFound
, Pins
);
1017 /* if there is no pin found, we have a broken topology */
1018 ASSERT(PinsFound
!= 0);
1020 /* there should be exactly one bridge pin */
1021 ASSERT(PinsFound
== 1);
1023 DPRINT("BridgePin %lu bInputMixer %lu\n", Pins
[0], bInputMixer
);
1025 /* does the pin have a physical connection */
1026 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Pins
[0], &OutConnection
);
1028 if (Status
== MM_STATUS_SUCCESS
)
1030 /* topology on the topoloy filter */
1031 Status
= MMixerHandlePhysicalConnection(MixerContext
, MixerList
, MixerData
, MixerInfo
, bInputMixer
, OutConnection
);
1033 /* free physical connection data */
1034 MixerContext
->Free(OutConnection
);
1039 * handle drivers which expose their topology on the same filter
1045 MixerContext
->Free(Pins
);
1047 if (!bInputMixer
&& MixerList
->MixerListCount
== 1)
1049 /* FIXME preferred device should be inserted at front
1050 * windows always inserts output mixer in front
1052 InsertHeadList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1056 /* insert at back */
1057 InsertTailList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1060 /* increment mixer count */
1061 MixerList
->MixerListCount
++;
1069 IN PMIXER_CONTEXT MixerContext
,
1070 IN PMIXER_LIST MixerList
,
1071 IN LPMIXER_DATA MixerData
,
1072 IN PULONG DeviceCount
)
1074 MIXER_STATUS Status
;
1078 /* check if topology has already been built */
1079 if (MixerData
->Topology
== NULL
)
1081 /* build topology */
1082 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1084 if (Status
!= MM_STATUS_SUCCESS
)
1086 /* failed to build topology */
1090 /* store topology */
1091 MixerData
->Topology
= Topology
;
1095 /* re-use topology */
1096 Topology
= MixerData
->Topology
;
1099 /* check if the filter has an wave out node */
1100 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_DAC
);
1101 if (NodeIndex
!= MAXULONG
)
1104 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, Topology
, NodeIndex
, FALSE
);
1106 /* check for success */
1107 if (Status
== MM_STATUS_SUCCESS
)
1109 /* increment mixer count */
1115 /* check if the filter has an wave in node */
1116 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_ADC
);
1117 if (NodeIndex
!= MAXULONG
)
1120 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, Topology
, NodeIndex
, TRUE
);
1122 /* check for success */
1123 if (Status
== MM_STATUS_SUCCESS
)
1125 /* increment mixer count */
1138 IN PMIXER_CONTEXT MixerContext
,
1139 IN OUT LPMIXER_INFO MixerInfo
,
1140 IN PVOID MixerEventContext
,
1141 IN PMIXER_EVENT MixerEventRoutine
)
1143 //KSE_NODE Property;
1144 PEVENT_NOTIFICATION_ENTRY EventData
;
1145 //ULONG BytesReturned;
1146 //MIXER_STATUS Status;
1148 EventData
= (PEVENT_NOTIFICATION_ENTRY
)MixerContext
->AllocEventData(sizeof(EVENT_NOTIFICATION_ENTRY
));
1151 /* not enough memory */
1152 return MM_STATUS_NO_MEMORY
;
1157 Property
.Event
.Set
= KSEVENTSETID_AudioControlChange
;
1158 Property
.Event
.Flags
= KSEVENT_TYPE_TOPOLOGY
|KSEVENT_TYPE_ENABLE
;
1159 Property
.Event
.Id
= KSEVENT_CONTROL_CHANGE
;
1161 Property
.NodeId
= NodeId
;
1162 Property
.Reserved
= 0;
1164 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSP_NODE
), (PVOID
)EventData
, sizeof(KSEVENTDATA
), &BytesReturned
);
1165 if (Status
!= MM_STATUS_SUCCESS
)
1167 /* failed to add event */
1168 MixerContext
->FreeEventData(EventData
);
1173 /* initialize notification entry */
1174 EventData
->MixerEventContext
= MixerEventContext
;
1175 EventData
->MixerEventRoutine
;
1178 InsertTailList(&MixerInfo
->EventList
, &EventData
->Entry
);
1179 return MM_STATUS_SUCCESS
;