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 MMixerHandleTopologyFilter(
1273 IN PMIXER_CONTEXT MixerContext
,
1274 IN PMIXER_LIST MixerList
,
1275 IN LPMIXER_DATA MixerData
,
1276 IN OUT LPMIXER_INFO MixerInfo
,
1280 MIXER_STATUS Status
;
1281 ULONG PinsCount
, LineTerminator
, DestinationLineID
;
1285 /* re-use existing topology */
1286 Topology
= MixerData
->Topology
;
1290 /* allocate pin index array which will hold all referenced pins */
1291 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1292 if (Status
!= MM_STATUS_SUCCESS
)
1294 /* failed to create topology */
1298 /* the mixer is an output mixer
1299 * find end pin of the node path
1302 Status
= MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext
, Topology
, Pin
, FALSE
, &PinsCount
, Pins
);
1304 /* check for success */
1305 if (Status
!= MM_STATUS_SUCCESS
)
1307 /* failed to get end pin */
1308 MixerContext
->Free(Pins
);
1309 //MMixerFreeTopology(Topology);
1311 /* return error code */
1315 * some topologies do not have strict boundaries
1316 * WorkArround: remove all pin ids which have a physical connection
1317 * because bridge pins may belong to different render paths
1319 MMixerApplyOutputFilterHack(MixerContext
, MixerData
, MixerData
->hDevice
, &PinsCount
, Pins
);
1322 ASSERT(PinsCount
!= 0);
1325 DPRINT1("MMixerHandlePhysicalConnection Expected 1 pin but got %lu\n", PinsCount
);
1328 /* create destination line */
1329 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Pins
[0], bInput
);
1331 /* calculate destination line id */
1332 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
- 1);
1334 if (Status
!= MM_STATUS_SUCCESS
)
1336 /* failed to build destination line */
1337 MixerContext
->Free(Pins
);
1339 /* return error code */
1343 /* add mixer controls to destination line */
1344 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, Pins
[0], bInput
, DestinationLineID
, &LineTerminator
);
1346 if (Status
== MM_STATUS_SUCCESS
)
1348 /* now add the rest of the source lines */
1349 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, DestinationLineID
, LineTerminator
);
1352 /* mark pin as consumed */
1353 MMixerSetTopologyPinReserved(Topology
, Pins
[0]);
1355 /* free topology pin array */
1356 MixerContext
->Free(Pins
);
1360 /* calculate destination line id */
1361 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
- 1);
1363 /* add mixer controls */
1364 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, Pin
, bInput
, DestinationLineID
, &LineTerminator
);
1366 if (Status
== MM_STATUS_SUCCESS
)
1368 /* now add the rest of the source lines */
1369 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, DestinationLineID
, LineTerminator
);
1376 MMixerHandlePhysicalConnection(
1377 IN PMIXER_CONTEXT MixerContext
,
1378 IN PMIXER_LIST MixerList
,
1379 IN LPMIXER_DATA MixerData
,
1380 IN OUT LPMIXER_INFO MixerInfo
,
1382 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
1384 MIXER_STATUS Status
;
1385 ULONG PinsCount
, LineTerminator
, DestinationLineID
;
1389 /* first try to open the connected filter */
1390 OutConnection
->SymbolicLinkName
[1] = L
'\\';
1391 MixerData
= MMixerGetDataByDeviceName(MixerList
, OutConnection
->SymbolicLinkName
);
1393 /* check if the linked connection is found */
1396 /* filter references invalid physical connection */
1397 return MM_STATUS_UNSUCCESSFUL
;
1400 DPRINT("Name %S, Pin %lu bInput %lu\n", OutConnection
->SymbolicLinkName
, OutConnection
->Pin
, bInput
);
1403 ASSERT(MixerData
->MixerInfo
== NULL
|| MixerData
->MixerInfo
== MixerInfo
);
1405 /* associate with mixer */
1406 MixerData
->MixerInfo
= MixerInfo
;
1408 if (MixerData
->Topology
== NULL
)
1410 /* construct new topology */
1411 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1412 if (Status
!= MM_STATUS_SUCCESS
)
1414 /* failed to create topology */
1418 /* store topology */
1419 MixerData
->Topology
= Topology
;
1423 /* re-use existing topology */
1424 Topology
= MixerData
->Topology
;
1427 /* mark pin as consumed */
1428 MMixerSetTopologyPinReserved(Topology
, OutConnection
->Pin
);
1432 /* allocate pin index array which will hold all referenced pins */
1433 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1434 if (Status
!= MM_STATUS_SUCCESS
)
1436 /* failed to create topology */
1440 /* the mixer is an output mixer
1441 * find end pin of the node path
1444 Status
= MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext
, Topology
, OutConnection
->Pin
, FALSE
, &PinsCount
, Pins
);
1446 /* check for success */
1447 if (Status
!= MM_STATUS_SUCCESS
)
1449 /* failed to get end pin */
1450 MixerContext
->Free(Pins
);
1451 //MMixerFreeTopology(Topology);
1453 /* return error code */
1457 * some topologies do not have strict boundaries
1458 * WorkArround: remove all pin ids which have a physical connection
1459 * because bridge pins may belong to different render paths
1461 MMixerApplyOutputFilterHack(MixerContext
, MixerData
, MixerData
->hDevice
, &PinsCount
, Pins
);
1464 ASSERT(PinsCount
!= 0);
1467 DPRINT1("MMixerHandlePhysicalConnection Expected 1 pin but got %lu\n", PinsCount
);
1470 /* create destination line */
1471 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Pins
[0], bInput
);
1473 /* calculate destination line id */
1474 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1476 if (Status
!= MM_STATUS_SUCCESS
)
1478 /* failed to build destination line */
1479 MixerContext
->Free(Pins
);
1481 /* return error code */
1485 /* add mixer controls to destination line */
1486 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, Pins
[0], bInput
, DestinationLineID
, &LineTerminator
);
1488 if (Status
== MM_STATUS_SUCCESS
)
1490 /* now add the rest of the source lines */
1491 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, DestinationLineID
, LineTerminator
);
1494 /* mark pin as consumed */
1495 MMixerSetTopologyPinReserved(Topology
, Pins
[0]);
1497 /* free topology pin array */
1498 MixerContext
->Free(Pins
);
1502 /* calculate destination line id */
1503 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1505 /* add mixer controls */
1506 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, OutConnection
->Pin
, bInput
, DestinationLineID
, &LineTerminator
);
1508 if (Status
== MM_STATUS_SUCCESS
)
1510 /* now add the rest of the source lines */
1511 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, DestinationLineID
, LineTerminator
);
1519 MMixerInitializeFilter(
1520 IN PMIXER_CONTEXT MixerContext
,
1521 IN PMIXER_LIST MixerList
,
1522 IN LPMIXER_DATA MixerData
,
1523 IN LPMIXER_INFO MixerInfo
,
1524 IN PTOPOLOGY Topology
,
1526 IN ULONG bInputMixer
,
1527 IN OUT LPMIXER_INFO
* OutMixerInfo
)
1530 MIXER_STATUS Status
;
1531 PKSPIN_PHYSICALCONNECTION OutConnection
;
1534 ULONG NewMixerInfo
= FALSE
;
1536 if (MixerInfo
== NULL
)
1538 /* allocate a mixer info struct */
1539 MixerInfo
= (LPMIXER_INFO
) MixerContext
->Alloc(sizeof(MIXER_INFO
));
1543 return MM_STATUS_NO_MEMORY
;
1546 /* new mixer info */
1547 NewMixerInfo
= TRUE
;
1549 /* intialize mixer caps */
1550 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; /* FIXME */
1551 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; /* FIXME */
1552 MixerInfo
->MixCaps
.vDriverVersion
= 1; /* FIXME */
1553 MixerInfo
->MixCaps
.fdwSupport
= 0;
1554 MixerInfo
->MixCaps
.cDestinations
= 0;
1556 /* get mixer name */
1557 Status
= MMixerGetDeviceName(MixerContext
, MixerInfo
->MixCaps
.szPname
, MixerData
->hDeviceInterfaceKey
);
1558 if (Status
!= MM_STATUS_SUCCESS
)
1560 /* try get name with component id */
1561 Status
= MMixerGetDeviceNameWithComponentId(MixerContext
, MixerData
->hDevice
, MixerInfo
->MixCaps
.szPname
);
1564 /* initialize line list */
1565 InitializeListHead(&MixerInfo
->LineList
);
1566 InitializeListHead(&MixerInfo
->EventList
);
1568 /* associate with mixer data */
1569 MixerData
->MixerInfo
= MixerInfo
;
1572 /* store mixer info */
1573 *OutMixerInfo
= MixerInfo
;
1575 /* now allocate an array which will receive the indices of the pin
1576 * which has a ADC / DAC nodetype in its path
1578 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1579 ASSERT(Status
== MM_STATUS_SUCCESS
);
1583 /* now get all sink / source pins, which are attached to the ADC / DAC node
1584 * For sink pins (wave out) search up stream
1585 * For source pins (wave in) search down stream
1586 * The search direction is always the opposite of the current mixer type
1589 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, !bInputMixer
, &PinsFound
, Pins
);
1591 /* if there is no pin found, we have a broken topology */
1592 ASSERT(PinsFound
!= 0);
1594 /* now create a wave info struct */
1595 Status
= MMixerInitializeWaveInfo(MixerContext
, MixerList
, MixerData
, MixerInfo
->MixCaps
.szPname
, bInputMixer
, PinsFound
, Pins
);
1596 if (Status
!= MM_STATUS_SUCCESS
)
1598 /* failed to create wave info struct */
1599 MixerContext
->Free(MixerInfo
);
1600 MixerContext
->Free(Pins
);
1604 /* mark all found pins as reserved */
1605 for(Index
= 0; Index
< PinsFound
; Index
++)
1607 MMixerSetTopologyPinReserved(Topology
, Pins
[Index
]);
1612 /* pre create the mixer destination line for input mixers */
1613 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Pins
[0], bInputMixer
);
1615 if (Status
!= MM_STATUS_SUCCESS
)
1617 /* failed to create mixer destination line */
1623 /* now get the bridge pin which is at the end of node path
1624 * For sink pins (wave out) search down stream
1625 * For source pins (wave in) search up stream
1627 MixerContext
->Free(Pins
);
1628 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1629 ASSERT(Status
== MM_STATUS_SUCCESS
);
1632 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bInputMixer
, &PinsFound
, Pins
);
1634 /* if there is no pin found, we have a broken topology */
1635 ASSERT(PinsFound
!= 0);
1637 /* there should be exactly one bridge pin */
1638 ASSERT(PinsFound
== 1);
1640 DPRINT("BridgePin %lu bInputMixer %lu\n", Pins
[0], bInputMixer
);
1642 /* does the pin have a physical connection */
1643 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Pins
[0], &OutConnection
);
1645 if (Status
== MM_STATUS_SUCCESS
)
1647 /* mark pin as reserved */
1648 MMixerSetTopologyPinReserved(Topology
, Pins
[0]);
1650 /* topology on the topoloy filter */
1651 Status
= MMixerHandlePhysicalConnection(MixerContext
, MixerList
, MixerData
, MixerInfo
, bInputMixer
, OutConnection
);
1653 /* free physical connection data */
1654 MixerContext
->Free(OutConnection
);
1658 /* topology is on the same filter */
1659 Status
= MMixerHandleTopologyFilter(MixerContext
, MixerList
, MixerData
, MixerInfo
, bInputMixer
, Pins
[0]);
1663 MixerContext
->Free(Pins
);
1668 InsertHeadList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1669 /* increment mixer count */
1670 MixerList
->MixerListCount
++;
1678 MMixerHandleAlternativeMixers(
1679 IN PMIXER_CONTEXT MixerContext
,
1680 IN PMIXER_LIST MixerList
,
1681 IN LPMIXER_DATA MixerData
,
1682 IN PTOPOLOGY Topology
)
1684 ULONG Index
, PinCount
, Reserved
;
1685 MIXER_STATUS Status
;
1686 ULONG DestinationLineID
, LineTerminator
;
1687 LPMIXERLINE_EXT DstLine
;
1689 DPRINT("DeviceName %S\n", MixerData
->DeviceName
);
1691 /* get topology pin count */
1692 MMixerGetTopologyPinCount(Topology
, &PinCount
);
1694 for(Index
= 0; Index
< PinCount
; Index
++)
1696 MMixerIsTopologyPinReserved(Topology
, Index
, &Reserved
);
1698 /* check if it has already been reserved */
1701 /* pin has already been reserved */
1705 DPRINT("MixerName %S Available PinID %lu\n", MixerData
->DeviceName
, Index
);
1708 //ASSERT(MixerData->MixerInfo);
1710 if (!MixerData
->MixerInfo
)
1712 DPRINT1("Expected mixer info\n");
1716 /* build the destination line */
1717 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerData
->MixerInfo
, MixerData
->hDevice
, Index
, TRUE
);
1718 if (Status
!= MM_STATUS_SUCCESS
)
1720 /* failed to build destination line */
1724 /* calculate destination line id */
1725 DestinationLineID
= (DESTINATION_LINE
+ MixerData
->MixerInfo
->MixCaps
.cDestinations
-1);
1727 /* add mixer controls to destination line */
1728 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerData
->MixerInfo
, MixerData
->hDevice
, MixerData
->Topology
, Index
, TRUE
, DestinationLineID
, &LineTerminator
);
1729 if (Status
== MM_STATUS_SUCCESS
)
1731 /* now add the rest of the source lines */
1732 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerData
->MixerInfo
, MixerData
->hDevice
, MixerData
->Topology
, DestinationLineID
, LineTerminator
);
1735 /* mark pin as consumed */
1736 MMixerSetTopologyPinReserved(Topology
, Index
);
1738 /* now grab destination line */
1739 DstLine
= MMixerGetSourceMixerLineByLineId(MixerData
->MixerInfo
, DestinationLineID
);
1741 /* set type and target as undefined */
1742 DstLine
->Line
.dwComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
1743 DstLine
->Line
.Target
.dwType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
1744 DstLine
->Line
.Target
.vDriverVersion
= 0;
1745 DstLine
->Line
.Target
.wMid
= 0;
1746 DstLine
->Line
.Target
.wPid
= 0;
1752 IN PMIXER_CONTEXT MixerContext
,
1753 IN PMIXER_LIST MixerList
,
1754 IN LPMIXER_DATA MixerData
,
1755 IN PULONG DeviceCount
)
1757 MIXER_STATUS Status
= MM_STATUS_SUCCESS
;
1760 LPMIXER_INFO MixerInfo
= NULL
;
1762 /* check if topology has already been built */
1763 if (MixerData
->Topology
== NULL
)
1765 /* build topology */
1766 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1768 if (Status
!= MM_STATUS_SUCCESS
)
1770 /* failed to build topology */
1774 /* store topology */
1775 MixerData
->Topology
= Topology
;
1779 /* re-use topology */
1780 Topology
= MixerData
->Topology
;
1783 /* check if the filter has an wave out node */
1784 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_DAC
);
1785 if (NodeIndex
!= MAXULONG
)
1788 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, NULL
, Topology
, NodeIndex
, FALSE
, &MixerInfo
);
1790 /* check for success */
1791 if (Status
== MM_STATUS_SUCCESS
)
1793 /* increment mixer count */
1798 /* reset mixer info in case of error */
1803 /* check if the filter has an wave in node */
1804 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_ADC
);
1805 if (NodeIndex
!= MAXULONG
)
1808 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, MixerInfo
, Topology
, NodeIndex
, TRUE
, &MixerInfo
);
1810 /* check for success */
1811 if (Status
== MM_STATUS_SUCCESS
)
1813 /* increment mixer count */
1819 /* TODO: apply hacks for Wave source line */
1821 /* activate midi devices */
1822 //MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology);
1831 IN PMIXER_CONTEXT MixerContext
,
1832 IN OUT LPMIXER_INFO MixerInfo
,
1833 IN PVOID MixerEventContext
,
1834 IN PMIXER_EVENT MixerEventRoutine
)
1836 //KSE_NODE Property;
1837 //KSEVENTDATA EventData
1838 //ULONG BytesReturned;
1839 //MIXER_STATUS Status;
1840 PEVENT_NOTIFICATION_ENTRY EventNotification
;
1842 EventNotification
= (PEVENT_NOTIFICATION_ENTRY
)MixerContext
->Alloc(sizeof(EVENT_NOTIFICATION_ENTRY
));
1843 if (!EventNotification
)
1845 /* not enough memory */
1846 return MM_STATUS_NO_MEMORY
;
1849 /* FIXME: what is it supposed to happen with KSEVENTDATA ? */
1852 Property
.Event
.Set
= KSEVENTSETID_AudioControlChange
;
1853 Property
.Event
.Flags
= KSEVENT_TYPE_TOPOLOGY
|KSEVENT_TYPE_ENABLE
;
1854 Property
.Event
.Id
= KSEVENT_CONTROL_CHANGE
;
1856 Property
.NodeId
= NodeId
;
1857 Property
.Reserved
= 0;
1859 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSP_NODE
), (PVOID
)EventData
, sizeof(KSEVENTDATA
), &BytesReturned
);
1860 if (Status
!= MM_STATUS_SUCCESS
)
1862 /* failed to add event */
1863 MixerContext
->FreeEventData(EventData
);
1868 /* initialize notification entry */
1869 EventNotification
->MixerEventContext
= MixerEventContext
;
1870 EventNotification
->MixerEventRoutine
= MixerEventRoutine
;
1873 InsertTailList(&MixerInfo
->EventList
, &EventNotification
->Entry
);
1874 return MM_STATUS_SUCCESS
;
1879 IN PMIXER_CONTEXT MixerContext
,
1880 IN OUT LPMIXER_INFO MixerInfo
,
1881 IN PVOID MixerEventContext
,
1882 IN PMIXER_EVENT MixerEventRoutine
)
1884 PLIST_ENTRY EventList
;
1885 PEVENT_NOTIFICATION_ENTRY NotificationEntry
;
1887 /* Lookup through mixers */
1888 EventList
= MixerInfo
->EventList
.Flink
;
1889 while(EventList
!= &MixerInfo
->EventList
)
1891 NotificationEntry
= CONTAINING_RECORD(EventList
, EVENT_NOTIFICATION_ENTRY
, Entry
);
1892 EventList
= EventList
->Flink
;
1893 /* TODO: find a better way to identify an event ? */
1894 if(NotificationEntry
->MixerEventRoutine
== MixerEventRoutine
&&
1895 NotificationEntry
->MixerEventContext
== MixerEventContext
)
1897 DPRINT1("Freeing entry %p\n", NotificationEntry
);
1898 /* We found the event to remove */
1899 RemoveEntryList(&NotificationEntry
->Entry
);
1900 MixerContext
->Free(NotificationEntry
);
1903 return MM_STATUS_SUCCESS
;