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 MMixerHandlePhysicalConnection(
777 IN PMIXER_CONTEXT MixerContext
,
778 IN PMIXER_LIST MixerList
,
779 IN LPMIXER_DATA MixerData
,
780 IN OUT LPMIXER_INFO MixerInfo
,
782 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
785 ULONG PinsCount
, LineTerminator
;
789 /* first try to open the connected filter */
790 OutConnection
->SymbolicLinkName
[1] = L
'\\';
791 MixerData
= MMixerGetDataByDeviceName(MixerList
, OutConnection
->SymbolicLinkName
);
793 /* check if the linked connection is found */
796 /* filter references invalid physical connection */
797 return MM_STATUS_UNSUCCESSFUL
;
800 DPRINT("Name %S, Pin %lu bInput %lu\n", OutConnection
->SymbolicLinkName
, OutConnection
->Pin
, bInput
);
802 /* store connected mixer handle */
803 MixerInfo
->hMixer
= MixerData
->hDevice
;
806 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
807 if (Status
!= MM_STATUS_SUCCESS
)
809 /* failed to create topology */
813 /* allocate pin index array which will hold all referenced pins */
814 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
815 ASSERT(Status
== MM_STATUS_SUCCESS
);
819 /* the mixer is an output mixer
820 * find end pin of the node path
823 Status
= MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext
, Topology
, OutConnection
->Pin
, FALSE
, &PinsCount
, Pins
);
825 /* check for success */
826 if (Status
!= MM_STATUS_SUCCESS
)
828 /* failed to get end pin */
829 MixerContext
->Free(Pins
);
830 //MMixerFreeTopology(Topology);
832 /* return error code */
837 ASSERT(PinsCount
!= 0);
838 //ASSERT(PinsCount == 1);
840 /* create destination line */
841 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, Pins
[0], bInput
);
843 if (Status
!= MM_STATUS_SUCCESS
)
845 MixerContext
->Free(Pins
);
846 //MMixerFreeTopology(Topology);
848 /* return error code */
852 /* add mixer controls to destination line */
853 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, Topology
, Pins
[0], bInput
, &LineTerminator
);
855 if (Status
== MM_STATUS_SUCCESS
)
857 /* now add the rest of the source lines */
858 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, Topology
, LineTerminator
);
863 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, Topology
, OutConnection
->Pin
, bInput
, &LineTerminator
);
865 if (Status
== MM_STATUS_SUCCESS
)
867 /* now add the rest of the source lines */
868 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, Topology
, LineTerminator
);
873 //MMixerFreeTopology(Topology);
880 MMixerInitializeFilter(
881 IN PMIXER_CONTEXT MixerContext
,
882 IN PMIXER_LIST MixerList
,
883 IN LPMIXER_DATA MixerData
,
884 IN PTOPOLOGY Topology
,
886 IN ULONG bInputMixer
)
888 LPMIXER_INFO MixerInfo
;
890 PKSPIN_PHYSICALCONNECTION OutConnection
;
894 /* allocate a mixer info struct */
895 MixerInfo
= (LPMIXER_INFO
) MixerContext
->Alloc(sizeof(MIXER_INFO
));
899 return MM_STATUS_NO_MEMORY
;
902 /* intialize mixer caps */
903 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; /* FIXME */
904 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; /* FIXME */
905 MixerInfo
->MixCaps
.vDriverVersion
= 1; /* FIXME */
906 MixerInfo
->MixCaps
.fdwSupport
= 0;
907 MixerInfo
->MixCaps
.cDestinations
= 1;
908 MixerInfo
->hMixer
= MixerData
->hDevice
;
911 MMixerGetDeviceName(MixerContext
, MixerInfo
, MixerData
->hDeviceInterfaceKey
);
913 /* initialize line list */
914 InitializeListHead(&MixerInfo
->LineList
);
915 InitializeListHead(&MixerInfo
->EventList
);
917 /* now allocate an array which will receive the indices of the pin
918 * which has a ADC / DAC nodetype in its path
920 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
921 ASSERT(Status
== MM_STATUS_SUCCESS
);
925 /* now get all sink / source pins, which are attached to the ADC / DAC node
926 * For sink pins (wave out) search up stream
927 * For source pins (wave in) search down stream
928 * The search direction is always the opposite of the current mixer type
931 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, !bInputMixer
, &PinsFound
, Pins
);
933 /* if there is now pin found, we have a broken topology */
934 ASSERT(PinsFound
!= 0);
936 /* now create a wave info struct */
937 Status
= MMixerInitializeWaveInfo(MixerContext
, MixerList
, MixerData
, MixerInfo
->MixCaps
.szPname
, bInputMixer
, PinsFound
, Pins
);
938 if (Status
!= MM_STATUS_SUCCESS
)
940 /* failed to create wave info struct */
941 MixerContext
->Free(MixerInfo
);
942 MixerContext
->Free(Pins
);
948 /* pre create the mixer destination line for input mixers */
949 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, Pins
[0], bInputMixer
);
951 if (Status
!= MM_STATUS_SUCCESS
)
953 /* failed to create mixer destination line */
959 /* now get the bridge pin which is at the end of node path
960 * For sink pins (wave out) search down stream
961 * For source pins (wave in) search up stream
963 MixerContext
->Free(Pins
);
964 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
965 ASSERT(Status
== MM_STATUS_SUCCESS
);
968 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bInputMixer
, &PinsFound
, Pins
);
970 /* if there is no pin found, we have a broken topology */
971 ASSERT(PinsFound
!= 0);
973 /* there should be exactly one bridge pin */
974 ASSERT(PinsFound
== 1);
976 DPRINT("BridgePin %lu bInputMixer %lu\n", Pins
[0], bInputMixer
);
978 /* does the pin have a physical connection */
979 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Pins
[0], &OutConnection
);
981 if (Status
== MM_STATUS_SUCCESS
)
983 /* topology on the topoloy filter */
984 Status
= MMixerHandlePhysicalConnection(MixerContext
, MixerList
, MixerData
, MixerInfo
, bInputMixer
, OutConnection
);
986 /* free physical connection data */
987 MixerContext
->Free(OutConnection
);
992 * handle drivers which expose their topology on the same filter
998 MixerContext
->Free(Pins
);
1000 if (!bInputMixer
&& MixerList
->MixerListCount
== 1)
1002 /* FIXME preferred device should be inserted at front
1003 * windows always inserts output mixer in front
1005 InsertHeadList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1009 /* insert at back */
1010 InsertTailList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1013 /* increment mixer count */
1014 MixerList
->MixerListCount
++;
1022 IN PMIXER_CONTEXT MixerContext
,
1023 IN PMIXER_LIST MixerList
,
1024 IN LPMIXER_DATA MixerData
,
1025 IN PULONG DeviceCount
)
1027 MIXER_STATUS Status
;
1031 /* check if topology has already been built */
1032 if (MixerData
->Topology
== NULL
)
1034 /* build topology */
1035 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1037 if (Status
!= MM_STATUS_SUCCESS
)
1039 /* failed to build topology */
1043 /* store topology */
1044 MixerData
->Topology
= Topology
;
1048 /* re-use topology */
1049 Topology
= MixerData
->Topology
;
1052 /* check if the filter has an wave out node */
1053 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_DAC
);
1054 if (NodeIndex
!= MAXULONG
)
1057 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, Topology
, NodeIndex
, FALSE
);
1059 /* check for success */
1060 if (Status
== MM_STATUS_SUCCESS
)
1062 /* increment mixer count */
1068 /* check if the filter has an wave in node */
1069 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_ADC
);
1070 if (NodeIndex
!= MAXULONG
)
1073 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, Topology
, NodeIndex
, TRUE
);
1075 /* check for success */
1076 if (Status
== MM_STATUS_SUCCESS
)
1078 /* increment mixer count */
1091 IN PMIXER_CONTEXT MixerContext
,
1092 IN OUT LPMIXER_INFO MixerInfo
,
1093 IN PVOID MixerEventContext
,
1094 IN PMIXER_EVENT MixerEventRoutine
)
1096 //KSE_NODE Property;
1097 PEVENT_NOTIFICATION_ENTRY EventData
;
1098 //ULONG BytesReturned;
1099 //MIXER_STATUS Status;
1101 EventData
= (PEVENT_NOTIFICATION_ENTRY
)MixerContext
->AllocEventData(sizeof(EVENT_NOTIFICATION_ENTRY
));
1104 /* not enough memory */
1105 return MM_STATUS_NO_MEMORY
;
1110 Property
.Event
.Set
= KSEVENTSETID_AudioControlChange
;
1111 Property
.Event
.Flags
= KSEVENT_TYPE_TOPOLOGY
|KSEVENT_TYPE_ENABLE
;
1112 Property
.Event
.Id
= KSEVENT_CONTROL_CHANGE
;
1114 Property
.NodeId
= NodeId
;
1115 Property
.Reserved
= 0;
1117 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSP_NODE
), (PVOID
)EventData
, sizeof(KSEVENTDATA
), &BytesReturned
);
1118 if (Status
!= MM_STATUS_SUCCESS
)
1120 /* failed to add event */
1121 MixerContext
->FreeEventData(EventData
);
1126 /* initialize notification entry */
1127 EventData
->MixerEventContext
= MixerEventContext
;
1128 EventData
->MixerEventRoutine
;
1131 InsertTailList(&MixerInfo
->EventList
, &EventData
->Entry
);
1132 return MM_STATUS_SUCCESS
;