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
,
21 PKSTOPOLOGY_CONNECTION Connection
;
22 ULONG PinId
, NodeConnectionCount
, Index
;
23 PULONG NodeConnection
;
28 ASSERT(NodeConnectionIndex
< NodeConnections
->Count
);
30 Connection
= (PKSTOPOLOGY_CONNECTION
)(NodeConnections
+ 1);
32 //DPRINT("FromNode %u FromNodePin %u -> ToNode %u ToNodePin %u\n", Connection[NodeConnectionIndex].FromNode, Connection[NodeConnectionIndex].FromNodePin, Connection[NodeConnectionIndex].ToNode, Connection[NodeConnectionIndex].ToNodePin );
34 if ((Connection
[NodeConnectionIndex
].ToNode
== KSFILTER_NODE
&& bUpDirection
== FALSE
) ||
35 (Connection
[NodeConnectionIndex
].FromNode
== KSFILTER_NODE
&& bUpDirection
== TRUE
))
37 /* iteration stops here */
39 PinId
= Connection
[NodeConnectionIndex
].FromNodePin
;
41 PinId
= Connection
[NodeConnectionIndex
].ToNodePin
;
43 //DPRINT("GetTargetPinsByNodeIndex FOUND Target Pin %u Parsed %u\n", PinId, Pins[PinId]);
46 ASSERT(PinId
< PinCount
);
48 /* mark pin index as a target pin */
50 return MM_STATUS_SUCCESS
;
53 // get all node indexes referenced by that node
56 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, Connection
[NodeConnectionIndex
].FromNode
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
60 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, Connection
[NodeConnectionIndex
].ToNode
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
63 if (Status
== MM_STATUS_SUCCESS
)
65 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
67 // iterate recursively into the nodes
68 Status
= MMixerGetTargetPinsByNodeConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], PinCount
, Pins
);
69 ASSERT(Status
== MM_STATUS_SUCCESS
);
71 // free node connection indexes
72 MixerContext
->Free(NodeConnection
);
79 MMixerGetControlsFromPinByConnectionIndex(
80 IN PMIXER_CONTEXT MixerContext
,
81 IN PKSMULTIPLE_ITEM NodeConnections
,
82 IN PKSMULTIPLE_ITEM NodeTypes
,
83 IN ULONG bUpDirection
,
84 IN ULONG NodeConnectionIndex
,
87 PKSTOPOLOGY_CONNECTION CurConnection
;
91 ULONG NodeConnectionCount
, Index
;
92 PULONG NodeConnection
;
95 /* get current connection */
96 CurConnection
= MMixerGetConnectionByIndex(NodeConnections
, NodeConnectionIndex
);
99 NodeIndex
= CurConnection
->FromNode
;
101 NodeIndex
= CurConnection
->ToNode
;
103 if (NodeIndex
> NodeTypes
->Count
)
105 // reached end of pin connection
106 return MM_STATUS_SUCCESS
;
109 /* get target node type of current connection */
110 NodeType
= MMixerGetNodeType(NodeTypes
, NodeIndex
);
112 if (IsEqualGUIDAligned(NodeType
, &KSNODETYPE_SUM
) || IsEqualGUIDAligned(NodeType
, &KSNODETYPE_MUX
))
116 /* add the sum / mux node to destination line */
117 Nodes
[NodeIndex
] = TRUE
;
120 return MM_STATUS_SUCCESS
;
123 /* now add the node */
124 Nodes
[NodeIndex
] = TRUE
;
127 /* get all node indexes referenced by that node */
130 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, NodeIndex
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
134 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, NodeIndex
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
137 if (Status
== MM_STATUS_SUCCESS
)
139 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
141 /* iterate recursively into the nodes */
142 Status
= MMixerGetControlsFromPinByConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Nodes
);
143 ASSERT(Status
== MM_STATUS_SUCCESS
);
145 /* free node connection indexes */
146 MixerContext
->Free(NodeConnection
);
153 MMixerAddMixerControl(
154 IN PMIXER_CONTEXT MixerContext
,
155 IN LPMIXER_INFO MixerInfo
,
157 IN PKSMULTIPLE_ITEM NodeTypes
,
159 IN LPMIXERLINE_EXT MixerLine
,
160 OUT LPMIXERCONTROLW MixerControl
)
168 /* initialize mixer control */
169 MixerControl
->cbStruct
= sizeof(MIXERCONTROLW
);
170 MixerControl
->dwControlID
= MixerInfo
->ControlId
;
173 NodeType
= MMixerGetNodeType(NodeTypes
, NodeIndex
);
174 /* store control type */
175 MixerControl
->dwControlType
= MMixerGetControlTypeFromTopologyNode(NodeType
);
177 MixerControl
->fdwControl
= MIXERCONTROL_CONTROLF_UNIFORM
; //FIXME
178 MixerControl
->cMultipleItems
= 0; //FIXME
180 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
182 MixerControl
->Bounds
.dwMinimum
= 0;
183 MixerControl
->Bounds
.dwMaximum
= 1;
185 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
187 MixerControl
->Bounds
.dwMinimum
= 0;
188 MixerControl
->Bounds
.dwMaximum
= 0xFFFF;
189 MixerControl
->Metrics
.cSteps
= 0xC0; //FIXME
192 /* setup request to retrieve name */
193 Node
.NodeId
= NodeIndex
;
194 Node
.Property
.Id
= KSPROPERTY_TOPOLOGY_NAME
;
195 Node
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
196 Node
.Property
.Set
= KSPROPSETID_Topology
;
199 /* get node name size */
200 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), NULL
, 0, &BytesReturned
);
202 if (Status
== MM_STATUS_MORE_ENTRIES
)
204 ASSERT(BytesReturned
!= 0);
205 Name
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
208 /* not enough memory */
209 return MM_STATUS_NO_MEMORY
;
213 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), (LPVOID
)Name
, BytesReturned
, &BytesReturned
);
215 if (Status
== MM_STATUS_SUCCESS
)
217 MixerContext
->Copy(MixerControl
->szShortName
, Name
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
218 MixerControl
->szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
220 MixerContext
->Copy(MixerControl
->szName
, Name
, (min(MIXER_LONG_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
221 MixerControl
->szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
224 /* free name buffer */
225 MixerContext
->Free(Name
);
228 MixerInfo
->ControlId
++;
230 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUX
)
232 KSNODEPROPERTY Property
;
235 /* setup the request */
236 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY
));
238 Property
.NodeId
= NodeIndex
;
239 Property
.Property
.Id
= KSPROPERTY_AUDIO_MUX_SOURCE
;
240 Property
.Property
.Flags
= KSPROPERTY_TYPE_SET
;
241 Property
.Property
.Set
= KSPROPSETID_Audio
;
243 /* get node volume level info */
244 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY
), (PVOID
)&PinId
, sizeof(ULONG
), &BytesReturned
);
246 DPRINT1("Status %x NodeIndex %u PinId %u\n", Status
, NodeIndex
, PinId
);
250 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
252 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
254 PKSPROPERTY_DESCRIPTION Desc
;
255 PKSPROPERTY_MEMBERSHEADER Members
;
256 PKSPROPERTY_STEPPING_LONG Range
;
258 Length
= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) + sizeof(KSPROPERTY_STEPPING_LONG
);
259 Desc
= (PKSPROPERTY_DESCRIPTION
)MixerContext
->Alloc(Length
);
262 /* setup the request */
263 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
265 Property
.NodeProperty
.NodeId
= NodeIndex
;
266 Property
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
267 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
;
268 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
270 /* get node volume level info */
271 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), Desc
, Length
, &BytesReturned
);
273 if (Status
== MM_STATUS_SUCCESS
)
275 LPMIXERVOLUME_DATA VolumeData
;
276 ULONG Steps
, MaxRange
, Index
;
279 Members
= (PKSPROPERTY_MEMBERSHEADER
)(Desc
+ 1);
280 Range
= (PKSPROPERTY_STEPPING_LONG
)(Members
+ 1);
282 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
);
284 MaxRange
= Range
->Bounds
.UnsignedMaximum
- Range
->Bounds
.UnsignedMinimum
;
289 VolumeData
= (LPMIXERVOLUME_DATA
)MixerContext
->Alloc(sizeof(MIXERVOLUME_DATA
));
291 return MM_STATUS_NO_MEMORY
;
293 Steps
= MaxRange
/ Range
->SteppingDelta
+ 1;
295 /* store mixer control info there */
296 VolumeData
->Header
.dwControlID
= MixerControl
->dwControlID
;
297 VolumeData
->SignedMaximum
= Range
->Bounds
.SignedMaximum
;
298 VolumeData
->SignedMinimum
= Range
->Bounds
.SignedMinimum
;
299 VolumeData
->SteppingDelta
= Range
->SteppingDelta
;
300 VolumeData
->ValuesCount
= Steps
;
301 VolumeData
->InputSteppingDelta
= 0x10000 / Steps
;
303 VolumeData
->Values
= (PLONG
)MixerContext
->Alloc(sizeof(LONG
) * Steps
);
304 if (!VolumeData
->Values
)
306 MixerContext
->Free(Desc
);
307 MixerContext
->Free(VolumeData
);
308 return MM_STATUS_NO_MEMORY
;
311 Value
= Range
->Bounds
.SignedMinimum
;
312 for(Index
= 0; Index
< Steps
; Index
++)
314 VolumeData
->Values
[Index
] = Value
;
315 Value
+= Range
->SteppingDelta
;
317 InsertTailList(&MixerLine
->LineControlsExtraData
, &VolumeData
->Header
.Entry
);
320 MixerContext
->Free(Desc
);
323 DPRINT("Status %x Name %S\n", Status
, MixerControl
->szName
);
324 return MM_STATUS_SUCCESS
;
328 MMixerAddMixerSourceLine(
329 IN PMIXER_CONTEXT MixerContext
,
330 IN OUT LPMIXER_INFO MixerInfo
,
332 IN PKSMULTIPLE_ITEM NodeConnections
,
333 IN PKSMULTIPLE_ITEM NodeTypes
,
338 LPMIXERLINE_EXT SrcLine
, DstLine
;
343 ULONG BytesReturned
, ControlCount
, Index
;
349 /* allocate src mixer line */
350 SrcLine
= (LPMIXERLINE_EXT
)MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
353 return MM_STATUS_NO_MEMORY
;
356 RtlZeroMemory(SrcLine
, sizeof(MIXERLINE_EXT
));
361 ASSERT(!IsListEmpty(&MixerInfo
->LineList
));
362 SrcLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
365 /* get destination line */
366 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
372 /* initialize mixer src line */
373 SrcLine
->hDevice
= hDevice
;
374 SrcLine
->PinId
= PinId
;
375 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
377 /* initialize mixer destination line */
378 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
379 SrcLine
->Line
.dwDestination
= 0;
380 SrcLine
->Line
.dwSource
= DstLine
->Line
.cConnections
;
381 SrcLine
->Line
.dwLineID
= (DstLine
->Line
.cConnections
* 0x10000);
382 SrcLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
| MIXERLINE_LINEF_SOURCE
;
383 SrcLine
->Line
.dwUser
= 0;
384 SrcLine
->Line
.cChannels
= DstLine
->Line
.cChannels
;
385 SrcLine
->Line
.cConnections
= 0;
386 SrcLine
->Line
.Target
.dwType
= 1;
387 SrcLine
->Line
.Target
.dwDeviceID
= DstLine
->Line
.Target
.dwDeviceID
;
388 SrcLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
389 SrcLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
390 SrcLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
391 InitializeListHead(&SrcLine
->LineControlsExtraData
);
393 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == L
'\0');
394 wcscpy(SrcLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
398 /* allocate a node arrary */
399 Nodes
= (PULONG
)MixerContext
->Alloc(sizeof(ULONG
) * NodeTypes
->Count
);
403 /* not enough memory */
406 MixerContext
->Free(SrcLine
);
408 return MM_STATUS_NO_MEMORY
;
411 Status
= MMixerGetControlsFromPin(MixerContext
, NodeConnections
, NodeTypes
, PinId
, bTargetPin
, Nodes
);
412 if (Status
!= MM_STATUS_SUCCESS
)
414 /* something went wrong */
417 MixerContext
->Free(SrcLine
);
419 MixerContext
->Free(Nodes
);
423 /* now count all nodes controlled by that pin */
425 for(Index
= 0; Index
< NodeTypes
->Count
; Index
++)
430 Node
= MMixerGetNodeType(NodeTypes
, Index
);
432 if (MMixerGetControlTypeFromTopologyNode(Node
))
434 // found a node which can be resolved to a type
440 /* now allocate the line controls */
443 SrcLine
->LineControls
= (LPMIXERCONTROLW
)MixerContext
->Alloc(sizeof(MIXERCONTROLW
) * ControlCount
);
445 if (!SrcLine
->LineControls
)
447 /* no memory available */
450 MixerContext
->Free(SrcLine
);
452 MixerContext
->Free(Nodes
);
453 return MM_STATUS_NO_MEMORY
;
456 SrcLine
->NodeIds
= (PULONG
)MixerContext
->Alloc(sizeof(ULONG
) * ControlCount
);
457 if (!SrcLine
->NodeIds
)
459 /* no memory available */
460 MixerContext
->Free(SrcLine
->LineControls
);
463 MixerContext
->Free(SrcLine
);
465 MixerContext
->Free(Nodes
);
466 return MM_STATUS_NO_MEMORY
;
469 /* zero line controls */
470 RtlZeroMemory(SrcLine
->LineControls
, sizeof(MIXERCONTROLW
) * ControlCount
);
471 RtlZeroMemory(SrcLine
->NodeIds
, sizeof(ULONG
) * ControlCount
);
474 for(Index
= 0; Index
< NodeTypes
->Count
; Index
++)
479 Node
= MMixerGetNodeType(NodeTypes
, Index
);
481 if (MMixerGetControlTypeFromTopologyNode(Node
))
483 /* store the node index for retrieving / setting details */
484 SrcLine
->NodeIds
[ControlCount
] = Index
;
486 Status
= MMixerAddMixerControl(MixerContext
, MixerInfo
, hDevice
, NodeTypes
, Index
, SrcLine
, &SrcLine
->LineControls
[ControlCount
]);
487 if (Status
== MM_STATUS_SUCCESS
)
489 /* increment control count on success */
495 /* store control count */
496 SrcLine
->Line
.cControls
= ControlCount
;
499 /* release nodes array */
500 MixerContext
->Free(Nodes
);
502 /* get pin category */
505 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
506 Pin
.Property
.Set
= KSPROPSETID_Pin
;
507 Pin
.Property
.Id
= KSPROPERTY_PIN_CATEGORY
;
509 /* try get pin category */
510 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (LPVOID
)&NodeType
, sizeof(GUID
), &BytesReturned
);
511 if (Status
!= MM_STATUS_SUCCESS
)
517 /* retrieve pin name */
520 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
521 Pin
.Property
.Set
= KSPROPSETID_Pin
;
522 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
524 /* try get pin name size */
525 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
527 if (Status
== MM_STATUS_MORE_ENTRIES
)
529 PinName
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
532 /* try get pin name */
533 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (LPVOID
)PinName
, BytesReturned
, &BytesReturned
);
535 if (Status
== MM_STATUS_SUCCESS
)
537 MixerContext
->Copy(SrcLine
->Line
.szShortName
, PinName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
538 SrcLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
540 MixerContext
->Copy(SrcLine
->Line
.szName
, PinName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
541 SrcLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
543 MixerContext
->Free(PinName
);
547 /* insert src line */
550 InsertTailList(&MixerInfo
->LineList
, &SrcLine
->Entry
);
551 DstLine
->Line
.cConnections
++;
554 return MM_STATUS_SUCCESS
;
558 MMixerCreateDestinationLine(
559 IN PMIXER_CONTEXT MixerContext
,
560 IN LPMIXER_INFO MixerInfo
,
561 IN ULONG bInputMixer
,
564 LPMIXERLINE_EXT DestinationLine
;
566 // allocate a mixer destination line
567 DestinationLine
= (LPMIXERLINE_EXT
) MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
571 return MM_STATUS_NO_MEMORY
;
574 /* initialize mixer destination line */
575 DestinationLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
576 DestinationLine
->Line
.dwSource
= MAXULONG
;
577 DestinationLine
->Line
.dwLineID
= DESTINATION_LINE
;
578 DestinationLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
;
579 DestinationLine
->Line
.dwUser
= 0;
580 DestinationLine
->Line
.dwComponentType
= (bInputMixer
== 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
);
581 DestinationLine
->Line
.cChannels
= 2; //FIXME
585 MixerContext
->Copy(DestinationLine
->Line
.szShortName
, LineName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
586 DestinationLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
588 MixerContext
->Copy(DestinationLine
->Line
.szName
, LineName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
589 DestinationLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
594 /* FIXME no name was found for pin */
595 wcscpy(DestinationLine
->Line
.szShortName
, L
"Summe");
596 wcscpy(DestinationLine
->Line
.szName
, L
"Summe");
599 DestinationLine
->Line
.Target
.dwType
= (bInputMixer
== 0 ? MIXERLINE_TARGETTYPE_WAVEOUT
: MIXERLINE_TARGETTYPE_WAVEIN
);
600 DestinationLine
->Line
.Target
.dwDeviceID
= !bInputMixer
;
601 DestinationLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
602 DestinationLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
603 DestinationLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
605 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == 0);
606 wcscpy(DestinationLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
608 // initialize extra line
609 InitializeListHead(&DestinationLine
->LineControlsExtraData
);
611 // insert into mixer info
612 InsertHeadList(&MixerInfo
->LineList
, &DestinationLine
->Entry
);
615 return MM_STATUS_SUCCESS
;
619 MMixerGetControlsFromPin(
620 IN PMIXER_CONTEXT MixerContext
,
621 IN PKSMULTIPLE_ITEM NodeConnections
,
622 IN PKSMULTIPLE_ITEM NodeTypes
,
624 IN ULONG bUpDirection
,
627 ULONG NodeConnectionCount
, Index
;
629 PULONG NodeConnection
;
632 ASSERT(PinId
!= (ULONG
)-1);
634 /* get all node indexes referenced by that pin */
636 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, PinId
, FALSE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
638 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, PinId
, FALSE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
640 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
642 /* get all associated controls */
643 Status
= MMixerGetControlsFromPinByConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Nodes
);
646 MixerContext
->Free(NodeConnection
);
655 MMixerAddMixerSourceLines(
656 IN PMIXER_CONTEXT MixerContext
,
657 IN OUT LPMIXER_INFO MixerInfo
,
659 IN PKSMULTIPLE_ITEM NodeConnections
,
660 IN PKSMULTIPLE_ITEM NodeTypes
,
662 IN ULONG BridgePinIndex
,
663 IN ULONG TargetPinIndex
,
668 for(Index
= PinsCount
; Index
> 0; Index
--)
670 DPRINT("MMixerAddMixerSourceLines Index %lu Pin %lu\n", Index
-1, Pins
[Index
-1]);
673 MMixerAddMixerSourceLine(MixerContext
, MixerInfo
, hDevice
, NodeConnections
, NodeTypes
, Index
-1, (Index
-1 == BridgePinIndex
), (Index
-1 == TargetPinIndex
));
676 return MM_STATUS_SUCCESS
;
681 MMixerHandlePhysicalConnection(
682 IN PMIXER_CONTEXT MixerContext
,
683 IN PMIXER_LIST MixerList
,
684 IN OUT LPMIXER_INFO MixerInfo
,
686 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
688 PULONG PinsRef
= NULL
, PinConnectionIndex
= NULL
, PinsSrcRef
;
689 ULONG PinsRefCount
, Index
, PinConnectionIndexCount
;
691 PKSMULTIPLE_ITEM NodeTypes
= NULL
;
692 PKSMULTIPLE_ITEM NodeConnections
= NULL
;
693 PULONG MixerControls
;
694 ULONG MixerControlsCount
;
695 LPMIXER_DATA MixerData
;
698 // open the connected filter
699 OutConnection
->SymbolicLinkName
[1] = L
'\\';
700 MixerData
= MMixerGetDataByDeviceName(MixerList
, OutConnection
->SymbolicLinkName
);
703 // store connected mixer handle
704 MixerInfo
->hMixer
= MixerData
->hDevice
;
706 // get connected filter pin count
707 PinsRefCount
= MMixerGetFilterPinCount(MixerContext
, MixerData
->hDevice
);
708 ASSERT(PinsRefCount
);
710 PinsRef
= (PULONG
)MixerContext
->Alloc(sizeof(ULONG
) * PinsRefCount
);
714 return MM_STATUS_UNSUCCESSFUL
;
717 // get topology node types
718 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
719 if (Status
!= MM_STATUS_SUCCESS
)
721 MixerContext
->Free(PinsRef
);
725 // get topology connections
726 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
727 if (Status
!= MM_STATUS_SUCCESS
)
729 MixerContext
->Free(PinsRef
);
730 MixerContext
->Free(NodeTypes
);
733 // gets connection index of the bridge pin which connects to a node
734 DPRINT("Pin %lu\n", OutConnection
->Pin
);
736 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, OutConnection
->Pin
, FALSE
, !bInput
, &PinConnectionIndexCount
, &PinConnectionIndex
);
737 if (Status
!= MM_STATUS_SUCCESS
)
739 MixerContext
->Free(PinsRef
);
740 MixerContext
->Free(NodeTypes
);
741 MixerContext
->Free(NodeConnections
);
745 /* there should be no split in the bridge pin */
746 ASSERT(PinConnectionIndexCount
== 1);
748 /* find all target pins of this connection */
749 Status
= MMixerGetTargetPinsByNodeConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, FALSE
, PinConnectionIndex
[0], PinsRefCount
, PinsRef
);
750 if (Status
!= MM_STATUS_SUCCESS
)
752 MixerContext
->Free(PinsRef
);
753 MixerContext
->Free(NodeTypes
);
754 MixerContext
->Free(NodeConnections
);
755 MixerContext
->Free(PinConnectionIndex
);
759 for(Index
= 0; Index
< PinsRefCount
; Index
++)
761 DPRINT("PinsRefCount %lu Index %lu Value %lu\n", PinsRefCount
, Index
, PinsRef
[Index
]);
764 // found a target pin, now get all references
765 Status
= MMixerGetNodeIndexes(MixerContext
, NodeConnections
, Index
, FALSE
, FALSE
, &MixerControlsCount
, &MixerControls
);
766 if (Status
!= MM_STATUS_SUCCESS
)
768 DPRINT("MMixerGetNodeIndexes failed with %u\n", Status
);
773 ASSERT(MixerControlsCount
== 1);
775 PinsSrcRef
= (PULONG
)MixerContext
->Alloc(PinsRefCount
* sizeof(ULONG
));
779 MixerContext
->Free(PinsRef
);
780 MixerContext
->Free(NodeTypes
);
781 MixerContext
->Free(NodeConnections
);
782 MixerContext
->Free(PinConnectionIndex
);
783 MixerContext
->Free(MixerControls
);
784 return MM_STATUS_NO_MEMORY
;
787 // now get all connected source pins
788 Status
= MMixerGetTargetPinsByNodeConnectionIndex(MixerContext
, NodeConnections
, NodeTypes
, TRUE
, MixerControls
[0], PinsRefCount
, PinsSrcRef
);
789 if (Status
!= MM_STATUS_SUCCESS
)
792 MixerContext
->Free(PinsRef
);
793 MixerContext
->Free(NodeTypes
);
794 MixerContext
->Free(NodeConnections
);
795 MixerContext
->Free(PinConnectionIndex
);
796 MixerContext
->Free(MixerControls
);
797 MixerContext
->Free(PinsSrcRef
);
801 /* add pins from target line */
804 // dont add bridge pin for input mixers
805 PinsSrcRef
[Index
] = TRUE
;
806 PinsSrcRef
[OutConnection
->Pin
] = TRUE
;
808 PinsSrcRef
[OutConnection
->Pin
] = TRUE
;
810 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, NodeConnections
, NodeTypes
, PinsRefCount
, OutConnection
->Pin
, Index
, PinsSrcRef
);
812 MixerContext
->Free(MixerControls
);
813 MixerContext
->Free(PinsSrcRef
);
822 MMixerInitializeFilter(
823 IN PMIXER_CONTEXT MixerContext
,
824 IN PMIXER_LIST MixerList
,
825 IN LPMIXER_DATA MixerData
,
826 IN PKSMULTIPLE_ITEM NodeTypes
,
827 IN PKSMULTIPLE_ITEM NodeConnections
,
830 IN ULONG bInputMixer
)
832 LPMIXER_INFO MixerInfo
;
834 PKSPIN_PHYSICALCONNECTION OutConnection
;
840 LPWSTR Buffer
= NULL
;
843 // allocate a mixer info struct
844 MixerInfo
= (LPMIXER_INFO
) MixerContext
->Alloc(sizeof(MIXER_INFO
));
848 return MM_STATUS_NO_MEMORY
;
851 // intialize mixer caps */
852 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; //FIXME
853 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; //FIXME
854 MixerInfo
->MixCaps
.vDriverVersion
= 1; //FIXME
855 MixerInfo
->MixCaps
.fdwSupport
= 0;
856 MixerInfo
->MixCaps
.cDestinations
= 1;
857 MixerInfo
->hMixer
= MixerData
->hDevice
;
860 MMixerGetDeviceName(MixerContext
, MixerInfo
, MixerData
->hDeviceInterfaceKey
);
862 // initialize line list
863 InitializeListHead(&MixerInfo
->LineList
);
864 InitializeListHead(&MixerInfo
->EventList
);
869 // now allocate an array which will receive the indices of the pin
870 // which has a ADC / DAC nodetype in its path
871 Pins
= (PULONG
)MixerContext
->Alloc(PinCount
* sizeof(ULONG
));
876 MMixerFreeMixerInfo(MixerContext
, MixerInfo
);
877 return MM_STATUS_NO_MEMORY
;
880 // now get the target pins of the ADC / DAC node
881 Status
= MMixerGetTargetPins(MixerContext
, NodeTypes
, NodeConnections
, NodeIndex
, !bInputMixer
, Pins
, PinCount
);
883 // find a target pin with a name
885 for(Index
= 0; Index
< PinCount
; Index
++)
889 // store index of pin
892 /* retrieve pin name */
895 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
896 Pin
.Property
.Set
= KSPROPSETID_Pin
;
897 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
899 /* try get pin name size */
900 Status
= MixerContext
->Control(MixerData
->hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
902 if (Status
== MM_STATUS_MORE_ENTRIES
)
904 Buffer
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
907 /* try get pin name */
908 Status
= MixerContext
->Control(MixerData
->hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Buffer
, BytesReturned
, &BytesReturned
);
909 if (Status
!= MM_STATUS_SUCCESS
)
911 MixerContext
->Free((PVOID
)Buffer
);
924 if (PinId
< PinCount
)
926 // create an wave info struct
927 MMixerInitializeWaveInfo(MixerContext
, MixerList
, MixerData
, MixerInfo
->MixCaps
.szPname
, bInputMixer
, PinId
);
930 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInputMixer
, Buffer
);
935 MixerContext
->Free(Buffer
);
938 if (Status
!= MM_STATUS_SUCCESS
)
940 // failed to create destination line
941 MixerContext
->Free(MixerInfo
);
942 MixerContext
->Free(Pins
);
947 RtlZeroMemory(Pins
, sizeof(ULONG
) * PinCount
);
948 // now get the target pins of the ADC / DAC node
949 Status
= MMixerGetTargetPins(MixerContext
, NodeTypes
, NodeConnections
, NodeIndex
, bInputMixer
, Pins
, PinCount
);
951 if (Status
!= MM_STATUS_SUCCESS
)
953 // failed to locate target pins
954 MixerContext
->Free(Pins
);
955 MMixerFreeMixerInfo(MixerContext
, MixerInfo
);
956 DPRINT("MMixerGetTargetPins failed with %u\n", Status
);
960 // filter hasnt been used
963 // now check all pins and generate new lines for destination lines
964 for(Index
= 0; Index
< PinCount
; Index
++)
966 DPRINT("Index %lu TargetPin %lu\n", Index
, Pins
[Index
]);
967 // is the current index a target pin
970 // check if the pin has a physical connection
971 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Index
, &OutConnection
);
972 if (Status
== MM_STATUS_SUCCESS
)
974 // the pin has a physical connection
975 Status
= MMixerHandlePhysicalConnection(MixerContext
, MixerList
, MixerInfo
, bInputMixer
, OutConnection
);
976 DPRINT("MMixerHandlePhysicalConnection status %u\n", Status
);
977 MixerContext
->Free(OutConnection
);
982 // filter exposes the topology on the same filter
983 MMixerAddMixerSourceLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, NodeConnections
, NodeTypes
, Index
, FALSE
, FALSE
);
988 MixerContext
->Free(Pins
);
992 // store mixer info in list
993 if (!bInputMixer
&& MixerList
->MixerListCount
== 1)
995 //FIXME preferred device should be inserted at front
996 //windows always inserts output mixer in front
997 InsertHeadList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1001 InsertTailList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1003 MixerList
->MixerListCount
++;
1004 DPRINT("New MixerCount %lu\n", MixerList
->MixerListCount
);
1008 // failed to create a mixer topology
1009 MMixerFreeMixerInfo(MixerContext
, MixerInfo
);
1018 IN PMIXER_CONTEXT MixerContext
,
1019 IN PMIXER_LIST MixerList
,
1020 IN LPMIXER_DATA MixerData
,
1021 IN PULONG DeviceCount
)
1023 PKSMULTIPLE_ITEM NodeTypes
= NULL
, NodeConnections
= NULL
;
1024 MIXER_STATUS Status
;
1028 // get number of pins
1029 PinCount
= MMixerGetFilterPinCount(MixerContext
, MixerData
->hDevice
);
1031 DPRINT("NumOfPins: %lu\n", PinCount
);
1033 // get filter node types
1034 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
1035 if (Status
!= MM_STATUS_SUCCESS
)
1041 // get filter node connections
1042 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
1043 if (Status
!= MM_STATUS_SUCCESS
)
1046 MixerContext
->Free(NodeTypes
);
1050 // check if the filter has an wave out node
1052 NodeIndex
= MMixerGetIndexOfGuid(NodeTypes
, &KSNODETYPE_DAC
);
1053 if (NodeIndex
!= MAXULONG
)
1056 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, NodeTypes
, NodeConnections
, PinCount
, NodeIndex
, FALSE
);
1057 DPRINT("MMixerInitializeFilter Status %u\n", Status
);
1058 // check for success
1059 if (Status
== MM_STATUS_SUCCESS
)
1061 // increment mixer count
1067 // check if the filter has an wave in node
1068 NodeIndex
= MMixerGetIndexOfGuid(NodeTypes
, &KSNODETYPE_ADC
);
1069 if (NodeIndex
!= MAXULONG
)
1072 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, NodeTypes
, NodeConnections
, PinCount
, NodeIndex
, TRUE
);
1073 DPRINT("MMixerInitializeFilter Status %u\n", Status
);
1074 // check for success
1075 if (Status
== MM_STATUS_SUCCESS
)
1077 // increment mixer count
1084 MixerContext
->Free((PVOID
)NodeTypes
);
1085 MixerContext
->Free((PVOID
)NodeConnections
);
1094 IN PMIXER_CONTEXT MixerContext
,
1095 IN OUT LPMIXER_INFO MixerInfo
,
1099 LPEVENT_ITEM EventData
;
1100 ULONG BytesReturned
;
1101 MIXER_STATUS Status
;
1103 EventData
= (LPEVENT_ITEM
)MixerContext
->AllocEventData(sizeof(LIST_ENTRY
));
1106 // not enough memory
1107 return MM_STATUS_NO_MEMORY
;
1111 Property
.Event
.Set
= KSEVENTSETID_AudioControlChange
;
1112 Property
.Event
.Flags
= KSEVENT_TYPE_TOPOLOGY
|KSEVENT_TYPE_ENABLE
;
1113 Property
.Event
.Id
= KSEVENT_CONTROL_CHANGE
;
1115 Property
.NodeId
= NodeId
;
1116 Property
.Reserved
= 0;
1118 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSP_NODE
), (PVOID
)EventData
, sizeof(KSEVENTDATA
), &BytesReturned
);
1119 if (Status
!= MM_STATUS_SUCCESS
)
1121 // failed to add event
1122 MixerContext
->FreeEventData(EventData
);
1127 InsertTailList(&MixerInfo
->EventList
, &EventData
->Entry
);
1133 IN PMIXER_CONTEXT MixerContext
,
1134 IN OUT LPMIXER_INFO MixerInfo
)
1136 PKSMULTIPLE_ITEM NodeTypes
;
1138 MIXER_STATUS Status
;
1141 // get filter node types
1142 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerInfo
->hMixer
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
1144 if (Status
!= MM_STATUS_SUCCESS
)
1150 for(Index
= 0; Index
< NodeTypes
->Count
; Index
++)
1152 Guid
= MMixerGetNodeType(NodeTypes
, Index
);
1153 if (IsEqualGUID(&KSNODETYPE_VOLUME
, Guid
) || IsEqualGUID(&KSNODETYPE_MUTE
, Guid
))
1155 //add an event for volume / mute controls
1156 //TODO: extra control types
1157 MMixerAddEvent(MixerContext
, MixerInfo
, Index
);
1162 MixerContext
->Free(NodeTypes
);
1164 return MM_STATUS_SUCCESS
;