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
11 const GUID KSNODETYPE_DESKTOP_MICROPHONE
= {0xDFF21BE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
12 const GUID KSNODETYPE_LEGACY_AUDIO_CONNECTOR
= {0xDFF21FE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
13 const GUID KSNODETYPE_TELEPHONE
= {0xDFF21EE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
14 const GUID KSNODETYPE_PHONE_LINE
= {0xDFF21EE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
15 const GUID KSNODETYPE_DOWN_LINE_PHONE
= {0xDFF21EE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
16 const GUID KSNODETYPE_DESKTOP_SPEAKER
= {0xDFF21CE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
17 const GUID KSNODETYPE_ROOM_SPEAKER
= {0xDFF21CE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
18 const GUID KSNODETYPE_COMMUNICATION_SPEAKER
= {0xDFF21CE6, 0xF70F, 0x11D0, {0xB9,0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
19 const GUID KSNODETYPE_HEADPHONES
= {0xDFF21CE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
20 const GUID KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO
= {0xDFF21CE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
21 const GUID KSNODETYPE_MICROPHONE
= {0xDFF21BE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9,0x22, 0x31, 0x96}};
22 const GUID KSCATEGORY_AUDIO
= {0x6994AD04L
, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
23 const GUID KSNODETYPE_SPDIF_INTERFACE
= {0xDFF21FE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
24 const GUID KSNODETYPE_ANALOG_CONNECTOR
= {0xDFF21FE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
25 const GUID KSNODETYPE_SPEAKER
= {0xDFF21CE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
26 const GUID KSNODETYPE_CD_PLAYER
= {0xDFF220E3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
27 const GUID KSNODETYPE_SYNTHESIZER
= {0xDFF220F3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
28 const GUID KSNODETYPE_LINE_CONNECTOR
= {0xDFF21FE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0,0xC9, 0x22, 0x31, 0x96}};
29 const GUID PINNAME_VIDEO_CAPTURE
= {0xfb6c4281, 0x353, 0x11d1, {0x90, 0x5f, 0x0, 0x0, 0xc0, 0xcc, 0x16, 0xba}};
32 MMixerAddMixerControl(
33 IN PMIXER_CONTEXT MixerContext
,
34 IN LPMIXER_INFO MixerInfo
,
36 IN PTOPOLOGY Topology
,
38 IN LPMIXERLINE_EXT MixerLine
)
45 LPMIXERCONTROL_EXT MixerControl
;
47 /* allocate mixer control */
48 MixerControl
= MixerContext
->Alloc(sizeof(MIXERCONTROL_EXT
));
52 return MM_STATUS_NO_MEMORY
;
56 /* initialize mixer control */
57 MixerControl
->hDevice
= hMixer
;
58 MixerControl
->NodeID
= NodeIndex
;
59 MixerControl
->ExtraData
= NULL
;
61 MixerControl
->Control
.cbStruct
= sizeof(MIXERCONTROLW
);
62 MixerControl
->Control
.dwControlID
= MixerInfo
->ControlId
;
65 NodeType
= MMixerGetNodeTypeFromTopology(Topology
, NodeIndex
);
66 /* store control type */
67 MixerControl
->Control
.dwControlType
= MMixerGetControlTypeFromTopologyNode(NodeType
);
69 MixerControl
->Control
.fdwControl
= MIXERCONTROL_CONTROLF_UNIFORM
; /* FIXME */
70 MixerControl
->Control
.cMultipleItems
= 0;
72 /* setup request to retrieve name */
73 Node
.NodeId
= NodeIndex
;
74 Node
.Property
.Id
= KSPROPERTY_TOPOLOGY_NAME
;
75 Node
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
76 Node
.Property
.Set
= KSPROPSETID_Topology
;
79 /* get node name size */
80 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), NULL
, 0, &BytesReturned
);
82 if (Status
== MM_STATUS_MORE_ENTRIES
)
84 ASSERT(BytesReturned
!= 0);
85 Name
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
88 /* not enough memory */
89 return MM_STATUS_NO_MEMORY
;
93 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), (LPVOID
)Name
, BytesReturned
, &BytesReturned
);
95 if (Status
== MM_STATUS_SUCCESS
)
97 MixerContext
->Copy(MixerControl
->Control
.szShortName
, Name
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
98 MixerControl
->Control
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
100 MixerContext
->Copy(MixerControl
->Control
.szName
, Name
, (min(MIXER_LONG_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
101 MixerControl
->Control
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
104 /* free name buffer */
105 MixerContext
->Free(Name
);
108 /* increment control count */
109 MixerInfo
->ControlId
++;
112 InsertTailList(&MixerLine
->ControlsList
, &MixerControl
->Entry
);
114 if (MixerControl
->Control
.dwControlType
== MIXERCONTROL_CONTROLTYPE_MUX
)
119 /* allocate topology nodes array */
120 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
122 if (Status
!= MM_STATUS_SUCCESS
)
125 return STATUS_NO_MEMORY
;
128 /* get connected node count */
129 MMixerGetNextNodesFromNodeIndex(MixerContext
, Topology
, NodeIndex
, TRUE
, &NodesCount
, Nodes
);
132 MixerContext
->Free(Nodes
);
134 /* setup mux bounds */
135 MixerControl
->Control
.Bounds
.dwMinimum
= 0;
136 MixerControl
->Control
.Bounds
.dwMaximum
= NodesCount
- 1;
137 MixerControl
->Control
.Metrics
.dwReserved
[0] = NodesCount
;
138 MixerControl
->Control
.cMultipleItems
= NodesCount
;
139 MixerControl
->Control
.fdwControl
|= MIXERCONTROL_CONTROLF_MULTIPLE
;
141 else if (MixerControl
->Control
.dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
143 MixerControl
->Control
.Bounds
.dwMinimum
= 0;
144 MixerControl
->Control
.Bounds
.dwMaximum
= 1;
146 else if (MixerControl
->Control
.dwControlType
== MIXERCONTROL_CONTROLTYPE_ONOFF
)
148 /* only needs to set bounds */
149 MixerControl
->Control
.Bounds
.dwMinimum
= 0;
150 MixerControl
->Control
.Bounds
.dwMaximum
= 1;
152 else if (MixerControl
->Control
.dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
154 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
156 PKSPROPERTY_DESCRIPTION Desc
;
157 PKSPROPERTY_MEMBERSHEADER Members
;
158 PKSPROPERTY_STEPPING_LONG Range
;
160 MixerControl
->Control
.Bounds
.dwMinimum
= 0;
161 MixerControl
->Control
.Bounds
.dwMaximum
= 0xFFFF;
162 MixerControl
->Control
.Metrics
.cSteps
= 0xC0; /* FIXME */
164 Length
= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) + sizeof(KSPROPERTY_STEPPING_LONG
);
165 Desc
= (PKSPROPERTY_DESCRIPTION
)MixerContext
->Alloc(Length
);
168 /* setup the request */
169 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
171 Property
.NodeProperty
.NodeId
= NodeIndex
;
172 Property
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
173 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
| KSPROPERTY_TYPE_TOPOLOGY
;
174 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
176 /* get node volume level info */
177 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), Desc
, Length
, &BytesReturned
);
179 if (Status
== MM_STATUS_SUCCESS
)
181 LPMIXERVOLUME_DATA VolumeData
;
182 ULONG Steps
, MaxRange
, Index
;
185 Members
= (PKSPROPERTY_MEMBERSHEADER
)(Desc
+ 1);
186 Range
= (PKSPROPERTY_STEPPING_LONG
)(Members
+ 1);
188 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
);
190 MaxRange
= Range
->Bounds
.UnsignedMaximum
- Range
->Bounds
.UnsignedMinimum
;
195 VolumeData
= (LPMIXERVOLUME_DATA
)MixerContext
->Alloc(sizeof(MIXERVOLUME_DATA
));
197 return MM_STATUS_NO_MEMORY
;
199 Steps
= MaxRange
/ Range
->SteppingDelta
+ 1;
201 /* store mixer control info there */
202 VolumeData
->Header
.dwControlID
= MixerControl
->Control
.dwControlID
;
203 VolumeData
->SignedMaximum
= Range
->Bounds
.SignedMaximum
;
204 VolumeData
->SignedMinimum
= Range
->Bounds
.SignedMinimum
;
205 VolumeData
->SteppingDelta
= Range
->SteppingDelta
;
206 VolumeData
->ValuesCount
= Steps
;
207 VolumeData
->InputSteppingDelta
= 0x10000 / Steps
;
209 VolumeData
->Values
= (PLONG
)MixerContext
->Alloc(sizeof(LONG
) * Steps
);
210 if (!VolumeData
->Values
)
212 MixerContext
->Free(Desc
);
213 MixerContext
->Free(VolumeData
);
214 return MM_STATUS_NO_MEMORY
;
217 Value
= Range
->Bounds
.SignedMinimum
;
218 for(Index
= 0; Index
< Steps
; Index
++)
220 VolumeData
->Values
[Index
] = Value
;
221 Value
+= Range
->SteppingDelta
;
223 MixerControl
->ExtraData
= VolumeData
;
226 MixerContext
->Free(Desc
);
229 DPRINT("Status %x Name %S\n", Status
, MixerControl
->Control
.szName
);
230 return MM_STATUS_SUCCESS
;
234 MMixerCreateDestinationLine(
235 IN PMIXER_CONTEXT MixerContext
,
236 IN LPMIXER_INFO MixerInfo
,
237 IN ULONG bInputMixer
,
240 LPMIXERLINE_EXT DestinationLine
;
242 /* allocate a mixer destination line */
243 DestinationLine
= (LPMIXERLINE_EXT
) MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
247 return MM_STATUS_NO_MEMORY
;
250 /* initialize mixer destination line */
251 DestinationLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
252 DestinationLine
->Line
.cChannels
= 2; /* FIXME */
253 DestinationLine
->Line
.cConnections
= 0;
254 DestinationLine
->Line
.cControls
= 0;
255 DestinationLine
->Line
.dwComponentType
= (bInputMixer
== 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
);
256 DestinationLine
->Line
.dwDestination
= MixerInfo
->MixCaps
.cDestinations
;
257 DestinationLine
->Line
.dwLineID
= MixerInfo
->MixCaps
.cDestinations
+ DESTINATION_LINE
;
258 DestinationLine
->Line
.dwSource
= MAXULONG
;
259 DestinationLine
->Line
.dwUser
= 0;
260 DestinationLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
;
265 MixerContext
->Copy(DestinationLine
->Line
.szShortName
, LineName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
266 DestinationLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
268 MixerContext
->Copy(DestinationLine
->Line
.szName
, LineName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
269 DestinationLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
273 DestinationLine
->Line
.Target
.dwType
= (bInputMixer
== 0 ? MIXERLINE_TARGETTYPE_WAVEOUT
: MIXERLINE_TARGETTYPE_WAVEIN
);
274 DestinationLine
->Line
.Target
.dwDeviceID
= 0; //FIXME
275 DestinationLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
276 DestinationLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
277 DestinationLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
279 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == 0);
280 wcscpy(DestinationLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
282 /* initialize extra line */
283 InitializeListHead(&DestinationLine
->ControlsList
);
285 /* insert into mixer info */
286 InsertTailList(&MixerInfo
->LineList
, &DestinationLine
->Entry
);
288 /* increment destination count */
289 MixerInfo
->MixCaps
.cDestinations
++;
292 return MM_STATUS_SUCCESS
;
297 IN PMIXER_CONTEXT MixerContext
,
298 IN LPMIXER_INFO MixerInfo
,
301 IN OUT LPWSTR
* OutBuffer
)
311 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
312 Pin
.Property
.Set
= KSPROPSETID_Pin
;
313 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
315 /* try get pin name size */
316 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
318 /* check if buffer overflowed */
319 if (Status
== MM_STATUS_MORE_ENTRIES
)
321 /* allocate buffer */
322 Buffer
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
326 return MM_STATUS_NO_MEMORY
;
329 /* try get pin name */
330 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Buffer
, BytesReturned
, &BytesReturned
);
331 if (Status
!= MM_STATUS_SUCCESS
)
333 /* failed to get pin name */
334 MixerContext
->Free((PVOID
)Buffer
);
338 /* successfully obtained pin name */
340 return MM_STATUS_SUCCESS
;
343 /* failed to get pin name */
348 MMixerBuildMixerDestinationLine(
349 IN PMIXER_CONTEXT MixerContext
,
350 IN OUT LPMIXER_INFO MixerInfo
,
358 /* try get pin name */
359 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, hMixer
, PinId
, &PinName
);
360 if (Status
== MM_STATUS_SUCCESS
)
362 /* create mixer destination line */
364 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, PinName
);
367 MixerContext
->Free(PinName
);
371 /* create mixer destination line unlocalized */
372 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, L
"No Name");
380 IN PMIXER_CONTEXT MixerContext
,
381 IN LPMIXER_DATA MixerData
,
382 OUT PTOPOLOGY
* OutTopology
)
385 PKSMULTIPLE_ITEM NodeTypes
= NULL
;
386 PKSMULTIPLE_ITEM NodeConnections
= NULL
;
389 if (MixerData
->Topology
)
391 /* re-use existing topology */
392 *OutTopology
= MixerData
->Topology
;
394 return MM_STATUS_SUCCESS
;
397 /* get connected filter pin count */
398 PinsCount
= MMixerGetFilterPinCount(MixerContext
, MixerData
->hDevice
);
402 /* referenced filter does not have any pins */
403 return MM_STATUS_UNSUCCESSFUL
;
406 /* get topology node types */
407 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
408 if (Status
!= MM_STATUS_SUCCESS
)
410 /* failed to get topology node types */
414 /* get topology connections */
415 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
416 if (Status
!= MM_STATUS_SUCCESS
)
418 /* failed to get topology connections */
419 MixerContext
->Free(NodeTypes
);
423 /* create a topology */
424 Status
= MMixerCreateTopology(MixerContext
, PinsCount
, NodeConnections
, NodeTypes
, OutTopology
);
426 /* free node types & connections */
427 MixerContext
->Free(NodeConnections
);
428 MixerContext
->Free(NodeTypes
);
430 if (Status
== MM_STATUS_SUCCESS
)
432 /* store topology object */
433 MixerData
->Topology
= *OutTopology
;
441 MMixerCountMixerControls(
442 IN PMIXER_CONTEXT MixerContext
,
443 IN PTOPOLOGY Topology
,
445 IN ULONG bInputMixer
,
447 OUT PULONG OutNodesCount
,
449 OUT PULONG OutLineTerminator
)
452 ULONG NodesCount
, NodeIndex
, Count
, bTerminator
;
455 /* allocate an array to store all nodes which are upstream of this pin */
456 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
458 if (Status
!= MM_STATUS_SUCCESS
)
461 return STATUS_NO_MEMORY
;
464 /* mark result array as zero */
468 MMixerGetNextNodesFromPinIndex(MixerContext
, Topology
, PinId
, bUpStream
, &NodesCount
, Nodes
);
470 /* assume no topology split before getting line terminator */
471 ASSERT(NodesCount
== 1);
474 NodeIndex
= Nodes
[0];
479 /* check if the node is a terminator */
480 MMixerIsNodeTerminator(Topology
, NodeIndex
, &bTerminator
);
484 /* found terminator */
487 /* add mux source for source destination line */
488 OutNodes
[Count
] = NodeIndex
;
495 OutNodes
[Count
] = NodeIndex
;
497 /* increment node count */
500 /* get next nodes upstream */
501 MMixerGetNextNodesFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bUpStream
, &NodesCount
, Nodes
);
503 /* assume there is a node connected */
504 ASSERT(NodesCount
!= 0);
505 ASSERT(NodesCount
== 1);
507 /* use first index */
508 NodeIndex
= Nodes
[0];
512 /* free node index */
513 MixerContext
->Free(Nodes
);
515 /* store nodes count */
516 *OutNodesCount
= Count
;
518 /* store line terminator */
519 *OutLineTerminator
= NodeIndex
;
522 return MM_STATUS_SUCCESS
;
526 MMixerGetChannelCountEnhanced(
527 IN PMIXER_CONTEXT MixerContext
,
528 IN LPMIXER_INFO MixerInfo
,
531 OUT PULONG MaxChannels
)
533 KSPROPERTY_DESCRIPTION Description
;
534 PKSPROPERTY_DESCRIPTION NewDescription
;
535 PKSPROPERTY_MEMBERSHEADER Header
;
540 /* try #1 obtain it via description */
541 Request
.NodeId
= NodeId
;
542 Request
.Reserved
= 0;
543 Request
.Property
.Set
= KSPROPSETID_Audio
;
544 Request
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
| KSPROPERTY_TYPE_TOPOLOGY
;
545 Request
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
548 /* get description */
549 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_NODE
), (PVOID
)&Description
, sizeof(KSPROPERTY_DESCRIPTION
), &BytesReturned
);
550 if (Status
== MM_STATUS_SUCCESS
)
552 if (Description
.DescriptionSize
>= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) && (Description
.MembersListCount
> 0))
554 /* allocate new description */
555 NewDescription
= MixerContext
->Alloc(Description
.DescriptionSize
);
559 /* not enough memory */
560 return MM_STATUS_NO_MEMORY
;
563 /* get description */
564 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_NODE
), (PVOID
)NewDescription
, Description
.DescriptionSize
, &BytesReturned
);
565 if (Status
== MM_STATUS_SUCCESS
)
568 Header
= (PKSPROPERTY_MEMBERSHEADER
)(NewDescription
+ 1);
570 if (Header
->Flags
& KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL
)
572 /* found enhanced flag */
573 ASSERT(Header
->MembersCount
> 1);
575 /* store channel count */
576 *MaxChannels
= Header
->MembersCount
;
578 /* free description */
579 MixerContext
->Free(NewDescription
);
582 return MM_STATUS_SUCCESS
;
586 /* free description */
587 MixerContext
->Free(NewDescription
);
591 /* failed to get channel count enhanced */
592 return MM_STATUS_UNSUCCESSFUL
;
596 MMixerGetChannelCountLegacy(
597 IN PMIXER_CONTEXT MixerContext
,
598 IN LPMIXER_INFO MixerInfo
,
601 OUT PULONG MaxChannels
)
605 KSNODEPROPERTY_AUDIO_CHANNEL Channel
;
609 Channel
.Reserved
= 0;
610 Channel
.NodeProperty
.NodeId
= NodeId
;
611 Channel
.NodeProperty
.Reserved
= 0;
612 Channel
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_TOPOLOGY
;
613 Channel
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
615 Channel
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
619 /* get channel volume */
620 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Channel
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), (PVOID
)&Volume
, sizeof(LONG
), &BytesReturned
);
621 if (Status
!= MM_STATUS_SUCCESS
)
624 /* increment channel count */
629 /* store channel count */
630 *MaxChannels
= Channel
.Channel
;
635 MMixerGetMaxChannelsForNode(
636 IN PMIXER_CONTEXT MixerContext
,
637 IN LPMIXER_INFO MixerInfo
,
640 OUT PULONG MaxChannels
)
644 /* try to get it enhanced */
645 Status
= MMixerGetChannelCountEnhanced(MixerContext
, MixerInfo
, hMixer
, NodeId
, MaxChannels
);
647 if (Status
!= MM_STATUS_SUCCESS
)
649 /* get it old-fashioned way */
650 MMixerGetChannelCountLegacy(MixerContext
, MixerInfo
, hMixer
, NodeId
, MaxChannels
);
655 MMixerAddMixerControlsToMixerLineByNodeIndexArray(
656 IN PMIXER_CONTEXT MixerContext
,
657 IN LPMIXER_INFO MixerInfo
,
659 IN PTOPOLOGY Topology
,
660 IN OUT LPMIXERLINE_EXT DstLine
,
664 ULONG Index
, Count
, bReserved
;
669 /* initialize control count */
672 for(Index
= 0; Index
< NodesCount
; Index
++)
674 /* check if the node has already been reserved to a line */
675 MMixerIsTopologyNodeReserved(Topology
, Nodes
[Index
], &bReserved
);
679 /* node is already used, skip it */
683 /* set node status as used */
684 MMixerSetTopologyNodeReserved(Topology
, Nodes
[Index
]);
686 /* query node type */
687 NodeType
= MMixerGetNodeTypeFromTopology(Topology
, Nodes
[Index
]);
689 if (IsEqualGUIDAligned(NodeType
, &KSNODETYPE_VOLUME
))
691 /* calculate maximum channel count for node */
692 MMixerGetMaxChannelsForNode(MixerContext
, MixerInfo
, hMixer
, Nodes
[Index
], &MaxChannels
);
694 DPRINT("NodeId %lu MaxChannels %lu Line %S Id %lu\n", Nodes
[Index
], MaxChannels
, DstLine
->Line
.szName
, DstLine
->Line
.dwLineID
);
695 /* calculate maximum channels */
696 DstLine
->Line
.cChannels
= min(DstLine
->Line
.cChannels
, MaxChannels
);
699 /* now add the mixer control */
700 Status
= MMixerAddMixerControl(MixerContext
, MixerInfo
, hMixer
, Topology
, Nodes
[Index
], DstLine
);
702 if (Status
== MM_STATUS_SUCCESS
)
704 /* increment control count */
709 /* store control count */
710 DstLine
->Line
.cControls
= Count
;
713 return MM_STATUS_SUCCESS
;
717 MMixerGetComponentAndTargetType(
718 IN PMIXER_CONTEXT MixerContext
,
719 IN OUT LPMIXER_INFO MixerInfo
,
722 OUT PULONG ComponentType
,
723 OUT PULONG TargetType
)
725 KSPIN_DATAFLOW DataFlow
;
726 KSPIN_COMMUNICATION Communication
;
731 BOOLEAN BridgePin
= FALSE
;
732 PKSPIN_PHYSICALCONNECTION Connection
;
734 /* first dataflow type */
735 Status
= MMixerGetPinDataFlowAndCommunication(MixerContext
, hMixer
, PinId
, &DataFlow
, &Communication
);
737 if (Status
!= MM_STATUS_SUCCESS
)
739 /* failed to get dataflow */
743 /* now get pin category guid */
744 Request
.PinId
= PinId
;
745 Request
.Reserved
= 0;
746 Request
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
747 Request
.Property
.Set
= KSPROPSETID_Pin
;
748 Request
.Property
.Id
= KSPROPERTY_PIN_CATEGORY
;
751 /* get pin category */
752 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_PIN
), &Guid
, sizeof(GUID
), &BytesReturned
);
753 if (Status
!= MM_STATUS_SUCCESS
)
755 /* failed to get dataflow */
759 /* check if it has a physical connection */
760 Status
= MMixerGetPhysicalConnection(MixerContext
, hMixer
, PinId
, &Connection
);
761 if (Status
== MM_STATUS_SUCCESS
)
763 /* pin is a brige pin */
766 /* free physical connection */
767 MixerContext
->Free(Connection
);
770 if (DataFlow
== KSPIN_DATAFLOW_IN
)
772 if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_MICROPHONE
) ||
773 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DESKTOP_MICROPHONE
))
775 /* type microphone */
776 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
777 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
;
779 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_LEGACY_AUDIO_CONNECTOR
) ||
780 IsEqualGUIDAligned(&Guid
, &KSCATEGORY_AUDIO
) ||
781 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPEAKER
))
784 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
785 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT
;
787 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_CD_PLAYER
))
790 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
791 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC
;
793 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SYNTHESIZER
))
795 /* type synthesizer */
796 *TargetType
= MIXERLINE_TARGETTYPE_MIDIOUT
;
797 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER
;
799 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_LINE_CONNECTOR
))
802 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
803 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_LINE
;
805 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_TELEPHONE
) ||
806 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_PHONE_LINE
) ||
807 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DOWN_LINE_PHONE
))
810 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
811 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE
;
813 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ANALOG_CONNECTOR
))
817 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
819 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
821 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_ANALOG
;
823 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPDIF_INTERFACE
))
827 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
829 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
831 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_DIGITAL
;
836 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
837 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED
;
838 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId
, BridgePin
);
843 if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPEAKER
) ||
844 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DESKTOP_SPEAKER
) ||
845 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ROOM_SPEAKER
) ||
846 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_COMMUNICATION_SPEAKER
))
849 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
850 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
852 else if (IsEqualGUIDAligned(&Guid
, &KSCATEGORY_AUDIO
) ||
853 IsEqualGUIDAligned(&Guid
, &PINNAME_CAPTURE
))
856 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
857 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
859 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_HEADPHONES
) ||
860 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO
))
862 /* type head phones */
863 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
864 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_HEADPHONES
;
866 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_TELEPHONE
) ||
867 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_PHONE_LINE
) ||
868 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DOWN_LINE_PHONE
))
871 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
872 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_TELEPHONE
;
874 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ANALOG_CONNECTOR
))
879 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
880 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
884 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
885 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
888 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPDIF_INTERFACE
))
893 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
894 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
898 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
899 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
905 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
906 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
907 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId
, BridgePin
);
912 return MM_STATUS_SUCCESS
;
916 MMixerBuildMixerSourceLine(
917 IN PMIXER_CONTEXT MixerContext
,
918 IN OUT LPMIXER_INFO MixerInfo
,
920 IN PTOPOLOGY Topology
,
924 IN ULONG DestinationLineID
,
925 OUT LPMIXERLINE_EXT
* OutSrcLine
)
927 LPMIXERLINE_EXT SrcLine
, DstLine
;
930 ULONG ComponentType
, TargetType
;
932 /* get component and target type */
933 Status
= MMixerGetComponentAndTargetType(MixerContext
, MixerInfo
, hMixer
, PinId
, &ComponentType
, &TargetType
);
934 if (Status
!= MM_STATUS_SUCCESS
)
936 /* failed to get component status */
937 TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
938 ComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
941 /* construct source line */
942 SrcLine
= (LPMIXERLINE_EXT
)MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
947 return MM_STATUS_NO_MEMORY
;
950 /* get destination line */
951 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineID
);
954 /* initialize mixer src line */
955 SrcLine
->PinId
= PinId
;
957 /* initialize mixer line */
958 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
959 SrcLine
->Line
.dwDestination
= MixerInfo
->MixCaps
.cDestinations
-1;
960 SrcLine
->Line
.dwSource
= DstLine
->Line
.cConnections
;
961 SrcLine
->Line
.dwLineID
= (DstLine
->Line
.cConnections
* SOURCE_LINE
)+ (MixerInfo
->MixCaps
.cDestinations
-1);
962 SrcLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
| MIXERLINE_LINEF_SOURCE
;
963 SrcLine
->Line
.dwComponentType
= ComponentType
;
964 SrcLine
->Line
.dwUser
= 0;
965 SrcLine
->Line
.cChannels
= DstLine
->Line
.cChannels
;
966 SrcLine
->Line
.cConnections
= 0;
967 SrcLine
->Line
.Target
.dwType
= TargetType
;
968 SrcLine
->Line
.Target
.dwDeviceID
= DstLine
->Line
.Target
.dwDeviceID
;
969 SrcLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
970 SrcLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
971 SrcLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
972 InitializeListHead(&SrcLine
->ControlsList
);
975 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == L
'\0');
976 wcscpy(SrcLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
979 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, hMixer
, PinId
, &PinName
);
981 if (Status
== MM_STATUS_SUCCESS
)
983 /* store pin name as line name */
984 MixerContext
->Copy(SrcLine
->Line
.szShortName
, PinName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
985 SrcLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
987 MixerContext
->Copy(SrcLine
->Line
.szName
, PinName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
988 SrcLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
990 /* free pin name buffer */
991 MixerContext
->Free(PinName
);
994 /* add the controls to mixer line */
995 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, hMixer
, Topology
, SrcLine
, NodesCount
, Nodes
);
996 if (Status
!= MM_STATUS_SUCCESS
)
1003 *OutSrcLine
= SrcLine
;
1005 return MM_STATUS_SUCCESS
;
1009 MMixerAddMixerSourceLines(
1010 IN PMIXER_CONTEXT MixerContext
,
1011 IN OUT LPMIXER_INFO MixerInfo
,
1013 IN PTOPOLOGY Topology
,
1014 IN ULONG DestinationLineID
,
1015 IN ULONG LineTerminator
)
1017 PULONG AllNodes
, AllPins
, AllPinNodes
;
1018 ULONG AllNodesCount
, AllPinsCount
, AllPinNodesCount
;
1019 ULONG Index
, SubIndex
, PinId
, CurNode
, bConnected
;
1020 MIXER_STATUS Status
;
1021 LPMIXERLINE_EXT DstLine
, SrcLine
;
1023 /* get destination line */
1024 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineID
);
1027 /* allocate an array to store all nodes which are upstream of the line terminator */
1028 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllNodes
);
1030 /* check for success */
1031 if (Status
!= MM_STATUS_SUCCESS
)
1034 return MM_STATUS_NO_MEMORY
;
1037 /* allocate an array to store all nodes which are downstream of a particular pin */
1038 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllPinNodes
);
1040 /* allocate an array to store all pins which are upstream of this pin */
1041 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &AllPins
);
1043 /* check for success */
1044 if (Status
!= MM_STATUS_SUCCESS
)
1047 MixerContext
->Free(AllNodes
);
1048 return MM_STATUS_NO_MEMORY
;
1051 /* get all nodes which indirectly / directly connect to this node */
1053 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllNodesCount
, AllNodes
);
1055 /* get all pins which indirectly / directly connect to this node */
1057 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllPinsCount
, AllPins
);
1059 DPRINT("LineTerminator %lu\n", LineTerminator
);
1060 DPRINT("PinCount %lu\n", AllPinsCount
);
1061 DPRINT("AllNodesCount %lu\n", AllNodesCount
);
1063 /* now construct the source lines which are attached to the destination line */
1064 Index
= AllPinsCount
;
1068 /* get current pin id */
1069 PinId
= AllPins
[Index
- 1];
1071 /* reset nodes count */
1072 AllPinNodesCount
= 0;
1074 /* now scan all nodes and add them to AllPinNodes array when they are connected to this pin */
1075 for(SubIndex
= 0; SubIndex
< AllNodesCount
; SubIndex
++)
1077 /* get current node index */
1078 CurNode
= AllNodes
[SubIndex
];
1080 if (CurNode
!= MAXULONG
&& CurNode
!= LineTerminator
)
1082 /* check if that node is connected in some way to the current pin */
1083 Status
= MMixerIsNodeConnectedToPin(MixerContext
, Topology
, CurNode
, PinId
, TRUE
, &bConnected
);
1085 if (Status
!= MM_STATUS_SUCCESS
)
1090 /* it is connected */
1091 AllPinNodes
[AllPinNodesCount
] = CurNode
;
1094 /* clear current index */
1095 AllNodes
[SubIndex
] = MAXULONG
;
1100 /* decrement pin index */
1103 if (AllPinNodesCount
)
1108 /* now build the mixer source line */
1109 Status
= MMixerBuildMixerSourceLine(MixerContext
, MixerInfo
, hMixer
, Topology
, PinId
, AllPinNodesCount
, AllPinNodes
, DestinationLineID
, &SrcLine
);
1111 if (Status
== MM_STATUS_SUCCESS
)
1113 /* insert into line list */
1114 InsertTailList(&MixerInfo
->LineList
, &SrcLine
->Entry
);
1116 /* increment destination line count */
1117 DstLine
->Line
.cConnections
++;
1119 /* mark pin as reserved */
1120 MMixerSetTopologyPinReserved(Topology
, PinId
);
1123 DPRINT1("Adding PinId %lu AllPinNodesCount %lu to DestinationLine %lu\n", PinId
, AllPinNodesCount
, DestinationLineID
);
1124 for(TempIndex
= 0; TempIndex
< AllPinNodesCount
; TempIndex
++)
1125 DPRINT1("NodeIndex %lu\n", AllPinNodes
[TempIndex
]);
1132 DPRINT1("Discarding DestinationLineID %lu PinId %lu NO NODES!\n", DestinationLineID
, PinId
);
1138 return MM_STATUS_SUCCESS
;
1143 MMixerAddMixerControlsToDestinationLine(
1144 IN PMIXER_CONTEXT MixerContext
,
1145 IN OUT LPMIXER_INFO MixerInfo
,
1147 IN PTOPOLOGY Topology
,
1150 IN ULONG DestinationLineId
,
1151 OUT PULONG OutLineTerminator
)
1154 ULONG NodesCount
, LineTerminator
;
1155 MIXER_STATUS Status
;
1156 LPMIXERLINE_EXT DstLine
;
1158 /* allocate nodes index array */
1159 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
1161 /* check for success */
1162 if (Status
!= MM_STATUS_SUCCESS
)
1165 return MM_STATUS_NO_MEMORY
;
1168 /* get all destination line controls */
1169 Status
= MMixerCountMixerControls(MixerContext
, Topology
, PinId
, bInput
, TRUE
, &NodesCount
, Nodes
, &LineTerminator
);
1171 /* check for success */
1172 if (Status
!= MM_STATUS_SUCCESS
)
1174 /* failed to count controls */
1175 MixerContext
->Free(Nodes
);
1179 /* get destination mixer line */
1180 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineId
);
1187 /* add all nodes as mixer controls to the destination line */
1188 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, hMixer
, Topology
, DstLine
, NodesCount
, Nodes
);
1189 if (Status
!= MM_STATUS_SUCCESS
)
1191 /* failed to add controls */
1192 MixerContext
->Free(Nodes
);
1198 *OutLineTerminator
= LineTerminator
;
1205 MMixerApplyOutputFilterHack(
1206 IN PMIXER_CONTEXT MixerContext
,
1207 IN LPMIXER_DATA MixerData
,
1209 IN OUT PULONG PinsCount
,
1212 ULONG Count
= 0, Index
;
1213 MIXER_STATUS Status
;
1214 PKSPIN_PHYSICALCONNECTION Connection
;
1216 for(Index
= 0; Index
< *PinsCount
; Index
++)
1218 /* check if it has a physical connection */
1219 Status
= MMixerGetPhysicalConnection(MixerContext
, hMixer
, Pins
[Index
], &Connection
);
1221 if (Status
== MM_STATUS_SUCCESS
)
1224 MixerContext
->Copy(&Pins
[Index
], &Pins
[Index
+ 1], (*PinsCount
- (Index
+ 1)) * sizeof(ULONG
));
1226 /* free physical connection */
1227 MixerContext
->Free(Connection
);
1229 /* decrement index */
1232 /* decrement pin count */
1247 MMixerHandlePhysicalConnection(
1248 IN PMIXER_CONTEXT MixerContext
,
1249 IN PMIXER_LIST MixerList
,
1250 IN LPMIXER_DATA MixerData
,
1251 IN OUT LPMIXER_INFO MixerInfo
,
1253 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
1255 MIXER_STATUS Status
;
1256 ULONG PinsCount
, LineTerminator
, DestinationLineID
;
1260 /* first try to open the connected filter */
1261 OutConnection
->SymbolicLinkName
[1] = L
'\\';
1262 MixerData
= MMixerGetDataByDeviceName(MixerList
, OutConnection
->SymbolicLinkName
);
1264 /* check if the linked connection is found */
1267 /* filter references invalid physical connection */
1268 return MM_STATUS_UNSUCCESSFUL
;
1271 DPRINT("Name %S, Pin %lu bInput %lu\n", OutConnection
->SymbolicLinkName
, OutConnection
->Pin
, bInput
);
1274 ASSERT(MixerData
->MixerInfo
== NULL
|| MixerData
->MixerInfo
== MixerInfo
);
1276 /* associate with mixer */
1277 MixerData
->MixerInfo
= MixerInfo
;
1279 if (MixerData
->Topology
== NULL
)
1281 /* construct new topology */
1282 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1283 if (Status
!= MM_STATUS_SUCCESS
)
1285 /* failed to create topology */
1289 /* store topology */
1290 MixerData
->Topology
= Topology
;
1294 /* re-use existing topology */
1295 Topology
= MixerData
->Topology
;
1298 /* mark pin as consumed */
1299 MMixerSetTopologyPinReserved(Topology
, OutConnection
->Pin
);
1303 /* allocate pin index array which will hold all referenced pins */
1304 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1305 if (Status
!= MM_STATUS_SUCCESS
)
1307 /* failed to create topology */
1311 /* the mixer is an output mixer
1312 * find end pin of the node path
1315 Status
= MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext
, Topology
, OutConnection
->Pin
, FALSE
, &PinsCount
, Pins
);
1317 /* check for success */
1318 if (Status
!= MM_STATUS_SUCCESS
)
1320 /* failed to get end pin */
1321 MixerContext
->Free(Pins
);
1322 //MMixerFreeTopology(Topology);
1324 /* return error code */
1328 * some topologies do not have strict boundaries
1329 * WorkArround: remove all pin ids which have a physical connection
1330 * because bridge pins may belong to different render paths
1332 MMixerApplyOutputFilterHack(MixerContext
, MixerData
, MixerData
->hDevice
, &PinsCount
, Pins
);
1335 ASSERT(PinsCount
!= 0);
1336 ASSERT(PinsCount
== 1);
1338 /* create destination line */
1339 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Pins
[0], bInput
);
1341 /* calculate destination line id */
1342 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1344 if (Status
!= MM_STATUS_SUCCESS
)
1346 /* failed to build destination line */
1347 MixerContext
->Free(Pins
);
1349 /* return error code */
1353 /* add mixer controls to destination line */
1354 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, Pins
[0], bInput
, DestinationLineID
, &LineTerminator
);
1356 if (Status
== MM_STATUS_SUCCESS
)
1358 /* now add the rest of the source lines */
1359 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, DestinationLineID
, LineTerminator
);
1362 /* mark pin as consumed */
1363 MMixerSetTopologyPinReserved(Topology
, Pins
[0]);
1365 /* free topology pin array */
1366 MixerContext
->Free(Pins
);
1370 /* calculate destination line id */
1371 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1373 /* add mixer controls */
1374 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, OutConnection
->Pin
, bInput
, DestinationLineID
, &LineTerminator
);
1376 if (Status
== MM_STATUS_SUCCESS
)
1378 /* now add the rest of the source lines */
1379 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, DestinationLineID
, LineTerminator
);
1387 MMixerInitializeFilter(
1388 IN PMIXER_CONTEXT MixerContext
,
1389 IN PMIXER_LIST MixerList
,
1390 IN LPMIXER_DATA MixerData
,
1391 IN LPMIXER_INFO MixerInfo
,
1392 IN PTOPOLOGY Topology
,
1394 IN ULONG bInputMixer
,
1395 IN OUT LPMIXER_INFO
* OutMixerInfo
)
1398 MIXER_STATUS Status
;
1399 PKSPIN_PHYSICALCONNECTION OutConnection
;
1402 ULONG NewMixerInfo
= FALSE
;
1404 if (MixerInfo
== NULL
)
1406 /* allocate a mixer info struct */
1407 MixerInfo
= (LPMIXER_INFO
) MixerContext
->Alloc(sizeof(MIXER_INFO
));
1411 return MM_STATUS_NO_MEMORY
;
1414 /* new mixer info */
1415 NewMixerInfo
= TRUE
;
1417 /* intialize mixer caps */
1418 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; /* FIXME */
1419 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; /* FIXME */
1420 MixerInfo
->MixCaps
.vDriverVersion
= 1; /* FIXME */
1421 MixerInfo
->MixCaps
.fdwSupport
= 0;
1422 MixerInfo
->MixCaps
.cDestinations
= 0;
1424 /* get mixer name */
1425 MMixerGetDeviceName(MixerContext
, MixerInfo
->MixCaps
.szPname
, MixerData
->hDeviceInterfaceKey
);
1427 /* initialize line list */
1428 InitializeListHead(&MixerInfo
->LineList
);
1429 InitializeListHead(&MixerInfo
->EventList
);
1431 /* associate with mixer data */
1432 MixerData
->MixerInfo
= MixerInfo
;
1435 /* store mixer info */
1436 *OutMixerInfo
= MixerInfo
;
1438 /* now allocate an array which will receive the indices of the pin
1439 * which has a ADC / DAC nodetype in its path
1441 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1442 ASSERT(Status
== MM_STATUS_SUCCESS
);
1446 /* now get all sink / source pins, which are attached to the ADC / DAC node
1447 * For sink pins (wave out) search up stream
1448 * For source pins (wave in) search down stream
1449 * The search direction is always the opposite of the current mixer type
1452 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, !bInputMixer
, &PinsFound
, Pins
);
1454 /* if there is no pin found, we have a broken topology */
1455 ASSERT(PinsFound
!= 0);
1457 /* now create a wave info struct */
1458 Status
= MMixerInitializeWaveInfo(MixerContext
, MixerList
, MixerData
, MixerInfo
->MixCaps
.szPname
, bInputMixer
, PinsFound
, Pins
);
1459 if (Status
!= MM_STATUS_SUCCESS
)
1461 /* failed to create wave info struct */
1462 MixerContext
->Free(MixerInfo
);
1463 MixerContext
->Free(Pins
);
1467 /* mark all found pins as reserved */
1468 for(Index
= 0; Index
< PinsFound
; Index
++)
1470 MMixerSetTopologyPinReserved(Topology
, Pins
[Index
]);
1475 /* pre create the mixer destination line for input mixers */
1476 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Pins
[0], bInputMixer
);
1478 if (Status
!= MM_STATUS_SUCCESS
)
1480 /* failed to create mixer destination line */
1486 /* now get the bridge pin which is at the end of node path
1487 * For sink pins (wave out) search down stream
1488 * For source pins (wave in) search up stream
1490 MixerContext
->Free(Pins
);
1491 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1492 ASSERT(Status
== MM_STATUS_SUCCESS
);
1495 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bInputMixer
, &PinsFound
, Pins
);
1497 /* if there is no pin found, we have a broken topology */
1498 ASSERT(PinsFound
!= 0);
1500 /* there should be exactly one bridge pin */
1501 ASSERT(PinsFound
== 1);
1503 DPRINT("BridgePin %lu bInputMixer %lu\n", Pins
[0], bInputMixer
);
1505 /* does the pin have a physical connection */
1506 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Pins
[0], &OutConnection
);
1508 if (Status
== MM_STATUS_SUCCESS
)
1510 /* mark pin as reserved */
1511 MMixerSetTopologyPinReserved(Topology
, Pins
[0]);
1513 /* topology on the topoloy filter */
1514 Status
= MMixerHandlePhysicalConnection(MixerContext
, MixerList
, MixerData
, MixerInfo
, bInputMixer
, OutConnection
);
1516 /* free physical connection data */
1517 MixerContext
->Free(OutConnection
);
1522 * handle drivers which expose their topology on the same filter
1528 MixerContext
->Free(Pins
);
1533 InsertHeadList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1534 /* increment mixer count */
1535 MixerList
->MixerListCount
++;
1543 MMixerHandleAlternativeMixers(
1544 IN PMIXER_CONTEXT MixerContext
,
1545 IN PMIXER_LIST MixerList
,
1546 IN LPMIXER_DATA MixerData
,
1547 IN PTOPOLOGY Topology
)
1549 ULONG Index
, PinCount
, Reserved
;
1550 MIXER_STATUS Status
;
1551 ULONG DestinationLineID
, LineTerminator
;
1552 LPMIXERLINE_EXT DstLine
;
1554 DPRINT("DeviceName %S\n", MixerData
->DeviceName
);
1556 /* get topology pin count */
1557 MMixerGetTopologyPinCount(Topology
, &PinCount
);
1559 for(Index
= 0; Index
< PinCount
; Index
++)
1561 MMixerIsTopologyPinReserved(Topology
, Index
, &Reserved
);
1563 /* check if it has already been reserved */
1564 if (Reserved
== TRUE
)
1566 /* pin has already been reserved */
1570 DPRINT("MixerName %S Available PinID %lu\n", MixerData
->DeviceName
, Index
);
1573 //ASSERT(MixerData->MixerInfo);
1575 if (!MixerData
->MixerInfo
)
1577 DPRINT1("Expected mixer info\n");
1581 /* build the destination line */
1582 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerData
->MixerInfo
, MixerData
->hDevice
, Index
, TRUE
);
1583 if (Status
!= MM_STATUS_SUCCESS
)
1585 /* failed to build destination line */
1589 /* calculate destination line id */
1590 DestinationLineID
= (DESTINATION_LINE
+ MixerData
->MixerInfo
->MixCaps
.cDestinations
-1);
1592 /* add mixer controls to destination line */
1593 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerData
->MixerInfo
, MixerData
->hDevice
, MixerData
->Topology
, Index
, TRUE
, DestinationLineID
, &LineTerminator
);
1594 if (Status
== MM_STATUS_SUCCESS
)
1596 /* now add the rest of the source lines */
1597 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerData
->MixerInfo
, MixerData
->hDevice
, MixerData
->Topology
, DestinationLineID
, LineTerminator
);
1600 /* mark pin as consumed */
1601 MMixerSetTopologyPinReserved(Topology
, Index
);
1603 /* now grab destination line */
1604 DstLine
= MMixerGetSourceMixerLineByLineId(MixerData
->MixerInfo
, DestinationLineID
);
1606 /* set type and target as undefined */
1607 DstLine
->Line
.dwComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
1608 DstLine
->Line
.Target
.dwType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
1609 DstLine
->Line
.Target
.vDriverVersion
= 0;
1610 DstLine
->Line
.Target
.wMid
= 0;
1611 DstLine
->Line
.Target
.wPid
= 0;
1617 IN PMIXER_CONTEXT MixerContext
,
1618 IN PMIXER_LIST MixerList
,
1619 IN LPMIXER_DATA MixerData
,
1620 IN PULONG DeviceCount
)
1622 MIXER_STATUS Status
;
1625 LPMIXER_INFO MixerInfo
= NULL
;
1627 /* check if topology has already been built */
1628 if (MixerData
->Topology
== NULL
)
1630 /* build topology */
1631 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1633 if (Status
!= MM_STATUS_SUCCESS
)
1635 /* failed to build topology */
1639 /* store topology */
1640 MixerData
->Topology
= Topology
;
1644 /* re-use topology */
1645 Topology
= MixerData
->Topology
;
1648 /* check if the filter has an wave out node */
1649 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_DAC
);
1650 if (NodeIndex
!= MAXULONG
)
1653 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, NULL
, Topology
, NodeIndex
, FALSE
, &MixerInfo
);
1655 /* check for success */
1656 if (Status
== MM_STATUS_SUCCESS
)
1658 /* increment mixer count */
1663 /* reset mixer info in case of error */
1668 /* check if the filter has an wave in node */
1669 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_ADC
);
1670 if (NodeIndex
!= MAXULONG
)
1673 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, MixerInfo
, Topology
, NodeIndex
, TRUE
, &MixerInfo
);
1675 /* check for success */
1676 if (Status
== MM_STATUS_SUCCESS
)
1678 /* increment mixer count */
1684 /* TODO: apply hacks for Wave source line */
1686 /* activate midi devices */
1687 //MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology);
1696 IN PMIXER_CONTEXT MixerContext
,
1697 IN OUT LPMIXER_INFO MixerInfo
,
1698 IN PVOID MixerEventContext
,
1699 IN PMIXER_EVENT MixerEventRoutine
)
1701 //KSE_NODE Property;
1702 PEVENT_NOTIFICATION_ENTRY EventData
;
1703 //ULONG BytesReturned;
1704 //MIXER_STATUS Status;
1706 EventData
= (PEVENT_NOTIFICATION_ENTRY
)MixerContext
->AllocEventData(sizeof(EVENT_NOTIFICATION_ENTRY
));
1709 /* not enough memory */
1710 return MM_STATUS_NO_MEMORY
;
1715 Property
.Event
.Set
= KSEVENTSETID_AudioControlChange
;
1716 Property
.Event
.Flags
= KSEVENT_TYPE_TOPOLOGY
|KSEVENT_TYPE_ENABLE
;
1717 Property
.Event
.Id
= KSEVENT_CONTROL_CHANGE
;
1719 Property
.NodeId
= NodeId
;
1720 Property
.Reserved
= 0;
1722 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSP_NODE
), (PVOID
)EventData
, sizeof(KSEVENTDATA
), &BytesReturned
);
1723 if (Status
!= MM_STATUS_SUCCESS
)
1725 /* failed to add event */
1726 MixerContext
->FreeEventData(EventData
);
1731 /* initialize notification entry */
1732 EventData
->MixerEventContext
= MixerEventContext
;
1733 EventData
->MixerEventRoutine
= MixerEventRoutine
;
1736 InsertTailList(&MixerInfo
->EventList
, &EventData
->Entry
);
1737 return MM_STATUS_SUCCESS
;