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
.dwSource
= MAXULONG
;
253 DestinationLine
->Line
.dwLineID
= MixerInfo
->MixCaps
.cDestinations
+ DESTINATION_LINE
;
254 DestinationLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
;
255 DestinationLine
->Line
.dwUser
= 0;
256 DestinationLine
->Line
.dwDestination
= MixerInfo
->MixCaps
.cDestinations
;
257 DestinationLine
->Line
.dwComponentType
= (bInputMixer
== 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
);
258 DestinationLine
->Line
.cChannels
= 2; /* FIXME */
262 MixerContext
->Copy(DestinationLine
->Line
.szShortName
, LineName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
263 DestinationLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
265 MixerContext
->Copy(DestinationLine
->Line
.szName
, LineName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
266 DestinationLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
270 DestinationLine
->Line
.Target
.dwType
= (bInputMixer
== 0 ? MIXERLINE_TARGETTYPE_WAVEOUT
: MIXERLINE_TARGETTYPE_WAVEIN
);
271 DestinationLine
->Line
.Target
.dwDeviceID
= 0; //FIXME
272 DestinationLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
273 DestinationLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
274 DestinationLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
276 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == 0);
277 wcscpy(DestinationLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
279 /* initialize extra line */
280 InitializeListHead(&DestinationLine
->ControlsList
);
282 /* insert into mixer info */
283 InsertTailList(&MixerInfo
->LineList
, &DestinationLine
->Entry
);
285 /* increment destination count */
286 MixerInfo
->MixCaps
.cDestinations
++;
289 return MM_STATUS_SUCCESS
;
294 IN PMIXER_CONTEXT MixerContext
,
295 IN LPMIXER_INFO MixerInfo
,
298 IN OUT LPWSTR
* OutBuffer
)
308 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
309 Pin
.Property
.Set
= KSPROPSETID_Pin
;
310 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
312 /* try get pin name size */
313 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
315 /* check if buffer overflowed */
316 if (Status
== MM_STATUS_MORE_ENTRIES
)
318 /* allocate buffer */
319 Buffer
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
323 return MM_STATUS_NO_MEMORY
;
326 /* try get pin name */
327 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Buffer
, BytesReturned
, &BytesReturned
);
328 if (Status
!= MM_STATUS_SUCCESS
)
330 /* failed to get pin name */
331 MixerContext
->Free((PVOID
)Buffer
);
335 /* successfully obtained pin name */
337 return MM_STATUS_SUCCESS
;
340 /* failed to get pin name */
345 MMixerBuildMixerDestinationLine(
346 IN PMIXER_CONTEXT MixerContext
,
347 IN OUT LPMIXER_INFO MixerInfo
,
355 /* try get pin name */
356 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, hMixer
, PinId
, &PinName
);
357 if (Status
== MM_STATUS_SUCCESS
)
359 /* create mixer destination line */
361 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, PinName
);
364 MixerContext
->Free(PinName
);
368 /* create mixer destination line unlocalized */
369 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, L
"No Name");
377 IN PMIXER_CONTEXT MixerContext
,
378 IN LPMIXER_DATA MixerData
,
379 OUT PTOPOLOGY
* OutTopology
)
382 PKSMULTIPLE_ITEM NodeTypes
= NULL
;
383 PKSMULTIPLE_ITEM NodeConnections
= NULL
;
386 if (MixerData
->Topology
)
388 /* re-use existing topology */
389 *OutTopology
= MixerData
->Topology
;
391 return MM_STATUS_SUCCESS
;
394 /* get connected filter pin count */
395 PinsCount
= MMixerGetFilterPinCount(MixerContext
, MixerData
->hDevice
);
399 /* referenced filter does not have any pins */
400 return MM_STATUS_UNSUCCESSFUL
;
403 /* get topology node types */
404 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
405 if (Status
!= MM_STATUS_SUCCESS
)
407 /* failed to get topology node types */
411 /* get topology connections */
412 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
413 if (Status
!= MM_STATUS_SUCCESS
)
415 /* failed to get topology connections */
416 MixerContext
->Free(NodeTypes
);
420 /* create a topology */
421 Status
= MMixerCreateTopology(MixerContext
, PinsCount
, NodeConnections
, NodeTypes
, OutTopology
);
423 /* free node types & connections */
424 MixerContext
->Free(NodeConnections
);
425 MixerContext
->Free(NodeTypes
);
427 if (Status
== MM_STATUS_SUCCESS
)
429 /* store topology object */
430 MixerData
->Topology
= *OutTopology
;
438 MMixerCountMixerControls(
439 IN PMIXER_CONTEXT MixerContext
,
440 IN PTOPOLOGY Topology
,
442 IN ULONG bInputMixer
,
444 OUT PULONG OutNodesCount
,
446 OUT PULONG OutLineTerminator
)
449 ULONG NodesCount
, NodeIndex
, Count
, bTerminator
;
452 /* allocate an array to store all nodes which are upstream of this pin */
453 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
455 if (Status
!= MM_STATUS_SUCCESS
)
458 return STATUS_NO_MEMORY
;
461 /* mark result array as zero */
465 MMixerGetNextNodesFromPinIndex(MixerContext
, Topology
, PinId
, bUpStream
, &NodesCount
, Nodes
);
467 /* assume no topology split before getting line terminator */
468 ASSERT(NodesCount
== 1);
471 NodeIndex
= Nodes
[0];
476 /* check if the node is a terminator */
477 MMixerIsNodeTerminator(Topology
, NodeIndex
, &bTerminator
);
481 /* found terminator */
484 /* add mux source for source destination line */
485 OutNodes
[Count
] = NodeIndex
;
492 OutNodes
[Count
] = NodeIndex
;
494 /* increment node count */
497 /* get next nodes upstream */
498 MMixerGetNextNodesFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bUpStream
, &NodesCount
, Nodes
);
500 /* assume there is a node connected */
501 ASSERT(NodesCount
!= 0);
502 ASSERT(NodesCount
== 1);
504 /* use first index */
505 NodeIndex
= Nodes
[0];
509 /* free node index */
510 MixerContext
->Free(Nodes
);
512 /* store nodes count */
513 *OutNodesCount
= Count
;
515 /* store line terminator */
516 *OutLineTerminator
= NodeIndex
;
519 return MM_STATUS_SUCCESS
;
523 MMixerGetChannelCountEnhanced(
524 IN PMIXER_CONTEXT MixerContext
,
525 IN LPMIXER_INFO MixerInfo
,
528 OUT PULONG MaxChannels
)
530 KSPROPERTY_DESCRIPTION Description
;
531 PKSPROPERTY_DESCRIPTION NewDescription
;
532 PKSPROPERTY_MEMBERSHEADER Header
;
537 /* try #1 obtain it via description */
538 Request
.NodeId
= NodeId
;
539 Request
.Reserved
= 0;
540 Request
.Property
.Set
= KSPROPSETID_Audio
;
541 Request
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
| KSPROPERTY_TYPE_TOPOLOGY
;
542 Request
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
545 /* get description */
546 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_NODE
), (PVOID
)&Description
, sizeof(KSPROPERTY_DESCRIPTION
), &BytesReturned
);
547 if (Status
== MM_STATUS_SUCCESS
)
549 if (Description
.DescriptionSize
>= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) && (Description
.MembersListCount
> 0))
551 /* allocate new description */
552 NewDescription
= MixerContext
->Alloc(Description
.DescriptionSize
);
556 /* not enough memory */
557 return MM_STATUS_NO_MEMORY
;
560 /* get description */
561 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_NODE
), (PVOID
)NewDescription
, Description
.DescriptionSize
, &BytesReturned
);
562 if (Status
== MM_STATUS_SUCCESS
)
565 Header
= (PKSPROPERTY_MEMBERSHEADER
)(NewDescription
+ 1);
567 if (Header
->Flags
& KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL
)
569 /* found enhanced flag */
570 ASSERT(Header
->MembersCount
> 1);
572 /* store channel count */
573 *MaxChannels
= Header
->MembersCount
;
575 /* free description */
576 MixerContext
->Free(NewDescription
);
579 return MM_STATUS_SUCCESS
;
583 /* free description */
584 MixerContext
->Free(NewDescription
);
588 /* failed to get channel count enhanced */
589 return MM_STATUS_UNSUCCESSFUL
;
593 MMixerGetChannelCountLegacy(
594 IN PMIXER_CONTEXT MixerContext
,
595 IN LPMIXER_INFO MixerInfo
,
598 OUT PULONG MaxChannels
)
602 KSNODEPROPERTY_AUDIO_CHANNEL Channel
;
606 Channel
.Reserved
= 0;
607 Channel
.NodeProperty
.NodeId
= NodeId
;
608 Channel
.NodeProperty
.Reserved
= 0;
609 Channel
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_TOPOLOGY
;
610 Channel
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
612 Channel
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
616 /* get channel volume */
617 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Channel
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), (PVOID
)&Volume
, sizeof(LONG
), &BytesReturned
);
618 if (Status
!= MM_STATUS_SUCCESS
)
621 /* increment channel count */
626 /* store channel count */
627 *MaxChannels
= Channel
.Channel
;
632 MMixerGetMaxChannelsForNode(
633 IN PMIXER_CONTEXT MixerContext
,
634 IN LPMIXER_INFO MixerInfo
,
637 OUT PULONG MaxChannels
)
641 /* try to get it enhanced */
642 Status
= MMixerGetChannelCountEnhanced(MixerContext
, MixerInfo
, hMixer
, NodeId
, MaxChannels
);
644 if (Status
!= MM_STATUS_SUCCESS
)
646 /* get it old-fashioned way */
647 MMixerGetChannelCountLegacy(MixerContext
, MixerInfo
, hMixer
, NodeId
, MaxChannels
);
652 MMixerAddMixerControlsToMixerLineByNodeIndexArray(
653 IN PMIXER_CONTEXT MixerContext
,
654 IN LPMIXER_INFO MixerInfo
,
656 IN PTOPOLOGY Topology
,
657 IN OUT LPMIXERLINE_EXT DstLine
,
661 ULONG Index
, Count
, bReserved
;
666 /* initialize control count */
669 for(Index
= 0; Index
< NodesCount
; Index
++)
671 /* check if the node has already been reserved to a line */
672 MMixerIsTopologyNodeReserved(Topology
, Nodes
[Index
], &bReserved
);
676 /* node is already used, skip it */
680 /* set node status as used */
681 MMixerSetTopologyNodeReserved(Topology
, Nodes
[Index
]);
683 /* query node type */
684 NodeType
= MMixerGetNodeTypeFromTopology(Topology
, Nodes
[Index
]);
686 if (IsEqualGUIDAligned(NodeType
, &KSNODETYPE_VOLUME
))
688 /* calculate maximum channel count for node */
689 MMixerGetMaxChannelsForNode(MixerContext
, MixerInfo
, hMixer
, Nodes
[Index
], &MaxChannels
);
691 DPRINT("NodeId %lu MaxChannels %lu Line %S Id %lu\n", Nodes
[Index
], MaxChannels
, DstLine
->Line
.szName
, DstLine
->Line
.dwLineID
);
692 /* calculate maximum channels */
693 DstLine
->Line
.cChannels
= min(DstLine
->Line
.cChannels
, MaxChannels
);
696 /* now add the mixer control */
697 Status
= MMixerAddMixerControl(MixerContext
, MixerInfo
, hMixer
, Topology
, Nodes
[Index
], DstLine
);
699 if (Status
== MM_STATUS_SUCCESS
)
701 /* increment control count */
706 /* store control count */
707 DstLine
->Line
.cControls
= Count
;
710 return MM_STATUS_SUCCESS
;
714 MMixerGetComponentAndTargetType(
715 IN PMIXER_CONTEXT MixerContext
,
716 IN OUT LPMIXER_INFO MixerInfo
,
719 OUT PULONG ComponentType
,
720 OUT PULONG TargetType
)
722 KSPIN_DATAFLOW DataFlow
;
723 KSPIN_COMMUNICATION Communication
;
728 BOOLEAN BridgePin
= FALSE
;
729 PKSPIN_PHYSICALCONNECTION Connection
;
731 /* first dataflow type */
732 Status
= MMixerGetPinDataFlowAndCommunication(MixerContext
, hMixer
, PinId
, &DataFlow
, &Communication
);
734 if (Status
!= MM_STATUS_SUCCESS
)
736 /* failed to get dataflow */
740 /* now get pin category guid */
741 Request
.PinId
= PinId
;
742 Request
.Reserved
= 0;
743 Request
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
744 Request
.Property
.Set
= KSPROPSETID_Pin
;
745 Request
.Property
.Id
= KSPROPERTY_PIN_CATEGORY
;
748 /* get pin category */
749 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_PIN
), &Guid
, sizeof(GUID
), &BytesReturned
);
750 if (Status
!= MM_STATUS_SUCCESS
)
752 /* failed to get dataflow */
756 /* check if it has a physical connection */
757 Status
= MMixerGetPhysicalConnection(MixerContext
, hMixer
, PinId
, &Connection
);
758 if (Status
== MM_STATUS_SUCCESS
)
760 /* pin is a brige pin */
763 /* free physical connection */
764 MixerContext
->Free(Connection
);
767 if (DataFlow
== KSPIN_DATAFLOW_IN
)
769 if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_MICROPHONE
) ||
770 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DESKTOP_MICROPHONE
))
772 /* type microphone */
773 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
774 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
;
776 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_LEGACY_AUDIO_CONNECTOR
) ||
777 IsEqualGUIDAligned(&Guid
, &KSCATEGORY_AUDIO
) ||
778 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPEAKER
))
781 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
782 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT
;
784 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_CD_PLAYER
))
787 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
788 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC
;
790 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SYNTHESIZER
))
792 /* type synthesizer */
793 *TargetType
= MIXERLINE_TARGETTYPE_MIDIOUT
;
794 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER
;
796 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_LINE_CONNECTOR
))
799 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
800 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_LINE
;
802 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_TELEPHONE
) ||
803 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_PHONE_LINE
) ||
804 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DOWN_LINE_PHONE
))
807 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
808 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE
;
810 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ANALOG_CONNECTOR
))
814 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
816 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
818 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_ANALOG
;
820 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPDIF_INTERFACE
))
824 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
826 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
828 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_DIGITAL
;
833 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
834 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED
;
835 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId
, BridgePin
);
840 if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPEAKER
) ||
841 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DESKTOP_SPEAKER
) ||
842 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ROOM_SPEAKER
) ||
843 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_COMMUNICATION_SPEAKER
))
846 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
847 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
849 else if (IsEqualGUIDAligned(&Guid
, &KSCATEGORY_AUDIO
) ||
850 IsEqualGUIDAligned(&Guid
, &PINNAME_CAPTURE
))
853 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
854 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
856 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_HEADPHONES
) ||
857 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO
))
859 /* type head phones */
860 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
861 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_HEADPHONES
;
863 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_TELEPHONE
) ||
864 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_PHONE_LINE
) ||
865 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DOWN_LINE_PHONE
))
868 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
869 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_TELEPHONE
;
871 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ANALOG_CONNECTOR
))
876 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
877 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
881 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
882 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
885 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPDIF_INTERFACE
))
890 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
891 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
895 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
896 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
902 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
903 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
904 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId
, BridgePin
);
909 return MM_STATUS_SUCCESS
;
913 MMixerBuildMixerSourceLine(
914 IN PMIXER_CONTEXT MixerContext
,
915 IN OUT LPMIXER_INFO MixerInfo
,
917 IN PTOPOLOGY Topology
,
921 IN ULONG DestinationLineID
,
922 OUT LPMIXERLINE_EXT
* OutSrcLine
)
924 LPMIXERLINE_EXT SrcLine
, DstLine
;
927 ULONG ComponentType
, TargetType
;
929 /* get component and target type */
930 Status
= MMixerGetComponentAndTargetType(MixerContext
, MixerInfo
, hMixer
, PinId
, &ComponentType
, &TargetType
);
931 if (Status
!= MM_STATUS_SUCCESS
)
933 /* failed to get component status */
934 TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
935 ComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
938 /* construct source line */
939 SrcLine
= (LPMIXERLINE_EXT
)MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
944 return MM_STATUS_NO_MEMORY
;
947 /* get destination line */
948 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineID
);
951 /* initialize mixer src line */
952 SrcLine
->PinId
= PinId
;
954 /* initialize mixer line */
955 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
956 SrcLine
->Line
.dwDestination
= MixerInfo
->MixCaps
.cDestinations
-1;
957 SrcLine
->Line
.dwSource
= DstLine
->Line
.cConnections
;
958 SrcLine
->Line
.dwLineID
= (DstLine
->Line
.cConnections
* SOURCE_LINE
)+ (MixerInfo
->MixCaps
.cDestinations
-1);
959 SrcLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
| MIXERLINE_LINEF_SOURCE
;
960 SrcLine
->Line
.dwComponentType
= ComponentType
;
961 SrcLine
->Line
.dwUser
= 0;
962 SrcLine
->Line
.cChannels
= DstLine
->Line
.cChannels
;
963 SrcLine
->Line
.cConnections
= 0;
964 SrcLine
->Line
.Target
.dwType
= TargetType
;
965 SrcLine
->Line
.Target
.dwDeviceID
= DstLine
->Line
.Target
.dwDeviceID
;
966 SrcLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
967 SrcLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
968 SrcLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
969 InitializeListHead(&SrcLine
->ControlsList
);
972 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == L
'\0');
973 wcscpy(SrcLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
976 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, hMixer
, PinId
, &PinName
);
978 if (Status
== MM_STATUS_SUCCESS
)
980 /* store pin name as line name */
981 MixerContext
->Copy(SrcLine
->Line
.szShortName
, PinName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
982 SrcLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
984 MixerContext
->Copy(SrcLine
->Line
.szName
, PinName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
985 SrcLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
987 /* free pin name buffer */
988 MixerContext
->Free(PinName
);
991 /* add the controls to mixer line */
992 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, hMixer
, Topology
, SrcLine
, NodesCount
, Nodes
);
993 if (Status
!= MM_STATUS_SUCCESS
)
1000 *OutSrcLine
= SrcLine
;
1002 return MM_STATUS_SUCCESS
;
1006 MMixerAddMixerSourceLines(
1007 IN PMIXER_CONTEXT MixerContext
,
1008 IN OUT LPMIXER_INFO MixerInfo
,
1010 IN PTOPOLOGY Topology
,
1011 IN ULONG DestinationLineID
,
1012 IN ULONG LineTerminator
)
1014 PULONG AllNodes
, AllPins
, AllPinNodes
;
1015 ULONG AllNodesCount
, AllPinsCount
, AllPinNodesCount
;
1016 ULONG Index
, SubIndex
, PinId
, CurNode
, bConnected
;
1017 MIXER_STATUS Status
;
1018 LPMIXERLINE_EXT DstLine
, SrcLine
;
1020 /* get destination line */
1021 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineID
);
1024 /* allocate an array to store all nodes which are upstream of the line terminator */
1025 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllNodes
);
1027 /* check for success */
1028 if (Status
!= MM_STATUS_SUCCESS
)
1031 return MM_STATUS_NO_MEMORY
;
1034 /* allocate an array to store all nodes which are downstream of a particular pin */
1035 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllPinNodes
);
1037 /* allocate an array to store all pins which are upstream of this pin */
1038 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &AllPins
);
1040 /* check for success */
1041 if (Status
!= MM_STATUS_SUCCESS
)
1044 MixerContext
->Free(AllNodes
);
1045 return MM_STATUS_NO_MEMORY
;
1048 /* get all nodes which indirectly / directly connect to this node */
1050 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllNodesCount
, AllNodes
);
1052 /* get all pins which indirectly / directly connect to this node */
1054 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllPinsCount
, AllPins
);
1056 DPRINT1("LineTerminator %lu\n", LineTerminator
);
1057 DPRINT1("PinCount %lu\n", AllPinsCount
);
1058 DPRINT1("AllNodesCount %lu\n", AllNodesCount
);
1060 /* now construct the source lines which are attached to the destination line */
1061 Index
= AllPinsCount
;
1065 /* get current pin id */
1066 PinId
= AllPins
[Index
- 1];
1068 /* reset nodes count */
1069 AllPinNodesCount
= 0;
1071 /* now scan all nodes and add them to AllPinNodes array when they are connected to this pin */
1072 for(SubIndex
= 0; SubIndex
< AllNodesCount
; SubIndex
++)
1074 /* get current node index */
1075 CurNode
= AllNodes
[SubIndex
];
1077 if (CurNode
!= MAXULONG
&& CurNode
!= LineTerminator
)
1079 /* check if that node is connected in some way to the current pin */
1080 Status
= MMixerIsNodeConnectedToPin(MixerContext
, Topology
, CurNode
, PinId
, TRUE
, &bConnected
);
1082 if (Status
!= MM_STATUS_SUCCESS
)
1087 /* it is connected */
1088 AllPinNodes
[AllPinNodesCount
] = CurNode
;
1091 /* clear current index */
1092 AllNodes
[SubIndex
] = MAXULONG
;
1097 /* decrement pin index */
1100 if (AllPinNodesCount
)
1105 /* now build the mixer source line */
1106 Status
= MMixerBuildMixerSourceLine(MixerContext
, MixerInfo
, hMixer
, Topology
, PinId
, AllPinNodesCount
, AllPinNodes
, DestinationLineID
, &SrcLine
);
1108 if (Status
== MM_STATUS_SUCCESS
)
1110 /* insert into line list */
1111 InsertTailList(&MixerInfo
->LineList
, &SrcLine
->Entry
);
1113 /* increment destination line count */
1114 DstLine
->Line
.cConnections
++;
1116 /* mark pin as reserved */
1117 MMixerSetTopologyPinReserved(Topology
, PinId
);
1120 DPRINT1("Adding PinId %lu AllPinNodesCount %lu to DestinationLine %lu\n", PinId
, AllPinNodesCount
, DestinationLineID
);
1121 for(TempIndex
= 0; TempIndex
< AllPinNodesCount
; TempIndex
++)
1122 DPRINT1("NodeIndex %lu\n", AllPinNodes
[TempIndex
]);
1129 DPRINT1("Discarding DestinationLineID %lu PinId %lu NO NODES!\n", DestinationLineID
, PinId
);
1135 return MM_STATUS_SUCCESS
;
1140 MMixerAddMixerControlsToDestinationLine(
1141 IN PMIXER_CONTEXT MixerContext
,
1142 IN OUT LPMIXER_INFO MixerInfo
,
1144 IN PTOPOLOGY Topology
,
1147 IN ULONG DestinationLineId
,
1148 OUT PULONG OutLineTerminator
)
1151 ULONG NodesCount
, LineTerminator
;
1152 MIXER_STATUS Status
;
1153 LPMIXERLINE_EXT DstLine
;
1155 /* allocate nodes index array */
1156 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
1158 /* check for success */
1159 if (Status
!= MM_STATUS_SUCCESS
)
1162 return MM_STATUS_NO_MEMORY
;
1165 /* get all destination line controls */
1166 Status
= MMixerCountMixerControls(MixerContext
, Topology
, PinId
, bInput
, TRUE
, &NodesCount
, Nodes
, &LineTerminator
);
1168 /* check for success */
1169 if (Status
!= MM_STATUS_SUCCESS
)
1171 /* failed to count controls */
1172 MixerContext
->Free(Nodes
);
1176 /* get destination mixer line */
1177 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineId
);
1184 /* add all nodes as mixer controls to the destination line */
1185 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, hMixer
, Topology
, DstLine
, NodesCount
, Nodes
);
1186 if (Status
!= MM_STATUS_SUCCESS
)
1188 /* failed to add controls */
1189 MixerContext
->Free(Nodes
);
1195 *OutLineTerminator
= LineTerminator
;
1202 MMixerApplyOutputFilterHack(
1203 IN PMIXER_CONTEXT MixerContext
,
1204 IN LPMIXER_DATA MixerData
,
1206 IN OUT PULONG PinsCount
,
1209 ULONG Count
= 0, Index
;
1210 MIXER_STATUS Status
;
1211 PKSPIN_PHYSICALCONNECTION Connection
;
1213 for(Index
= 0; Index
< *PinsCount
; Index
++)
1215 /* check if it has a physical connection */
1216 Status
= MMixerGetPhysicalConnection(MixerContext
, hMixer
, Pins
[Index
], &Connection
);
1218 if (Status
== MM_STATUS_SUCCESS
)
1221 MixerContext
->Copy(&Pins
[Index
], &Pins
[Index
+ 1], (*PinsCount
- (Index
+ 1)) * sizeof(ULONG
));
1223 /* free physical connection */
1224 MixerContext
->Free(Connection
);
1226 /* decrement index */
1229 /* decrement pin count */
1244 MMixerHandlePhysicalConnection(
1245 IN PMIXER_CONTEXT MixerContext
,
1246 IN PMIXER_LIST MixerList
,
1247 IN LPMIXER_DATA MixerData
,
1248 IN OUT LPMIXER_INFO MixerInfo
,
1250 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
1252 MIXER_STATUS Status
;
1253 ULONG PinsCount
, LineTerminator
, DestinationLineID
;
1257 /* first try to open the connected filter */
1258 OutConnection
->SymbolicLinkName
[1] = L
'\\';
1259 MixerData
= MMixerGetDataByDeviceName(MixerList
, OutConnection
->SymbolicLinkName
);
1261 /* check if the linked connection is found */
1264 /* filter references invalid physical connection */
1265 return MM_STATUS_UNSUCCESSFUL
;
1268 DPRINT1("Name %S, Pin %lu bInput %lu\n", OutConnection
->SymbolicLinkName
, OutConnection
->Pin
, bInput
);
1270 if (MixerData
->Topology
== NULL
)
1272 /* construct new topology */
1273 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1274 if (Status
!= MM_STATUS_SUCCESS
)
1276 /* failed to create topology */
1280 /* store topology */
1281 MixerData
->Topology
= Topology
;
1285 /* re-use existing topology */
1286 Topology
= MixerData
->Topology
;
1289 /* mark pin as consumed */
1290 MMixerSetTopologyPinReserved(Topology
, OutConnection
->Pin
);
1294 /* allocate pin index array which will hold all referenced pins */
1295 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1296 if (Status
!= MM_STATUS_SUCCESS
)
1298 /* failed to create topology */
1302 /* the mixer is an output mixer
1303 * find end pin of the node path
1306 Status
= MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext
, Topology
, OutConnection
->Pin
, FALSE
, &PinsCount
, Pins
);
1308 /* check for success */
1309 if (Status
!= MM_STATUS_SUCCESS
)
1311 /* failed to get end pin */
1312 MixerContext
->Free(Pins
);
1313 //MMixerFreeTopology(Topology);
1315 /* return error code */
1319 * some topologies do not have strict boundaries
1320 * WorkArround: remove all pin ids which have a physical connection
1321 * because bridge pins may belong to different render paths
1323 MMixerApplyOutputFilterHack(MixerContext
, MixerData
, MixerData
->hDevice
, &PinsCount
, Pins
);
1326 ASSERT(PinsCount
!= 0);
1327 ASSERT(PinsCount
== 1);
1329 /* create destination line */
1330 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Pins
[0], bInput
);
1332 /* calculate destination line id */
1333 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1335 if (Status
!= MM_STATUS_SUCCESS
)
1337 /* failed to build destination line */
1338 MixerContext
->Free(Pins
);
1340 /* return error code */
1344 /* add mixer controls to destination line */
1345 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, Pins
[0], bInput
, DestinationLineID
, &LineTerminator
);
1347 if (Status
== MM_STATUS_SUCCESS
)
1349 /* now add the rest of the source lines */
1350 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, DestinationLineID
, LineTerminator
);
1353 /* mark pin as consumed */
1354 MMixerSetTopologyPinReserved(Topology
, Pins
[0]);
1356 /* free topology pin array */
1357 MixerContext
->Free(Pins
);
1361 /* calculate destination line id */
1362 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1364 /* add mixer controls */
1365 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, OutConnection
->Pin
, bInput
, DestinationLineID
, &LineTerminator
);
1367 if (Status
== MM_STATUS_SUCCESS
)
1369 /* now add the rest of the source lines */
1370 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, DestinationLineID
, LineTerminator
);
1378 MMixerInitializeFilter(
1379 IN PMIXER_CONTEXT MixerContext
,
1380 IN PMIXER_LIST MixerList
,
1381 IN LPMIXER_DATA MixerData
,
1382 IN LPMIXER_INFO MixerInfo
,
1383 IN PTOPOLOGY Topology
,
1385 IN ULONG bInputMixer
,
1386 IN OUT LPMIXER_INFO
* OutMixerInfo
)
1389 MIXER_STATUS Status
;
1390 PKSPIN_PHYSICALCONNECTION OutConnection
;
1393 ULONG NewMixerInfo
= FALSE
;
1395 if (MixerInfo
== NULL
)
1397 /* allocate a mixer info struct */
1398 MixerInfo
= (LPMIXER_INFO
) MixerContext
->Alloc(sizeof(MIXER_INFO
));
1402 return MM_STATUS_NO_MEMORY
;
1405 /* new mixer info */
1406 NewMixerInfo
= TRUE
;
1408 /* intialize mixer caps */
1409 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; /* FIXME */
1410 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; /* FIXME */
1411 MixerInfo
->MixCaps
.vDriverVersion
= 1; /* FIXME */
1412 MixerInfo
->MixCaps
.fdwSupport
= 0;
1413 MixerInfo
->MixCaps
.cDestinations
= 0;
1415 /* get mixer name */
1416 MMixerGetDeviceName(MixerContext
, MixerInfo
->MixCaps
.szPname
, MixerData
->hDeviceInterfaceKey
);
1418 /* initialize line list */
1419 InitializeListHead(&MixerInfo
->LineList
);
1420 InitializeListHead(&MixerInfo
->EventList
);
1423 /* store mixer info */
1424 *OutMixerInfo
= MixerInfo
;
1426 /* now allocate an array which will receive the indices of the pin
1427 * which has a ADC / DAC nodetype in its path
1429 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1430 ASSERT(Status
== MM_STATUS_SUCCESS
);
1434 /* now get all sink / source pins, which are attached to the ADC / DAC node
1435 * For sink pins (wave out) search up stream
1436 * For source pins (wave in) search down stream
1437 * The search direction is always the opposite of the current mixer type
1440 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, !bInputMixer
, &PinsFound
, Pins
);
1442 /* if there is no pin found, we have a broken topology */
1443 ASSERT(PinsFound
!= 0);
1445 /* now create a wave info struct */
1446 Status
= MMixerInitializeWaveInfo(MixerContext
, MixerList
, MixerData
, MixerInfo
->MixCaps
.szPname
, bInputMixer
, PinsFound
, Pins
);
1447 if (Status
!= MM_STATUS_SUCCESS
)
1449 /* failed to create wave info struct */
1450 MixerContext
->Free(MixerInfo
);
1451 MixerContext
->Free(Pins
);
1455 /* mark all found pins as reserved */
1456 for(Index
= 0; Index
< PinsFound
; Index
++)
1458 MMixerSetTopologyPinReserved(Topology
, Pins
[Index
]);
1463 /* pre create the mixer destination line for input mixers */
1464 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Pins
[0], bInputMixer
);
1466 if (Status
!= MM_STATUS_SUCCESS
)
1468 /* failed to create mixer destination line */
1474 /* now get the bridge pin which is at the end of node path
1475 * For sink pins (wave out) search down stream
1476 * For source pins (wave in) search up stream
1478 MixerContext
->Free(Pins
);
1479 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1480 ASSERT(Status
== MM_STATUS_SUCCESS
);
1483 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bInputMixer
, &PinsFound
, Pins
);
1485 /* if there is no pin found, we have a broken topology */
1486 ASSERT(PinsFound
!= 0);
1488 /* there should be exactly one bridge pin */
1489 ASSERT(PinsFound
== 1);
1491 DPRINT("BridgePin %lu bInputMixer %lu\n", Pins
[0], bInputMixer
);
1493 /* does the pin have a physical connection */
1494 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Pins
[0], &OutConnection
);
1496 if (Status
== MM_STATUS_SUCCESS
)
1498 /* mark pin as reserved */
1499 MMixerSetTopologyPinReserved(Topology
, Pins
[0]);
1501 /* topology on the topoloy filter */
1502 Status
= MMixerHandlePhysicalConnection(MixerContext
, MixerList
, MixerData
, MixerInfo
, bInputMixer
, OutConnection
);
1504 /* free physical connection data */
1505 MixerContext
->Free(OutConnection
);
1510 * handle drivers which expose their topology on the same filter
1516 MixerContext
->Free(Pins
);
1521 InsertHeadList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1522 /* increment mixer count */
1523 MixerList
->MixerListCount
++;
1531 MMixerHandleAlternativeMixers(
1532 IN PMIXER_CONTEXT MixerContext
,
1533 IN PMIXER_LIST MixerList
,
1534 IN LPMIXER_DATA MixerData
,
1535 IN PTOPOLOGY Topology
)
1537 ULONG Index
, PinCount
, Reserved
;
1539 DPRINT1("DeviceName %S\n", MixerData
->DeviceName
);
1541 /* get topology pin count */
1542 MMixerGetTopologyPinCount(Topology
, &PinCount
);
1544 for(Index
= 0; Index
< PinCount
; Index
++)
1546 MMixerIsTopologyPinReserved(Topology
, Index
, &Reserved
);
1548 /* check if it has already been reserved */
1549 if (Reserved
== FALSE
)
1551 DPRINT1("MixerName %S Available PinID %lu\n", MixerData
->DeviceName
, Index
);
1558 IN PMIXER_CONTEXT MixerContext
,
1559 IN PMIXER_LIST MixerList
,
1560 IN LPMIXER_DATA MixerData
,
1561 IN PULONG DeviceCount
)
1563 MIXER_STATUS Status
;
1566 LPMIXER_INFO MixerInfo
= NULL
;
1568 /* check if topology has already been built */
1569 if (MixerData
->Topology
== NULL
)
1571 /* build topology */
1572 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1574 if (Status
!= MM_STATUS_SUCCESS
)
1576 /* failed to build topology */
1580 /* store topology */
1581 MixerData
->Topology
= Topology
;
1585 /* re-use topology */
1586 Topology
= MixerData
->Topology
;
1589 /* check if the filter has an wave out node */
1590 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_DAC
);
1591 if (NodeIndex
!= MAXULONG
)
1594 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, NULL
, Topology
, NodeIndex
, FALSE
, &MixerInfo
);
1596 /* check for success */
1597 if (Status
== MM_STATUS_SUCCESS
)
1599 /* increment mixer count */
1604 /* reset mixer info in case of error */
1609 /* check if the filter has an wave in node */
1610 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_ADC
);
1611 if (NodeIndex
!= MAXULONG
)
1614 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, MixerInfo
, Topology
, NodeIndex
, TRUE
, &MixerInfo
);
1616 /* check for success */
1617 if (Status
== MM_STATUS_SUCCESS
)
1619 /* increment mixer count */
1625 /* TODO: apply hacks for Wave source line */
1627 /* activate midi devices */
1628 MMixerInitializeMidiForFilter(MixerContext
, MixerList
, MixerData
, Topology
);
1637 IN PMIXER_CONTEXT MixerContext
,
1638 IN OUT LPMIXER_INFO MixerInfo
,
1639 IN PVOID MixerEventContext
,
1640 IN PMIXER_EVENT MixerEventRoutine
)
1642 //KSE_NODE Property;
1643 PEVENT_NOTIFICATION_ENTRY EventData
;
1644 //ULONG BytesReturned;
1645 //MIXER_STATUS Status;
1647 EventData
= (PEVENT_NOTIFICATION_ENTRY
)MixerContext
->AllocEventData(sizeof(EVENT_NOTIFICATION_ENTRY
));
1650 /* not enough memory */
1651 return MM_STATUS_NO_MEMORY
;
1656 Property
.Event
.Set
= KSEVENTSETID_AudioControlChange
;
1657 Property
.Event
.Flags
= KSEVENT_TYPE_TOPOLOGY
|KSEVENT_TYPE_ENABLE
;
1658 Property
.Event
.Id
= KSEVENT_CONTROL_CHANGE
;
1660 Property
.NodeId
= NodeId
;
1661 Property
.Reserved
= 0;
1663 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSP_NODE
), (PVOID
)EventData
, sizeof(KSEVENTDATA
), &BytesReturned
);
1664 if (Status
!= MM_STATUS_SUCCESS
)
1666 /* failed to add event */
1667 MixerContext
->FreeEventData(EventData
);
1672 /* initialize notification entry */
1673 EventData
->MixerEventContext
= MixerEventContext
;
1674 EventData
->MixerEventRoutine
;
1677 InsertTailList(&MixerInfo
->EventList
, &EventData
->Entry
);
1678 return MM_STATUS_SUCCESS
;