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
14 const GUID KSNODETYPE_DESKTOP_MICROPHONE
= {0xDFF21BE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
15 const GUID KSNODETYPE_LEGACY_AUDIO_CONNECTOR
= {0xDFF21FE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
16 const GUID KSNODETYPE_TELEPHONE
= {0xDFF21EE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
17 const GUID KSNODETYPE_PHONE_LINE
= {0xDFF21EE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
18 const GUID KSNODETYPE_DOWN_LINE_PHONE
= {0xDFF21EE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
19 const GUID KSNODETYPE_DESKTOP_SPEAKER
= {0xDFF21CE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
20 const GUID KSNODETYPE_ROOM_SPEAKER
= {0xDFF21CE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
21 const GUID KSNODETYPE_COMMUNICATION_SPEAKER
= {0xDFF21CE6, 0xF70F, 0x11D0, {0xB9,0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
22 const GUID KSNODETYPE_HEADPHONES
= {0xDFF21CE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
23 const GUID KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO
= {0xDFF21CE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
24 const GUID KSNODETYPE_MICROPHONE
= {0xDFF21BE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9,0x22, 0x31, 0x96}};
25 const GUID KSCATEGORY_AUDIO
= {0x6994AD04L
, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
26 const GUID KSNODETYPE_SPDIF_INTERFACE
= {0xDFF21FE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
27 const GUID KSNODETYPE_ANALOG_CONNECTOR
= {0xDFF21FE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
28 const GUID KSNODETYPE_SPEAKER
= {0xDFF21CE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
29 const GUID KSNODETYPE_CD_PLAYER
= {0xDFF220E3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
30 const GUID KSNODETYPE_SYNTHESIZER
= {0xDFF220F3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
31 const GUID KSNODETYPE_LINE_CONNECTOR
= {0xDFF21FE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0,0xC9, 0x22, 0x31, 0x96}};
32 const GUID PINNAME_VIDEO_CAPTURE
= {0xfb6c4281, 0x353, 0x11d1, {0x90, 0x5f, 0x0, 0x0, 0xc0, 0xcc, 0x16, 0xba}};
35 MMixerAddMixerControl(
36 IN PMIXER_CONTEXT MixerContext
,
37 IN LPMIXER_INFO MixerInfo
,
39 IN PTOPOLOGY Topology
,
41 IN LPMIXERLINE_EXT MixerLine
,
49 LPMIXERCONTROL_EXT MixerControl
;
51 /* allocate mixer control */
52 MixerControl
= MixerContext
->Alloc(sizeof(MIXERCONTROL_EXT
));
56 return MM_STATUS_NO_MEMORY
;
60 /* initialize mixer control */
61 MixerControl
->hDevice
= hMixer
;
62 MixerControl
->NodeID
= NodeIndex
;
63 MixerControl
->ExtraData
= NULL
;
65 MixerControl
->Control
.cbStruct
= sizeof(MIXERCONTROLW
);
66 MixerControl
->Control
.dwControlID
= MixerInfo
->ControlId
;
69 NodeType
= MMixerGetNodeTypeFromTopology(Topology
, NodeIndex
);
70 /* store control type */
71 MixerControl
->Control
.dwControlType
= MMixerGetControlTypeFromTopologyNode(NodeType
);
73 MixerControl
->Control
.fdwControl
= (MaxChannels
> 1 ? 0 : MIXERCONTROL_CONTROLF_UNIFORM
);
74 MixerControl
->Control
.cMultipleItems
= 0;
76 /* setup request to retrieve name */
77 Node
.NodeId
= NodeIndex
;
78 Node
.Property
.Id
= KSPROPERTY_TOPOLOGY_NAME
;
79 Node
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
80 Node
.Property
.Set
= KSPROPSETID_Topology
;
83 /* get node name size */
84 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), NULL
, 0, &BytesReturned
);
86 if (Status
== MM_STATUS_MORE_ENTRIES
)
88 ASSERT(BytesReturned
!= 0);
89 Name
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
92 /* not enough memory */
93 return MM_STATUS_NO_MEMORY
;
97 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), (LPVOID
)Name
, BytesReturned
, &BytesReturned
);
99 if (Status
== MM_STATUS_SUCCESS
)
101 MixerContext
->Copy(MixerControl
->Control
.szShortName
, Name
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
102 MixerControl
->Control
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
104 MixerContext
->Copy(MixerControl
->Control
.szName
, Name
, (min(MIXER_LONG_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
105 MixerControl
->Control
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
108 /* free name buffer */
109 MixerContext
->Free(Name
);
112 /* increment control count */
113 MixerInfo
->ControlId
++;
116 InsertTailList(&MixerLine
->ControlsList
, &MixerControl
->Entry
);
118 if (MixerControl
->Control
.dwControlType
== MIXERCONTROL_CONTROLTYPE_MUX
)
123 /* allocate topology nodes array */
124 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
126 if (Status
!= MM_STATUS_SUCCESS
)
129 return STATUS_NO_MEMORY
;
132 /* get connected node count */
133 MMixerGetNextNodesFromNodeIndex(MixerContext
, Topology
, NodeIndex
, TRUE
, &NodesCount
, Nodes
);
136 MixerContext
->Free(Nodes
);
138 /* setup mux bounds */
139 MixerControl
->Control
.Bounds
.dwMinimum
= 0;
140 MixerControl
->Control
.Bounds
.dwMaximum
= NodesCount
- 1;
141 MixerControl
->Control
.Metrics
.dwReserved
[0] = NodesCount
;
142 MixerControl
->Control
.cMultipleItems
= NodesCount
;
143 MixerControl
->Control
.fdwControl
|= MIXERCONTROL_CONTROLF_UNIFORM
| MIXERCONTROL_CONTROLF_MULTIPLE
;
145 else if (MixerControl
->Control
.dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
147 MixerControl
->Control
.Bounds
.dwMinimum
= 0;
148 MixerControl
->Control
.Bounds
.dwMaximum
= 1;
150 else if (MixerControl
->Control
.dwControlType
== MIXERCONTROL_CONTROLTYPE_ONOFF
)
152 /* only needs to set bounds */
153 MixerControl
->Control
.Bounds
.dwMinimum
= 0;
154 MixerControl
->Control
.Bounds
.dwMaximum
= 1;
156 else if (MixerControl
->Control
.dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
158 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
160 PKSPROPERTY_DESCRIPTION Desc
;
161 PKSPROPERTY_MEMBERSHEADER Members
;
162 PKSPROPERTY_STEPPING_LONG Range
;
164 MixerControl
->Control
.Bounds
.dwMinimum
= 0;
165 MixerControl
->Control
.Bounds
.dwMaximum
= 0xFFFF;
166 MixerControl
->Control
.Metrics
.cSteps
= 0xC0; /* FIXME */
168 Length
= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) + sizeof(KSPROPERTY_STEPPING_LONG
);
169 Desc
= (PKSPROPERTY_DESCRIPTION
)MixerContext
->Alloc(Length
);
172 /* setup the request */
173 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
175 Property
.NodeProperty
.NodeId
= NodeIndex
;
176 Property
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
177 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
| KSPROPERTY_TYPE_TOPOLOGY
;
178 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
180 /* get node volume level info */
181 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), Desc
, Length
, &BytesReturned
);
183 if (Status
== MM_STATUS_SUCCESS
)
185 LPMIXERVOLUME_DATA VolumeData
;
186 ULONG Steps
, MaxRange
, Index
;
189 Members
= (PKSPROPERTY_MEMBERSHEADER
)(Desc
+ 1);
190 Range
= (PKSPROPERTY_STEPPING_LONG
)(Members
+ 1);
192 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
);
194 MaxRange
= Range
->Bounds
.UnsignedMaximum
- Range
->Bounds
.UnsignedMinimum
;
199 VolumeData
= (LPMIXERVOLUME_DATA
)MixerContext
->Alloc(sizeof(MIXERVOLUME_DATA
));
201 return MM_STATUS_NO_MEMORY
;
203 Steps
= MaxRange
/ Range
->SteppingDelta
+ 1;
205 /* store mixer control info there */
206 VolumeData
->Header
.dwControlID
= MixerControl
->Control
.dwControlID
;
207 VolumeData
->SignedMaximum
= Range
->Bounds
.SignedMaximum
;
208 VolumeData
->SignedMinimum
= Range
->Bounds
.SignedMinimum
;
209 VolumeData
->SteppingDelta
= Range
->SteppingDelta
;
210 VolumeData
->ValuesCount
= Steps
;
211 VolumeData
->InputSteppingDelta
= 0x10000 / Steps
;
213 VolumeData
->Values
= (PLONG
)MixerContext
->Alloc(sizeof(LONG
) * Steps
);
214 if (!VolumeData
->Values
)
216 MixerContext
->Free(Desc
);
217 MixerContext
->Free(VolumeData
);
218 return MM_STATUS_NO_MEMORY
;
221 Value
= Range
->Bounds
.SignedMinimum
;
222 for(Index
= 0; Index
< Steps
; Index
++)
224 VolumeData
->Values
[Index
] = Value
;
225 Value
+= Range
->SteppingDelta
;
227 MixerControl
->ExtraData
= VolumeData
;
230 MixerContext
->Free(Desc
);
233 DPRINT("Status %x Name %S\n", Status
, MixerControl
->Control
.szName
);
234 return MM_STATUS_SUCCESS
;
238 MMixerCreateDestinationLine(
239 IN PMIXER_CONTEXT MixerContext
,
240 IN LPMIXER_INFO MixerInfo
,
241 IN ULONG bInputMixer
,
244 LPMIXERLINE_EXT DestinationLine
;
246 /* allocate a mixer destination line */
247 DestinationLine
= (LPMIXERLINE_EXT
) MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
251 return MM_STATUS_NO_MEMORY
;
254 /* initialize mixer destination line */
255 DestinationLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
256 DestinationLine
->Line
.cChannels
= 2; /* FIXME */
257 DestinationLine
->Line
.cConnections
= 0;
258 DestinationLine
->Line
.cControls
= 0;
259 DestinationLine
->Line
.dwComponentType
= (bInputMixer
== 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
);
260 DestinationLine
->Line
.dwDestination
= MixerInfo
->MixCaps
.cDestinations
;
261 DestinationLine
->Line
.dwLineID
= MixerInfo
->MixCaps
.cDestinations
+ DESTINATION_LINE
;
262 DestinationLine
->Line
.dwSource
= MAXULONG
;
263 DestinationLine
->Line
.dwUser
= 0;
264 DestinationLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
;
269 MixerContext
->Copy(DestinationLine
->Line
.szShortName
, LineName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
270 DestinationLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
272 MixerContext
->Copy(DestinationLine
->Line
.szName
, LineName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
273 DestinationLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
277 DestinationLine
->Line
.Target
.dwType
= (bInputMixer
== 0 ? MIXERLINE_TARGETTYPE_WAVEOUT
: MIXERLINE_TARGETTYPE_WAVEIN
);
278 DestinationLine
->Line
.Target
.dwDeviceID
= 0; //FIXME
279 DestinationLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
280 DestinationLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
281 DestinationLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
283 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == 0);
284 wcscpy(DestinationLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
286 /* initialize extra line */
287 InitializeListHead(&DestinationLine
->ControlsList
);
289 /* insert into mixer info */
290 InsertTailList(&MixerInfo
->LineList
, &DestinationLine
->Entry
);
292 /* increment destination count */
293 MixerInfo
->MixCaps
.cDestinations
++;
296 return MM_STATUS_SUCCESS
;
301 IN PMIXER_CONTEXT MixerContext
,
302 IN LPMIXER_INFO MixerInfo
,
305 IN OUT LPWSTR
* OutBuffer
)
315 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
316 Pin
.Property
.Set
= KSPROPSETID_Pin
;
317 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
319 /* try get pin name size */
320 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
322 /* check if buffer overflowed */
323 if (Status
== MM_STATUS_MORE_ENTRIES
)
325 /* allocate buffer */
326 Buffer
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
330 return MM_STATUS_NO_MEMORY
;
333 /* try get pin name */
334 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Buffer
, BytesReturned
, &BytesReturned
);
335 if (Status
!= MM_STATUS_SUCCESS
)
337 /* failed to get pin name */
338 MixerContext
->Free((PVOID
)Buffer
);
342 /* successfully obtained pin name */
344 return MM_STATUS_SUCCESS
;
347 /* failed to get pin name */
352 MMixerBuildMixerDestinationLine(
353 IN PMIXER_CONTEXT MixerContext
,
354 IN OUT LPMIXER_INFO MixerInfo
,
362 /* try get pin name */
363 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, hMixer
, PinId
, &PinName
);
364 if (Status
== MM_STATUS_SUCCESS
)
366 /* create mixer destination line */
368 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, PinName
);
371 MixerContext
->Free(PinName
);
375 /* create mixer destination line unlocalized */
376 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, L
"No Name");
384 IN PMIXER_CONTEXT MixerContext
,
385 IN LPMIXER_DATA MixerData
,
386 OUT PTOPOLOGY
* OutTopology
)
389 PKSMULTIPLE_ITEM NodeTypes
= NULL
;
390 PKSMULTIPLE_ITEM NodeConnections
= NULL
;
393 if (MixerData
->Topology
)
395 /* re-use existing topology */
396 *OutTopology
= MixerData
->Topology
;
398 return MM_STATUS_SUCCESS
;
401 /* get connected filter pin count */
402 PinsCount
= MMixerGetFilterPinCount(MixerContext
, MixerData
->hDevice
);
406 /* referenced filter does not have any pins */
407 return MM_STATUS_UNSUCCESSFUL
;
410 /* get topology node types */
411 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
412 if (Status
!= MM_STATUS_SUCCESS
)
414 /* failed to get topology node types */
418 /* get topology connections */
419 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
420 if (Status
!= MM_STATUS_SUCCESS
)
422 /* failed to get topology connections */
423 MixerContext
->Free(NodeTypes
);
427 /* create a topology */
428 Status
= MMixerCreateTopology(MixerContext
, PinsCount
, NodeConnections
, NodeTypes
, OutTopology
);
430 /* free node types & connections */
431 MixerContext
->Free(NodeConnections
);
432 MixerContext
->Free(NodeTypes
);
434 if (Status
== MM_STATUS_SUCCESS
)
436 /* store topology object */
437 MixerData
->Topology
= *OutTopology
;
445 MMixerCountMixerControls(
446 IN PMIXER_CONTEXT MixerContext
,
447 IN PTOPOLOGY Topology
,
449 IN ULONG bInputMixer
,
451 OUT PULONG OutNodesCount
,
453 OUT PULONG OutLineTerminator
)
456 ULONG NodesCount
, NodeIndex
, Count
, bTerminator
;
459 /* allocate an array to store all nodes which are upstream of this pin */
460 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
462 if (Status
!= MM_STATUS_SUCCESS
)
465 return STATUS_NO_MEMORY
;
468 /* mark result array as zero */
472 MMixerGetNextNodesFromPinIndex(MixerContext
, Topology
, PinId
, bUpStream
, &NodesCount
, Nodes
);
476 /* a pin which is not connected from any node
477 * a) it is a topology bug (driver bug)
478 * b) the request is from an alternative mixer
479 alternative mixer code scans all pins which have not been used and tries to build lines
481 DPRINT1("MMixerCountMixerControls PinId %lu is not connected by any node\n", PinId
);
482 MMixerPrintTopology(Topology
);
483 return MM_STATUS_UNSUCCESSFUL
;
486 /* assume no topology split before getting line terminator */
487 ASSERT(NodesCount
== 1);
490 NodeIndex
= Nodes
[0];
495 /* check if the node is a terminator */
496 MMixerIsNodeTerminator(Topology
, NodeIndex
, &bTerminator
);
500 /* found terminator */
503 /* add mux source for source destination line */
504 OutNodes
[Count
] = NodeIndex
;
511 OutNodes
[Count
] = NodeIndex
;
513 /* increment node count */
516 /* get next nodes upstream */
517 MMixerGetNextNodesFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bUpStream
, &NodesCount
, Nodes
);
521 DPRINT("PinId %lu bInputMixer %lu bUpStream %lu NodeIndex %lu is not connected", PinId
, bInputMixer
, bUpStream
, NodeIndex
);
525 ASSERT(NodesCount
== 1);
527 /* use first index */
528 NodeIndex
= Nodes
[0];
532 /* free node index */
533 MixerContext
->Free(Nodes
);
535 /* store nodes count */
536 *OutNodesCount
= Count
;
538 /* store line terminator */
539 *OutLineTerminator
= NodeIndex
;
542 return MM_STATUS_SUCCESS
;
546 MMixerGetChannelCountEnhanced(
547 IN PMIXER_CONTEXT MixerContext
,
548 IN LPMIXER_INFO MixerInfo
,
551 OUT PULONG MaxChannels
)
553 KSPROPERTY_DESCRIPTION Description
;
554 PKSPROPERTY_DESCRIPTION NewDescription
;
555 PKSPROPERTY_MEMBERSHEADER Header
;
560 /* try #1 obtain it via description */
561 Request
.NodeId
= NodeId
;
562 Request
.Reserved
= 0;
563 Request
.Property
.Set
= KSPROPSETID_Audio
;
564 Request
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
| KSPROPERTY_TYPE_TOPOLOGY
;
565 Request
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
568 /* get description */
569 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_NODE
), (PVOID
)&Description
, sizeof(KSPROPERTY_DESCRIPTION
), &BytesReturned
);
570 if (Status
== MM_STATUS_SUCCESS
)
572 if (Description
.DescriptionSize
>= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) && (Description
.MembersListCount
> 0))
574 /* allocate new description */
575 NewDescription
= MixerContext
->Alloc(Description
.DescriptionSize
);
579 /* not enough memory */
580 return MM_STATUS_NO_MEMORY
;
583 /* get description */
584 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_NODE
), (PVOID
)NewDescription
, Description
.DescriptionSize
, &BytesReturned
);
585 if (Status
== MM_STATUS_SUCCESS
)
588 Header
= (PKSPROPERTY_MEMBERSHEADER
)(NewDescription
+ 1);
590 if (Header
->Flags
& KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL
)
592 /* found enhanced flag */
593 ASSERT(Header
->MembersCount
> 1);
595 /* store channel count */
596 *MaxChannels
= Header
->MembersCount
;
598 /* free description */
599 MixerContext
->Free(NewDescription
);
602 return MM_STATUS_SUCCESS
;
606 /* free description */
607 MixerContext
->Free(NewDescription
);
611 /* failed to get channel count enhanced */
612 return MM_STATUS_UNSUCCESSFUL
;
616 MMixerGetChannelCountLegacy(
617 IN PMIXER_CONTEXT MixerContext
,
618 IN LPMIXER_INFO MixerInfo
,
621 OUT PULONG MaxChannels
)
625 KSNODEPROPERTY_AUDIO_CHANNEL Channel
;
629 Channel
.Reserved
= 0;
630 Channel
.NodeProperty
.NodeId
= NodeId
;
631 Channel
.NodeProperty
.Reserved
= 0;
632 Channel
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_TOPOLOGY
;
633 Channel
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
635 Channel
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
639 /* get channel volume */
640 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Channel
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), (PVOID
)&Volume
, sizeof(LONG
), &BytesReturned
);
641 if (Status
!= MM_STATUS_SUCCESS
)
644 /* increment channel count */
649 /* store channel count */
650 *MaxChannels
= Channel
.Channel
;
655 MMixerGetMaxChannelsForNode(
656 IN PMIXER_CONTEXT MixerContext
,
657 IN LPMIXER_INFO MixerInfo
,
660 OUT PULONG MaxChannels
)
664 /* try to get it enhanced */
665 Status
= MMixerGetChannelCountEnhanced(MixerContext
, MixerInfo
, hMixer
, NodeId
, MaxChannels
);
667 if (Status
!= MM_STATUS_SUCCESS
)
669 /* get it old-fashioned way */
670 MMixerGetChannelCountLegacy(MixerContext
, MixerInfo
, hMixer
, NodeId
, MaxChannels
);
675 MMixerAddMixerControlsToMixerLineByNodeIndexArray(
676 IN PMIXER_CONTEXT MixerContext
,
677 IN LPMIXER_INFO MixerInfo
,
679 IN PTOPOLOGY Topology
,
680 IN OUT LPMIXERLINE_EXT DstLine
,
684 ULONG Index
, Count
, bReserved
;
689 /* initialize control count */
692 for(Index
= 0; Index
< NodesCount
; Index
++)
694 /* check if the node has already been reserved to a line */
695 MMixerIsTopologyNodeReserved(Topology
, Nodes
[Index
], &bReserved
);
699 /* node is already used, skip it */
703 /* set node status as used */
704 MMixerSetTopologyNodeReserved(Topology
, Nodes
[Index
]);
706 /* query node type */
707 NodeType
= MMixerGetNodeTypeFromTopology(Topology
, Nodes
[Index
]);
709 if (IsEqualGUIDAligned(NodeType
, &KSNODETYPE_VOLUME
))
711 /* calculate maximum channel count for node */
712 MMixerGetMaxChannelsForNode(MixerContext
, MixerInfo
, hMixer
, Nodes
[Index
], &MaxChannels
);
714 DPRINT("NodeId %lu MaxChannels %lu Line %S Id %lu\n", Nodes
[Index
], MaxChannels
, DstLine
->Line
.szName
, DstLine
->Line
.dwLineID
);
715 /* calculate maximum channels */
716 DstLine
->Line
.cChannels
= min(DstLine
->Line
.cChannels
, MaxChannels
);
720 /* use default of one channel */
724 /* now add the mixer control */
725 Status
= MMixerAddMixerControl(MixerContext
, MixerInfo
, hMixer
, Topology
, Nodes
[Index
], DstLine
, MaxChannels
);
727 if (Status
== MM_STATUS_SUCCESS
)
729 /* increment control count */
734 /* store control count */
735 DstLine
->Line
.cControls
= Count
;
738 return MM_STATUS_SUCCESS
;
742 MMixerGetComponentAndTargetType(
743 IN PMIXER_CONTEXT MixerContext
,
744 IN OUT LPMIXER_INFO MixerInfo
,
747 OUT PULONG ComponentType
,
748 OUT PULONG TargetType
)
750 KSPIN_DATAFLOW DataFlow
;
751 KSPIN_COMMUNICATION Communication
;
756 BOOLEAN BridgePin
= FALSE
;
757 PKSPIN_PHYSICALCONNECTION Connection
;
759 /* first dataflow type */
760 Status
= MMixerGetPinDataFlowAndCommunication(MixerContext
, hMixer
, PinId
, &DataFlow
, &Communication
);
762 if (Status
!= MM_STATUS_SUCCESS
)
764 /* failed to get dataflow */
768 /* now get pin category guid */
769 Request
.PinId
= PinId
;
770 Request
.Reserved
= 0;
771 Request
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
772 Request
.Property
.Set
= KSPROPSETID_Pin
;
773 Request
.Property
.Id
= KSPROPERTY_PIN_CATEGORY
;
776 /* get pin category */
777 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_PIN
), &Guid
, sizeof(GUID
), &BytesReturned
);
778 if (Status
!= MM_STATUS_SUCCESS
)
780 /* failed to get dataflow */
784 /* check if it has a physical connection */
785 Status
= MMixerGetPhysicalConnection(MixerContext
, hMixer
, PinId
, &Connection
);
786 if (Status
== MM_STATUS_SUCCESS
)
788 /* pin is a brige pin */
791 /* free physical connection */
792 MixerContext
->Free(Connection
);
795 if (DataFlow
== KSPIN_DATAFLOW_IN
)
797 if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_MICROPHONE
) ||
798 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DESKTOP_MICROPHONE
))
800 /* type microphone */
801 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
802 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
;
804 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_LEGACY_AUDIO_CONNECTOR
) ||
805 IsEqualGUIDAligned(&Guid
, &KSCATEGORY_AUDIO
) ||
806 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPEAKER
))
809 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
810 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT
;
812 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_CD_PLAYER
))
815 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
816 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC
;
818 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SYNTHESIZER
))
820 /* type synthesizer */
821 *TargetType
= MIXERLINE_TARGETTYPE_MIDIOUT
;
822 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER
;
824 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_LINE_CONNECTOR
))
827 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
828 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_LINE
;
830 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_TELEPHONE
) ||
831 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_PHONE_LINE
) ||
832 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DOWN_LINE_PHONE
))
835 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
836 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE
;
838 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ANALOG_CONNECTOR
))
842 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
844 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
846 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_ANALOG
;
848 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPDIF_INTERFACE
))
852 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
854 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
856 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_DIGITAL
;
861 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
862 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED
;
863 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId
, BridgePin
);
868 if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPEAKER
) ||
869 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DESKTOP_SPEAKER
) ||
870 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ROOM_SPEAKER
) ||
871 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_COMMUNICATION_SPEAKER
))
874 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
875 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
877 else if (IsEqualGUIDAligned(&Guid
, &KSCATEGORY_AUDIO
) ||
878 IsEqualGUIDAligned(&Guid
, &PINNAME_CAPTURE
))
881 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
882 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
884 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_HEADPHONES
) ||
885 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO
))
887 /* type head phones */
888 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
889 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_HEADPHONES
;
891 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_TELEPHONE
) ||
892 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_PHONE_LINE
) ||
893 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DOWN_LINE_PHONE
))
896 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
897 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_TELEPHONE
;
899 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ANALOG_CONNECTOR
))
904 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
905 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
909 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
910 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
913 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPDIF_INTERFACE
))
918 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
919 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
923 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
924 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
930 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
931 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
932 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId
, BridgePin
);
937 return MM_STATUS_SUCCESS
;
941 MMixerBuildMixerSourceLine(
942 IN PMIXER_CONTEXT MixerContext
,
943 IN OUT LPMIXER_INFO MixerInfo
,
945 IN PTOPOLOGY Topology
,
949 IN ULONG DestinationLineID
,
950 OUT LPMIXERLINE_EXT
* OutSrcLine
)
952 LPMIXERLINE_EXT SrcLine
, DstLine
;
955 ULONG ComponentType
, TargetType
;
957 /* get component and target type */
958 Status
= MMixerGetComponentAndTargetType(MixerContext
, MixerInfo
, hMixer
, PinId
, &ComponentType
, &TargetType
);
959 if (Status
!= MM_STATUS_SUCCESS
)
961 /* failed to get component status */
962 TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
963 ComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
966 /* construct source line */
967 SrcLine
= (LPMIXERLINE_EXT
)MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
972 return MM_STATUS_NO_MEMORY
;
975 /* get destination line */
976 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineID
);
979 /* initialize mixer src line */
980 SrcLine
->PinId
= PinId
;
982 /* initialize mixer line */
983 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
984 SrcLine
->Line
.dwDestination
= MixerInfo
->MixCaps
.cDestinations
-1;
985 SrcLine
->Line
.dwSource
= DstLine
->Line
.cConnections
;
986 SrcLine
->Line
.dwLineID
= (DstLine
->Line
.cConnections
* SOURCE_LINE
)+ (MixerInfo
->MixCaps
.cDestinations
-1);
987 SrcLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
| MIXERLINE_LINEF_SOURCE
;
988 SrcLine
->Line
.dwComponentType
= ComponentType
;
989 SrcLine
->Line
.dwUser
= 0;
990 SrcLine
->Line
.cChannels
= DstLine
->Line
.cChannels
;
991 SrcLine
->Line
.cConnections
= 0;
992 SrcLine
->Line
.Target
.dwType
= TargetType
;
993 SrcLine
->Line
.Target
.dwDeviceID
= DstLine
->Line
.Target
.dwDeviceID
;
994 SrcLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
995 SrcLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
996 SrcLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
997 InitializeListHead(&SrcLine
->ControlsList
);
1000 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == L
'\0');
1001 wcscpy(SrcLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
1004 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, hMixer
, PinId
, &PinName
);
1006 if (Status
== MM_STATUS_SUCCESS
)
1008 /* store pin name as line name */
1009 MixerContext
->Copy(SrcLine
->Line
.szShortName
, PinName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
1010 SrcLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
1012 MixerContext
->Copy(SrcLine
->Line
.szName
, PinName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
1013 SrcLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
1015 /* free pin name buffer */
1016 MixerContext
->Free(PinName
);
1019 /* add the controls to mixer line */
1020 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, hMixer
, Topology
, SrcLine
, NodesCount
, Nodes
);
1021 if (Status
!= MM_STATUS_SUCCESS
)
1028 *OutSrcLine
= SrcLine
;
1030 return MM_STATUS_SUCCESS
;
1034 MMixerAddMixerSourceLines(
1035 IN PMIXER_CONTEXT MixerContext
,
1036 IN OUT LPMIXER_INFO MixerInfo
,
1038 IN PTOPOLOGY Topology
,
1039 IN ULONG DestinationLineID
,
1040 IN ULONG LineTerminator
)
1042 PULONG AllNodes
, AllPins
, AllPinNodes
;
1043 ULONG AllNodesCount
, AllPinsCount
, AllPinNodesCount
;
1044 ULONG Index
, SubIndex
, PinId
, CurNode
, bConnected
;
1045 MIXER_STATUS Status
;
1046 LPMIXERLINE_EXT DstLine
, SrcLine
;
1048 /* get destination line */
1049 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineID
);
1052 /* allocate an array to store all nodes which are upstream of the line terminator */
1053 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllNodes
);
1055 /* check for success */
1056 if (Status
!= MM_STATUS_SUCCESS
)
1059 return MM_STATUS_NO_MEMORY
;
1062 /* allocate an array to store all nodes which are downstream of a particular pin */
1063 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllPinNodes
);
1065 /* allocate an array to store all pins which are upstream of this pin */
1066 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &AllPins
);
1068 /* check for success */
1069 if (Status
!= MM_STATUS_SUCCESS
)
1072 MixerContext
->Free(AllNodes
);
1073 return MM_STATUS_NO_MEMORY
;
1076 /* get all nodes which indirectly / directly connect to this node */
1078 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllNodesCount
, AllNodes
);
1080 /* get all pins which indirectly / directly connect to this node */
1082 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllPinsCount
, AllPins
);
1084 DPRINT("LineTerminator %lu\n", LineTerminator
);
1085 DPRINT("PinCount %lu\n", AllPinsCount
);
1086 DPRINT("AllNodesCount %lu\n", AllNodesCount
);
1088 /* now construct the source lines which are attached to the destination line */
1089 Index
= AllPinsCount
;
1093 /* get current pin id */
1094 PinId
= AllPins
[Index
- 1];
1096 /* reset nodes count */
1097 AllPinNodesCount
= 0;
1099 /* now scan all nodes and add them to AllPinNodes array when they are connected to this pin */
1100 for(SubIndex
= 0; SubIndex
< AllNodesCount
; SubIndex
++)
1102 /* get current node index */
1103 CurNode
= AllNodes
[SubIndex
];
1105 if (CurNode
!= MAXULONG
&& CurNode
!= LineTerminator
)
1107 /* check if that node is connected in some way to the current pin */
1108 Status
= MMixerIsNodeConnectedToPin(MixerContext
, Topology
, CurNode
, PinId
, TRUE
, &bConnected
);
1110 if (Status
!= MM_STATUS_SUCCESS
)
1115 /* it is connected */
1116 AllPinNodes
[AllPinNodesCount
] = CurNode
;
1119 /* clear current index */
1120 AllNodes
[SubIndex
] = MAXULONG
;
1125 /* decrement pin index */
1128 if (AllPinNodesCount
)
1133 /* now build the mixer source line */
1134 Status
= MMixerBuildMixerSourceLine(MixerContext
, MixerInfo
, hMixer
, Topology
, PinId
, AllPinNodesCount
, AllPinNodes
, DestinationLineID
, &SrcLine
);
1136 if (Status
== MM_STATUS_SUCCESS
)
1138 /* insert into line list */
1139 InsertTailList(&MixerInfo
->LineList
, &SrcLine
->Entry
);
1141 /* increment destination line count */
1142 DstLine
->Line
.cConnections
++;
1144 /* mark pin as reserved */
1145 MMixerSetTopologyPinReserved(Topology
, PinId
);
1148 DPRINT1("Adding PinId %lu AllPinNodesCount %lu to DestinationLine %lu\n", PinId
, AllPinNodesCount
, DestinationLineID
);
1149 for(TempIndex
= 0; TempIndex
< AllPinNodesCount
; TempIndex
++)
1150 DPRINT1("NodeIndex %lu\n", AllPinNodes
[TempIndex
]);
1157 DPRINT1("Discarding DestinationLineID %lu PinId %lu NO NODES!\n", DestinationLineID
, PinId
);
1163 return MM_STATUS_SUCCESS
;
1168 MMixerAddMixerControlsToDestinationLine(
1169 IN PMIXER_CONTEXT MixerContext
,
1170 IN OUT LPMIXER_INFO MixerInfo
,
1172 IN PTOPOLOGY Topology
,
1175 IN ULONG DestinationLineId
,
1176 OUT PULONG OutLineTerminator
)
1179 ULONG NodesCount
, LineTerminator
;
1180 MIXER_STATUS Status
;
1181 LPMIXERLINE_EXT DstLine
;
1183 /* allocate nodes index array */
1184 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
1186 /* check for success */
1187 if (Status
!= MM_STATUS_SUCCESS
)
1193 /* get all destination line controls */
1194 Status
= MMixerCountMixerControls(MixerContext
, Topology
, PinId
, bInput
, TRUE
, &NodesCount
, Nodes
, &LineTerminator
);
1196 /* check for success */
1197 if (Status
!= MM_STATUS_SUCCESS
)
1199 /* failed to count controls */
1200 MixerContext
->Free(Nodes
);
1204 /* get destination mixer line */
1205 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineId
);
1212 /* add all nodes as mixer controls to the destination line */
1213 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, hMixer
, Topology
, DstLine
, NodesCount
, Nodes
);
1214 if (Status
!= MM_STATUS_SUCCESS
)
1216 /* failed to add controls */
1217 MixerContext
->Free(Nodes
);
1223 *OutLineTerminator
= LineTerminator
;
1230 MMixerApplyOutputFilterHack(
1231 IN PMIXER_CONTEXT MixerContext
,
1232 IN LPMIXER_DATA MixerData
,
1234 IN OUT PULONG PinsCount
,
1237 ULONG Count
= 0, Index
;
1238 MIXER_STATUS Status
;
1239 PKSPIN_PHYSICALCONNECTION Connection
;
1241 for(Index
= 0; Index
< *PinsCount
; Index
++)
1243 /* check if it has a physical connection */
1244 Status
= MMixerGetPhysicalConnection(MixerContext
, hMixer
, Pins
[Index
], &Connection
);
1246 if (Status
== MM_STATUS_SUCCESS
)
1249 MixerContext
->Copy(&Pins
[Index
], &Pins
[Index
+ 1], (*PinsCount
- (Index
+ 1)) * sizeof(ULONG
));
1251 /* free physical connection */
1252 MixerContext
->Free(Connection
);
1254 /* decrement index */
1257 /* decrement pin count */
1272 MMixerHandlePhysicalConnection(
1273 IN PMIXER_CONTEXT MixerContext
,
1274 IN PMIXER_LIST MixerList
,
1275 IN LPMIXER_DATA MixerData
,
1276 IN OUT LPMIXER_INFO MixerInfo
,
1278 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
1280 MIXER_STATUS Status
;
1281 ULONG PinsCount
, LineTerminator
, DestinationLineID
;
1285 /* first try to open the connected filter */
1286 OutConnection
->SymbolicLinkName
[1] = L
'\\';
1287 MixerData
= MMixerGetDataByDeviceName(MixerList
, OutConnection
->SymbolicLinkName
);
1289 /* check if the linked connection is found */
1292 /* filter references invalid physical connection */
1293 return MM_STATUS_UNSUCCESSFUL
;
1296 DPRINT("Name %S, Pin %lu bInput %lu\n", OutConnection
->SymbolicLinkName
, OutConnection
->Pin
, bInput
);
1299 ASSERT(MixerData
->MixerInfo
== NULL
|| MixerData
->MixerInfo
== MixerInfo
);
1301 /* associate with mixer */
1302 MixerData
->MixerInfo
= MixerInfo
;
1304 if (MixerData
->Topology
== NULL
)
1306 /* construct new topology */
1307 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1308 if (Status
!= MM_STATUS_SUCCESS
)
1310 /* failed to create topology */
1314 /* store topology */
1315 MixerData
->Topology
= Topology
;
1319 /* re-use existing topology */
1320 Topology
= MixerData
->Topology
;
1323 /* mark pin as consumed */
1324 MMixerSetTopologyPinReserved(Topology
, OutConnection
->Pin
);
1328 /* allocate pin index array which will hold all referenced pins */
1329 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1330 if (Status
!= MM_STATUS_SUCCESS
)
1332 /* failed to create topology */
1336 /* the mixer is an output mixer
1337 * find end pin of the node path
1340 Status
= MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext
, Topology
, OutConnection
->Pin
, FALSE
, &PinsCount
, Pins
);
1342 /* check for success */
1343 if (Status
!= MM_STATUS_SUCCESS
)
1345 /* failed to get end pin */
1346 MixerContext
->Free(Pins
);
1347 //MMixerFreeTopology(Topology);
1349 /* return error code */
1353 * some topologies do not have strict boundaries
1354 * WorkArround: remove all pin ids which have a physical connection
1355 * because bridge pins may belong to different render paths
1357 MMixerApplyOutputFilterHack(MixerContext
, MixerData
, MixerData
->hDevice
, &PinsCount
, Pins
);
1360 ASSERT(PinsCount
!= 0);
1363 DPRINT1("MMixerHandlePhysicalConnection Expected 1 pin but got %lu\n", PinsCount
);
1366 /* create destination line */
1367 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Pins
[0], bInput
);
1369 /* calculate destination line id */
1370 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1372 if (Status
!= MM_STATUS_SUCCESS
)
1374 /* failed to build destination line */
1375 MixerContext
->Free(Pins
);
1377 /* return error code */
1381 /* add mixer controls to destination line */
1382 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, Pins
[0], bInput
, DestinationLineID
, &LineTerminator
);
1384 if (Status
== MM_STATUS_SUCCESS
)
1386 /* now add the rest of the source lines */
1387 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, DestinationLineID
, LineTerminator
);
1390 /* mark pin as consumed */
1391 MMixerSetTopologyPinReserved(Topology
, Pins
[0]);
1393 /* free topology pin array */
1394 MixerContext
->Free(Pins
);
1398 /* calculate destination line id */
1399 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1401 /* add mixer controls */
1402 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, OutConnection
->Pin
, bInput
, DestinationLineID
, &LineTerminator
);
1404 if (Status
== MM_STATUS_SUCCESS
)
1406 /* now add the rest of the source lines */
1407 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, DestinationLineID
, LineTerminator
);
1415 MMixerInitializeFilter(
1416 IN PMIXER_CONTEXT MixerContext
,
1417 IN PMIXER_LIST MixerList
,
1418 IN LPMIXER_DATA MixerData
,
1419 IN LPMIXER_INFO MixerInfo
,
1420 IN PTOPOLOGY Topology
,
1422 IN ULONG bInputMixer
,
1423 IN OUT LPMIXER_INFO
* OutMixerInfo
)
1426 MIXER_STATUS Status
;
1427 PKSPIN_PHYSICALCONNECTION OutConnection
;
1430 ULONG NewMixerInfo
= FALSE
;
1432 if (MixerInfo
== NULL
)
1434 /* allocate a mixer info struct */
1435 MixerInfo
= (LPMIXER_INFO
) MixerContext
->Alloc(sizeof(MIXER_INFO
));
1439 return MM_STATUS_NO_MEMORY
;
1442 /* new mixer info */
1443 NewMixerInfo
= TRUE
;
1445 /* intialize mixer caps */
1446 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; /* FIXME */
1447 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; /* FIXME */
1448 MixerInfo
->MixCaps
.vDriverVersion
= 1; /* FIXME */
1449 MixerInfo
->MixCaps
.fdwSupport
= 0;
1450 MixerInfo
->MixCaps
.cDestinations
= 0;
1452 /* get mixer name */
1453 MMixerGetDeviceName(MixerContext
, MixerInfo
->MixCaps
.szPname
, MixerData
->hDeviceInterfaceKey
);
1455 /* initialize line list */
1456 InitializeListHead(&MixerInfo
->LineList
);
1457 InitializeListHead(&MixerInfo
->EventList
);
1459 /* associate with mixer data */
1460 MixerData
->MixerInfo
= MixerInfo
;
1463 /* store mixer info */
1464 *OutMixerInfo
= MixerInfo
;
1466 /* now allocate an array which will receive the indices of the pin
1467 * which has a ADC / DAC nodetype in its path
1469 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1470 ASSERT(Status
== MM_STATUS_SUCCESS
);
1474 /* now get all sink / source pins, which are attached to the ADC / DAC node
1475 * For sink pins (wave out) search up stream
1476 * For source pins (wave in) search down stream
1477 * The search direction is always the opposite of the current mixer type
1480 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, !bInputMixer
, &PinsFound
, Pins
);
1482 /* if there is no pin found, we have a broken topology */
1483 ASSERT(PinsFound
!= 0);
1485 /* now create a wave info struct */
1486 Status
= MMixerInitializeWaveInfo(MixerContext
, MixerList
, MixerData
, MixerInfo
->MixCaps
.szPname
, bInputMixer
, PinsFound
, Pins
);
1487 if (Status
!= MM_STATUS_SUCCESS
)
1489 /* failed to create wave info struct */
1490 MixerContext
->Free(MixerInfo
);
1491 MixerContext
->Free(Pins
);
1495 /* mark all found pins as reserved */
1496 for(Index
= 0; Index
< PinsFound
; Index
++)
1498 MMixerSetTopologyPinReserved(Topology
, Pins
[Index
]);
1503 /* pre create the mixer destination line for input mixers */
1504 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Pins
[0], bInputMixer
);
1506 if (Status
!= MM_STATUS_SUCCESS
)
1508 /* failed to create mixer destination line */
1514 /* now get the bridge pin which is at the end of node path
1515 * For sink pins (wave out) search down stream
1516 * For source pins (wave in) search up stream
1518 MixerContext
->Free(Pins
);
1519 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1520 ASSERT(Status
== MM_STATUS_SUCCESS
);
1523 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bInputMixer
, &PinsFound
, Pins
);
1525 /* if there is no pin found, we have a broken topology */
1526 ASSERT(PinsFound
!= 0);
1528 /* there should be exactly one bridge pin */
1529 ASSERT(PinsFound
== 1);
1531 DPRINT("BridgePin %lu bInputMixer %lu\n", Pins
[0], bInputMixer
);
1533 /* does the pin have a physical connection */
1534 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Pins
[0], &OutConnection
);
1536 if (Status
== MM_STATUS_SUCCESS
)
1538 /* mark pin as reserved */
1539 MMixerSetTopologyPinReserved(Topology
, Pins
[0]);
1541 /* topology on the topoloy filter */
1542 Status
= MMixerHandlePhysicalConnection(MixerContext
, MixerList
, MixerData
, MixerInfo
, bInputMixer
, OutConnection
);
1544 /* free physical connection data */
1545 MixerContext
->Free(OutConnection
);
1550 * handle drivers which expose their topology on the same filter
1556 MixerContext
->Free(Pins
);
1561 InsertHeadList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1562 /* increment mixer count */
1563 MixerList
->MixerListCount
++;
1571 MMixerHandleAlternativeMixers(
1572 IN PMIXER_CONTEXT MixerContext
,
1573 IN PMIXER_LIST MixerList
,
1574 IN LPMIXER_DATA MixerData
,
1575 IN PTOPOLOGY Topology
)
1577 ULONG Index
, PinCount
, Reserved
;
1578 MIXER_STATUS Status
;
1579 ULONG DestinationLineID
, LineTerminator
;
1580 LPMIXERLINE_EXT DstLine
;
1582 DPRINT("DeviceName %S\n", MixerData
->DeviceName
);
1584 /* get topology pin count */
1585 MMixerGetTopologyPinCount(Topology
, &PinCount
);
1587 for(Index
= 0; Index
< PinCount
; Index
++)
1589 MMixerIsTopologyPinReserved(Topology
, Index
, &Reserved
);
1591 /* check if it has already been reserved */
1594 /* pin has already been reserved */
1598 DPRINT("MixerName %S Available PinID %lu\n", MixerData
->DeviceName
, Index
);
1601 //ASSERT(MixerData->MixerInfo);
1603 if (!MixerData
->MixerInfo
)
1605 DPRINT1("Expected mixer info\n");
1609 /* build the destination line */
1610 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerData
->MixerInfo
, MixerData
->hDevice
, Index
, TRUE
);
1611 if (Status
!= MM_STATUS_SUCCESS
)
1613 /* failed to build destination line */
1617 /* calculate destination line id */
1618 DestinationLineID
= (DESTINATION_LINE
+ MixerData
->MixerInfo
->MixCaps
.cDestinations
-1);
1620 /* add mixer controls to destination line */
1621 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerData
->MixerInfo
, MixerData
->hDevice
, MixerData
->Topology
, Index
, TRUE
, DestinationLineID
, &LineTerminator
);
1622 if (Status
== MM_STATUS_SUCCESS
)
1624 /* now add the rest of the source lines */
1625 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerData
->MixerInfo
, MixerData
->hDevice
, MixerData
->Topology
, DestinationLineID
, LineTerminator
);
1628 /* mark pin as consumed */
1629 MMixerSetTopologyPinReserved(Topology
, Index
);
1631 /* now grab destination line */
1632 DstLine
= MMixerGetSourceMixerLineByLineId(MixerData
->MixerInfo
, DestinationLineID
);
1634 /* set type and target as undefined */
1635 DstLine
->Line
.dwComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
1636 DstLine
->Line
.Target
.dwType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
1637 DstLine
->Line
.Target
.vDriverVersion
= 0;
1638 DstLine
->Line
.Target
.wMid
= 0;
1639 DstLine
->Line
.Target
.wPid
= 0;
1645 IN PMIXER_CONTEXT MixerContext
,
1646 IN PMIXER_LIST MixerList
,
1647 IN LPMIXER_DATA MixerData
,
1648 IN PULONG DeviceCount
)
1650 MIXER_STATUS Status
= MM_STATUS_SUCCESS
;
1653 LPMIXER_INFO MixerInfo
= NULL
;
1655 /* check if topology has already been built */
1656 if (MixerData
->Topology
== NULL
)
1658 /* build topology */
1659 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1661 if (Status
!= MM_STATUS_SUCCESS
)
1663 /* failed to build topology */
1667 /* store topology */
1668 MixerData
->Topology
= Topology
;
1672 /* re-use topology */
1673 Topology
= MixerData
->Topology
;
1676 /* check if the filter has an wave out node */
1677 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_DAC
);
1678 if (NodeIndex
!= MAXULONG
)
1681 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, NULL
, Topology
, NodeIndex
, FALSE
, &MixerInfo
);
1683 /* check for success */
1684 if (Status
== MM_STATUS_SUCCESS
)
1686 /* increment mixer count */
1691 /* reset mixer info in case of error */
1696 /* check if the filter has an wave in node */
1697 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_ADC
);
1698 if (NodeIndex
!= MAXULONG
)
1701 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, MixerInfo
, Topology
, NodeIndex
, TRUE
, &MixerInfo
);
1703 /* check for success */
1704 if (Status
== MM_STATUS_SUCCESS
)
1706 /* increment mixer count */
1712 /* TODO: apply hacks for Wave source line */
1714 /* activate midi devices */
1715 //MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology);
1724 IN PMIXER_CONTEXT MixerContext
,
1725 IN OUT LPMIXER_INFO MixerInfo
,
1726 IN PVOID MixerEventContext
,
1727 IN PMIXER_EVENT MixerEventRoutine
)
1729 //KSE_NODE Property;
1730 PEVENT_NOTIFICATION_ENTRY EventData
;
1731 //ULONG BytesReturned;
1732 //MIXER_STATUS Status;
1734 EventData
= (PEVENT_NOTIFICATION_ENTRY
)MixerContext
->AllocEventData(sizeof(EVENT_NOTIFICATION_ENTRY
));
1737 /* not enough memory */
1738 return MM_STATUS_NO_MEMORY
;
1743 Property
.Event
.Set
= KSEVENTSETID_AudioControlChange
;
1744 Property
.Event
.Flags
= KSEVENT_TYPE_TOPOLOGY
|KSEVENT_TYPE_ENABLE
;
1745 Property
.Event
.Id
= KSEVENT_CONTROL_CHANGE
;
1747 Property
.NodeId
= NodeId
;
1748 Property
.Reserved
= 0;
1750 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSP_NODE
), (PVOID
)EventData
, sizeof(KSEVENTDATA
), &BytesReturned
);
1751 if (Status
!= MM_STATUS_SUCCESS
)
1753 /* failed to add event */
1754 MixerContext
->FreeEventData(EventData
);
1759 /* initialize notification entry */
1760 EventData
->MixerEventContext
= MixerEventContext
;
1761 EventData
->MixerEventRoutine
= MixerEventRoutine
;
1764 InsertTailList(&MixerInfo
->EventList
, &EventData
->Entry
);
1765 return MM_STATUS_SUCCESS
;