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
,
46 LPMIXERCONTROL_EXT MixerControl
;
48 /* allocate mixer control */
49 MixerControl
= MixerContext
->Alloc(sizeof(MIXERCONTROL_EXT
));
53 return MM_STATUS_NO_MEMORY
;
57 /* initialize mixer control */
58 MixerControl
->hDevice
= hMixer
;
59 MixerControl
->NodeID
= NodeIndex
;
60 MixerControl
->ExtraData
= NULL
;
62 MixerControl
->Control
.cbStruct
= sizeof(MIXERCONTROLW
);
63 MixerControl
->Control
.dwControlID
= MixerInfo
->ControlId
;
66 NodeType
= MMixerGetNodeTypeFromTopology(Topology
, NodeIndex
);
67 /* store control type */
68 MixerControl
->Control
.dwControlType
= MMixerGetControlTypeFromTopologyNode(NodeType
);
70 MixerControl
->Control
.fdwControl
= (MaxChannels
> 1 ? 0 : MIXERCONTROL_CONTROLF_UNIFORM
);
71 MixerControl
->Control
.cMultipleItems
= 0;
73 /* setup request to retrieve name */
74 Node
.NodeId
= NodeIndex
;
75 Node
.Property
.Id
= KSPROPERTY_TOPOLOGY_NAME
;
76 Node
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
77 Node
.Property
.Set
= KSPROPSETID_Topology
;
80 /* get node name size */
81 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), NULL
, 0, &BytesReturned
);
83 if (Status
== MM_STATUS_MORE_ENTRIES
)
85 ASSERT(BytesReturned
!= 0);
86 Name
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
89 /* not enough memory */
90 return MM_STATUS_NO_MEMORY
;
94 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), (LPVOID
)Name
, BytesReturned
, &BytesReturned
);
96 if (Status
== MM_STATUS_SUCCESS
)
98 MixerContext
->Copy(MixerControl
->Control
.szShortName
, Name
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
99 MixerControl
->Control
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
101 MixerContext
->Copy(MixerControl
->Control
.szName
, Name
, (min(MIXER_LONG_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
102 MixerControl
->Control
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
105 /* free name buffer */
106 MixerContext
->Free(Name
);
109 /* increment control count */
110 MixerInfo
->ControlId
++;
113 InsertTailList(&MixerLine
->ControlsList
, &MixerControl
->Entry
);
115 if (MixerControl
->Control
.dwControlType
== MIXERCONTROL_CONTROLTYPE_MUX
)
120 /* allocate topology nodes array */
121 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
123 if (Status
!= MM_STATUS_SUCCESS
)
126 return STATUS_NO_MEMORY
;
129 /* get connected node count */
130 MMixerGetNextNodesFromNodeIndex(MixerContext
, Topology
, NodeIndex
, TRUE
, &NodesCount
, Nodes
);
133 MixerContext
->Free(Nodes
);
135 /* setup mux bounds */
136 MixerControl
->Control
.Bounds
.dwMinimum
= 0;
137 MixerControl
->Control
.Bounds
.dwMaximum
= NodesCount
- 1;
138 MixerControl
->Control
.Metrics
.dwReserved
[0] = NodesCount
;
139 MixerControl
->Control
.cMultipleItems
= NodesCount
;
140 MixerControl
->Control
.fdwControl
|= MIXERCONTROL_CONTROLF_UNIFORM
| MIXERCONTROL_CONTROLF_MULTIPLE
;
142 else if (MixerControl
->Control
.dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
144 MixerControl
->Control
.Bounds
.dwMinimum
= 0;
145 MixerControl
->Control
.Bounds
.dwMaximum
= 1;
147 else if (MixerControl
->Control
.dwControlType
== MIXERCONTROL_CONTROLTYPE_ONOFF
)
149 /* only needs to set bounds */
150 MixerControl
->Control
.Bounds
.dwMinimum
= 0;
151 MixerControl
->Control
.Bounds
.dwMaximum
= 1;
153 else if (MixerControl
->Control
.dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
155 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
157 PKSPROPERTY_DESCRIPTION Desc
;
158 PKSPROPERTY_MEMBERSHEADER Members
;
159 PKSPROPERTY_STEPPING_LONG Range
;
161 MixerControl
->Control
.Bounds
.dwMinimum
= 0;
162 MixerControl
->Control
.Bounds
.dwMaximum
= 0xFFFF;
163 MixerControl
->Control
.Metrics
.cSteps
= 0xC0; /* FIXME */
165 Length
= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) + sizeof(KSPROPERTY_STEPPING_LONG
);
166 Desc
= (PKSPROPERTY_DESCRIPTION
)MixerContext
->Alloc(Length
);
169 /* setup the request */
170 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
172 Property
.NodeProperty
.NodeId
= NodeIndex
;
173 Property
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
174 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
| KSPROPERTY_TYPE_TOPOLOGY
;
175 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
177 /* get node volume level info */
178 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), Desc
, Length
, &BytesReturned
);
180 if (Status
== MM_STATUS_SUCCESS
)
182 LPMIXERVOLUME_DATA VolumeData
;
183 ULONG Steps
, MaxRange
, Index
;
186 Members
= (PKSPROPERTY_MEMBERSHEADER
)(Desc
+ 1);
187 Range
= (PKSPROPERTY_STEPPING_LONG
)(Members
+ 1);
189 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
);
191 MaxRange
= Range
->Bounds
.UnsignedMaximum
- Range
->Bounds
.UnsignedMinimum
;
196 VolumeData
= (LPMIXERVOLUME_DATA
)MixerContext
->Alloc(sizeof(MIXERVOLUME_DATA
));
198 return MM_STATUS_NO_MEMORY
;
200 Steps
= MaxRange
/ Range
->SteppingDelta
+ 1;
202 /* store mixer control info there */
203 VolumeData
->Header
.dwControlID
= MixerControl
->Control
.dwControlID
;
204 VolumeData
->SignedMaximum
= Range
->Bounds
.SignedMaximum
;
205 VolumeData
->SignedMinimum
= Range
->Bounds
.SignedMinimum
;
206 VolumeData
->SteppingDelta
= Range
->SteppingDelta
;
207 VolumeData
->ValuesCount
= Steps
;
208 VolumeData
->InputSteppingDelta
= 0x10000 / Steps
;
210 VolumeData
->Values
= (PLONG
)MixerContext
->Alloc(sizeof(LONG
) * Steps
);
211 if (!VolumeData
->Values
)
213 MixerContext
->Free(Desc
);
214 MixerContext
->Free(VolumeData
);
215 return MM_STATUS_NO_MEMORY
;
218 Value
= Range
->Bounds
.SignedMinimum
;
219 for(Index
= 0; Index
< Steps
; Index
++)
221 VolumeData
->Values
[Index
] = Value
;
222 Value
+= Range
->SteppingDelta
;
224 MixerControl
->ExtraData
= VolumeData
;
227 MixerContext
->Free(Desc
);
230 DPRINT("Status %x Name %S\n", Status
, MixerControl
->Control
.szName
);
231 return MM_STATUS_SUCCESS
;
235 MMixerCreateDestinationLine(
236 IN PMIXER_CONTEXT MixerContext
,
237 IN LPMIXER_INFO MixerInfo
,
238 IN ULONG bInputMixer
,
241 LPMIXERLINE_EXT DestinationLine
;
243 /* allocate a mixer destination line */
244 DestinationLine
= (LPMIXERLINE_EXT
) MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
248 return MM_STATUS_NO_MEMORY
;
251 /* initialize mixer destination line */
252 DestinationLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
253 DestinationLine
->Line
.cChannels
= 2; /* FIXME */
254 DestinationLine
->Line
.cConnections
= 0;
255 DestinationLine
->Line
.cControls
= 0;
256 DestinationLine
->Line
.dwComponentType
= (bInputMixer
== 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
);
257 DestinationLine
->Line
.dwDestination
= MixerInfo
->MixCaps
.cDestinations
;
258 DestinationLine
->Line
.dwLineID
= MixerInfo
->MixCaps
.cDestinations
+ DESTINATION_LINE
;
259 DestinationLine
->Line
.dwSource
= MAXULONG
;
260 DestinationLine
->Line
.dwUser
= 0;
261 DestinationLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
;
266 MixerContext
->Copy(DestinationLine
->Line
.szShortName
, LineName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
267 DestinationLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
269 MixerContext
->Copy(DestinationLine
->Line
.szName
, LineName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
270 DestinationLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
274 DestinationLine
->Line
.Target
.dwType
= (bInputMixer
== 0 ? MIXERLINE_TARGETTYPE_WAVEOUT
: MIXERLINE_TARGETTYPE_WAVEIN
);
275 DestinationLine
->Line
.Target
.dwDeviceID
= 0; //FIXME
276 DestinationLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
277 DestinationLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
278 DestinationLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
280 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == 0);
281 wcscpy(DestinationLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
283 /* initialize extra line */
284 InitializeListHead(&DestinationLine
->ControlsList
);
286 /* insert into mixer info */
287 InsertTailList(&MixerInfo
->LineList
, &DestinationLine
->Entry
);
289 /* increment destination count */
290 MixerInfo
->MixCaps
.cDestinations
++;
293 return MM_STATUS_SUCCESS
;
298 IN PMIXER_CONTEXT MixerContext
,
299 IN LPMIXER_INFO MixerInfo
,
302 IN OUT LPWSTR
* OutBuffer
)
312 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
313 Pin
.Property
.Set
= KSPROPSETID_Pin
;
314 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
316 /* try get pin name size */
317 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
319 /* check if buffer overflowed */
320 if (Status
== MM_STATUS_MORE_ENTRIES
)
322 /* allocate buffer */
323 Buffer
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
327 return MM_STATUS_NO_MEMORY
;
330 /* try get pin name */
331 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Buffer
, BytesReturned
, &BytesReturned
);
332 if (Status
!= MM_STATUS_SUCCESS
)
334 /* failed to get pin name */
335 MixerContext
->Free((PVOID
)Buffer
);
339 /* successfully obtained pin name */
341 return MM_STATUS_SUCCESS
;
344 /* failed to get pin name */
349 MMixerBuildMixerDestinationLine(
350 IN PMIXER_CONTEXT MixerContext
,
351 IN OUT LPMIXER_INFO MixerInfo
,
359 /* try get pin name */
360 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, hMixer
, PinId
, &PinName
);
361 if (Status
== MM_STATUS_SUCCESS
)
363 /* create mixer destination line */
365 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, PinName
);
368 MixerContext
->Free(PinName
);
372 /* create mixer destination line unlocalized */
373 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, L
"No Name");
381 IN PMIXER_CONTEXT MixerContext
,
382 IN LPMIXER_DATA MixerData
,
383 OUT PTOPOLOGY
* OutTopology
)
386 PKSMULTIPLE_ITEM NodeTypes
= NULL
;
387 PKSMULTIPLE_ITEM NodeConnections
= NULL
;
390 if (MixerData
->Topology
)
392 /* re-use existing topology */
393 *OutTopology
= MixerData
->Topology
;
395 return MM_STATUS_SUCCESS
;
398 /* get connected filter pin count */
399 PinsCount
= MMixerGetFilterPinCount(MixerContext
, MixerData
->hDevice
);
403 /* referenced filter does not have any pins */
404 return MM_STATUS_UNSUCCESSFUL
;
407 /* get topology node types */
408 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
409 if (Status
!= MM_STATUS_SUCCESS
)
411 /* failed to get topology node types */
415 /* get topology connections */
416 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
417 if (Status
!= MM_STATUS_SUCCESS
)
419 /* failed to get topology connections */
420 MixerContext
->Free(NodeTypes
);
424 /* create a topology */
425 Status
= MMixerCreateTopology(MixerContext
, PinsCount
, NodeConnections
, NodeTypes
, OutTopology
);
427 /* free node types & connections */
428 MixerContext
->Free(NodeConnections
);
429 MixerContext
->Free(NodeTypes
);
431 if (Status
== MM_STATUS_SUCCESS
)
433 /* store topology object */
434 MixerData
->Topology
= *OutTopology
;
442 MMixerCountMixerControls(
443 IN PMIXER_CONTEXT MixerContext
,
444 IN PTOPOLOGY Topology
,
446 IN ULONG bInputMixer
,
448 OUT PULONG OutNodesCount
,
450 OUT PULONG OutLineTerminator
)
453 ULONG NodesCount
, NodeIndex
, Count
, bTerminator
;
456 /* allocate an array to store all nodes which are upstream of this pin */
457 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
459 if (Status
!= MM_STATUS_SUCCESS
)
462 return STATUS_NO_MEMORY
;
465 /* mark result array as zero */
469 MMixerGetNextNodesFromPinIndex(MixerContext
, Topology
, PinId
, bUpStream
, &NodesCount
, Nodes
);
471 /* assume no topology split before getting line terminator */
472 ASSERT(NodesCount
== 1);
475 NodeIndex
= Nodes
[0];
480 /* check if the node is a terminator */
481 MMixerIsNodeTerminator(Topology
, NodeIndex
, &bTerminator
);
485 /* found terminator */
488 /* add mux source for source destination line */
489 OutNodes
[Count
] = NodeIndex
;
496 OutNodes
[Count
] = NodeIndex
;
498 /* increment node count */
501 /* get next nodes upstream */
502 MMixerGetNextNodesFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bUpStream
, &NodesCount
, Nodes
);
504 /* assume there is a node connected */
505 ASSERT(NodesCount
!= 0);
506 ASSERT(NodesCount
== 1);
508 /* use first index */
509 NodeIndex
= Nodes
[0];
513 /* free node index */
514 MixerContext
->Free(Nodes
);
516 /* store nodes count */
517 *OutNodesCount
= Count
;
519 /* store line terminator */
520 *OutLineTerminator
= NodeIndex
;
523 return MM_STATUS_SUCCESS
;
527 MMixerGetChannelCountEnhanced(
528 IN PMIXER_CONTEXT MixerContext
,
529 IN LPMIXER_INFO MixerInfo
,
532 OUT PULONG MaxChannels
)
534 KSPROPERTY_DESCRIPTION Description
;
535 PKSPROPERTY_DESCRIPTION NewDescription
;
536 PKSPROPERTY_MEMBERSHEADER Header
;
541 /* try #1 obtain it via description */
542 Request
.NodeId
= NodeId
;
543 Request
.Reserved
= 0;
544 Request
.Property
.Set
= KSPROPSETID_Audio
;
545 Request
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
| KSPROPERTY_TYPE_TOPOLOGY
;
546 Request
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
549 /* get description */
550 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_NODE
), (PVOID
)&Description
, sizeof(KSPROPERTY_DESCRIPTION
), &BytesReturned
);
551 if (Status
== MM_STATUS_SUCCESS
)
553 if (Description
.DescriptionSize
>= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) && (Description
.MembersListCount
> 0))
555 /* allocate new description */
556 NewDescription
= MixerContext
->Alloc(Description
.DescriptionSize
);
560 /* not enough memory */
561 return MM_STATUS_NO_MEMORY
;
564 /* get description */
565 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_NODE
), (PVOID
)NewDescription
, Description
.DescriptionSize
, &BytesReturned
);
566 if (Status
== MM_STATUS_SUCCESS
)
569 Header
= (PKSPROPERTY_MEMBERSHEADER
)(NewDescription
+ 1);
571 if (Header
->Flags
& KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL
)
573 /* found enhanced flag */
574 ASSERT(Header
->MembersCount
> 1);
576 /* store channel count */
577 *MaxChannels
= Header
->MembersCount
;
579 /* free description */
580 MixerContext
->Free(NewDescription
);
583 return MM_STATUS_SUCCESS
;
587 /* free description */
588 MixerContext
->Free(NewDescription
);
592 /* failed to get channel count enhanced */
593 return MM_STATUS_UNSUCCESSFUL
;
597 MMixerGetChannelCountLegacy(
598 IN PMIXER_CONTEXT MixerContext
,
599 IN LPMIXER_INFO MixerInfo
,
602 OUT PULONG MaxChannels
)
606 KSNODEPROPERTY_AUDIO_CHANNEL Channel
;
610 Channel
.Reserved
= 0;
611 Channel
.NodeProperty
.NodeId
= NodeId
;
612 Channel
.NodeProperty
.Reserved
= 0;
613 Channel
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_TOPOLOGY
;
614 Channel
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
616 Channel
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
620 /* get channel volume */
621 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Channel
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), (PVOID
)&Volume
, sizeof(LONG
), &BytesReturned
);
622 if (Status
!= MM_STATUS_SUCCESS
)
625 /* increment channel count */
630 /* store channel count */
631 *MaxChannels
= Channel
.Channel
;
636 MMixerGetMaxChannelsForNode(
637 IN PMIXER_CONTEXT MixerContext
,
638 IN LPMIXER_INFO MixerInfo
,
641 OUT PULONG MaxChannels
)
645 /* try to get it enhanced */
646 Status
= MMixerGetChannelCountEnhanced(MixerContext
, MixerInfo
, hMixer
, NodeId
, MaxChannels
);
648 if (Status
!= MM_STATUS_SUCCESS
)
650 /* get it old-fashioned way */
651 MMixerGetChannelCountLegacy(MixerContext
, MixerInfo
, hMixer
, NodeId
, MaxChannels
);
656 MMixerAddMixerControlsToMixerLineByNodeIndexArray(
657 IN PMIXER_CONTEXT MixerContext
,
658 IN LPMIXER_INFO MixerInfo
,
660 IN PTOPOLOGY Topology
,
661 IN OUT LPMIXERLINE_EXT DstLine
,
665 ULONG Index
, Count
, bReserved
;
670 /* initialize control count */
673 for(Index
= 0; Index
< NodesCount
; Index
++)
675 /* check if the node has already been reserved to a line */
676 MMixerIsTopologyNodeReserved(Topology
, Nodes
[Index
], &bReserved
);
680 /* node is already used, skip it */
684 /* set node status as used */
685 MMixerSetTopologyNodeReserved(Topology
, Nodes
[Index
]);
687 /* query node type */
688 NodeType
= MMixerGetNodeTypeFromTopology(Topology
, Nodes
[Index
]);
690 if (IsEqualGUIDAligned(NodeType
, &KSNODETYPE_VOLUME
))
692 /* calculate maximum channel count for node */
693 MMixerGetMaxChannelsForNode(MixerContext
, MixerInfo
, hMixer
, Nodes
[Index
], &MaxChannels
);
695 DPRINT("NodeId %lu MaxChannels %lu Line %S Id %lu\n", Nodes
[Index
], MaxChannels
, DstLine
->Line
.szName
, DstLine
->Line
.dwLineID
);
696 /* calculate maximum channels */
697 DstLine
->Line
.cChannels
= min(DstLine
->Line
.cChannels
, MaxChannels
);
701 /* use default of one channel */
705 /* now add the mixer control */
706 Status
= MMixerAddMixerControl(MixerContext
, MixerInfo
, hMixer
, Topology
, Nodes
[Index
], DstLine
, MaxChannels
);
708 if (Status
== MM_STATUS_SUCCESS
)
710 /* increment control count */
715 /* store control count */
716 DstLine
->Line
.cControls
= Count
;
719 return MM_STATUS_SUCCESS
;
723 MMixerGetComponentAndTargetType(
724 IN PMIXER_CONTEXT MixerContext
,
725 IN OUT LPMIXER_INFO MixerInfo
,
728 OUT PULONG ComponentType
,
729 OUT PULONG TargetType
)
731 KSPIN_DATAFLOW DataFlow
;
732 KSPIN_COMMUNICATION Communication
;
737 BOOLEAN BridgePin
= FALSE
;
738 PKSPIN_PHYSICALCONNECTION Connection
;
740 /* first dataflow type */
741 Status
= MMixerGetPinDataFlowAndCommunication(MixerContext
, hMixer
, PinId
, &DataFlow
, &Communication
);
743 if (Status
!= MM_STATUS_SUCCESS
)
745 /* failed to get dataflow */
749 /* now get pin category guid */
750 Request
.PinId
= PinId
;
751 Request
.Reserved
= 0;
752 Request
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
753 Request
.Property
.Set
= KSPROPSETID_Pin
;
754 Request
.Property
.Id
= KSPROPERTY_PIN_CATEGORY
;
757 /* get pin category */
758 Status
= MixerContext
->Control(hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_PIN
), &Guid
, sizeof(GUID
), &BytesReturned
);
759 if (Status
!= MM_STATUS_SUCCESS
)
761 /* failed to get dataflow */
765 /* check if it has a physical connection */
766 Status
= MMixerGetPhysicalConnection(MixerContext
, hMixer
, PinId
, &Connection
);
767 if (Status
== MM_STATUS_SUCCESS
)
769 /* pin is a brige pin */
772 /* free physical connection */
773 MixerContext
->Free(Connection
);
776 if (DataFlow
== KSPIN_DATAFLOW_IN
)
778 if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_MICROPHONE
) ||
779 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DESKTOP_MICROPHONE
))
781 /* type microphone */
782 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
783 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
;
785 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_LEGACY_AUDIO_CONNECTOR
) ||
786 IsEqualGUIDAligned(&Guid
, &KSCATEGORY_AUDIO
) ||
787 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPEAKER
))
790 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
791 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT
;
793 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_CD_PLAYER
))
796 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
797 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC
;
799 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SYNTHESIZER
))
801 /* type synthesizer */
802 *TargetType
= MIXERLINE_TARGETTYPE_MIDIOUT
;
803 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER
;
805 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_LINE_CONNECTOR
))
808 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
809 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_LINE
;
811 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_TELEPHONE
) ||
812 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_PHONE_LINE
) ||
813 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DOWN_LINE_PHONE
))
816 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
817 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE
;
819 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ANALOG_CONNECTOR
))
823 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
825 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
827 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_ANALOG
;
829 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPDIF_INTERFACE
))
833 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
835 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
837 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_DIGITAL
;
842 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
843 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED
;
844 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId
, BridgePin
);
849 if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPEAKER
) ||
850 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DESKTOP_SPEAKER
) ||
851 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ROOM_SPEAKER
) ||
852 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_COMMUNICATION_SPEAKER
))
855 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
856 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
858 else if (IsEqualGUIDAligned(&Guid
, &KSCATEGORY_AUDIO
) ||
859 IsEqualGUIDAligned(&Guid
, &PINNAME_CAPTURE
))
862 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
863 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
865 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_HEADPHONES
) ||
866 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO
))
868 /* type head phones */
869 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
870 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_HEADPHONES
;
872 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_TELEPHONE
) ||
873 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_PHONE_LINE
) ||
874 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DOWN_LINE_PHONE
))
877 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
878 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_TELEPHONE
;
880 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ANALOG_CONNECTOR
))
885 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
886 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
890 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
891 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
894 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPDIF_INTERFACE
))
899 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
900 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
904 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
905 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
911 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
912 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
913 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId
, BridgePin
);
918 return MM_STATUS_SUCCESS
;
922 MMixerBuildMixerSourceLine(
923 IN PMIXER_CONTEXT MixerContext
,
924 IN OUT LPMIXER_INFO MixerInfo
,
926 IN PTOPOLOGY Topology
,
930 IN ULONG DestinationLineID
,
931 OUT LPMIXERLINE_EXT
* OutSrcLine
)
933 LPMIXERLINE_EXT SrcLine
, DstLine
;
936 ULONG ComponentType
, TargetType
;
938 /* get component and target type */
939 Status
= MMixerGetComponentAndTargetType(MixerContext
, MixerInfo
, hMixer
, PinId
, &ComponentType
, &TargetType
);
940 if (Status
!= MM_STATUS_SUCCESS
)
942 /* failed to get component status */
943 TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
944 ComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
947 /* construct source line */
948 SrcLine
= (LPMIXERLINE_EXT
)MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
953 return MM_STATUS_NO_MEMORY
;
956 /* get destination line */
957 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineID
);
960 /* initialize mixer src line */
961 SrcLine
->PinId
= PinId
;
963 /* initialize mixer line */
964 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
965 SrcLine
->Line
.dwDestination
= MixerInfo
->MixCaps
.cDestinations
-1;
966 SrcLine
->Line
.dwSource
= DstLine
->Line
.cConnections
;
967 SrcLine
->Line
.dwLineID
= (DstLine
->Line
.cConnections
* SOURCE_LINE
)+ (MixerInfo
->MixCaps
.cDestinations
-1);
968 SrcLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
| MIXERLINE_LINEF_SOURCE
;
969 SrcLine
->Line
.dwComponentType
= ComponentType
;
970 SrcLine
->Line
.dwUser
= 0;
971 SrcLine
->Line
.cChannels
= DstLine
->Line
.cChannels
;
972 SrcLine
->Line
.cConnections
= 0;
973 SrcLine
->Line
.Target
.dwType
= TargetType
;
974 SrcLine
->Line
.Target
.dwDeviceID
= DstLine
->Line
.Target
.dwDeviceID
;
975 SrcLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
976 SrcLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
977 SrcLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
978 InitializeListHead(&SrcLine
->ControlsList
);
981 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == L
'\0');
982 wcscpy(SrcLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
985 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, hMixer
, PinId
, &PinName
);
987 if (Status
== MM_STATUS_SUCCESS
)
989 /* store pin name as line name */
990 MixerContext
->Copy(SrcLine
->Line
.szShortName
, PinName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
991 SrcLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
993 MixerContext
->Copy(SrcLine
->Line
.szName
, PinName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
994 SrcLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
996 /* free pin name buffer */
997 MixerContext
->Free(PinName
);
1000 /* add the controls to mixer line */
1001 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, hMixer
, Topology
, SrcLine
, NodesCount
, Nodes
);
1002 if (Status
!= MM_STATUS_SUCCESS
)
1009 *OutSrcLine
= SrcLine
;
1011 return MM_STATUS_SUCCESS
;
1015 MMixerAddMixerSourceLines(
1016 IN PMIXER_CONTEXT MixerContext
,
1017 IN OUT LPMIXER_INFO MixerInfo
,
1019 IN PTOPOLOGY Topology
,
1020 IN ULONG DestinationLineID
,
1021 IN ULONG LineTerminator
)
1023 PULONG AllNodes
, AllPins
, AllPinNodes
;
1024 ULONG AllNodesCount
, AllPinsCount
, AllPinNodesCount
;
1025 ULONG Index
, SubIndex
, PinId
, CurNode
, bConnected
;
1026 MIXER_STATUS Status
;
1027 LPMIXERLINE_EXT DstLine
, SrcLine
;
1029 /* get destination line */
1030 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineID
);
1033 /* allocate an array to store all nodes which are upstream of the line terminator */
1034 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllNodes
);
1036 /* check for success */
1037 if (Status
!= MM_STATUS_SUCCESS
)
1040 return MM_STATUS_NO_MEMORY
;
1043 /* allocate an array to store all nodes which are downstream of a particular pin */
1044 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllPinNodes
);
1046 /* allocate an array to store all pins which are upstream of this pin */
1047 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &AllPins
);
1049 /* check for success */
1050 if (Status
!= MM_STATUS_SUCCESS
)
1053 MixerContext
->Free(AllNodes
);
1054 return MM_STATUS_NO_MEMORY
;
1057 /* get all nodes which indirectly / directly connect to this node */
1059 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllNodesCount
, AllNodes
);
1061 /* get all pins which indirectly / directly connect to this node */
1063 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllPinsCount
, AllPins
);
1065 DPRINT("LineTerminator %lu\n", LineTerminator
);
1066 DPRINT("PinCount %lu\n", AllPinsCount
);
1067 DPRINT("AllNodesCount %lu\n", AllNodesCount
);
1069 /* now construct the source lines which are attached to the destination line */
1070 Index
= AllPinsCount
;
1074 /* get current pin id */
1075 PinId
= AllPins
[Index
- 1];
1077 /* reset nodes count */
1078 AllPinNodesCount
= 0;
1080 /* now scan all nodes and add them to AllPinNodes array when they are connected to this pin */
1081 for(SubIndex
= 0; SubIndex
< AllNodesCount
; SubIndex
++)
1083 /* get current node index */
1084 CurNode
= AllNodes
[SubIndex
];
1086 if (CurNode
!= MAXULONG
&& CurNode
!= LineTerminator
)
1088 /* check if that node is connected in some way to the current pin */
1089 Status
= MMixerIsNodeConnectedToPin(MixerContext
, Topology
, CurNode
, PinId
, TRUE
, &bConnected
);
1091 if (Status
!= MM_STATUS_SUCCESS
)
1096 /* it is connected */
1097 AllPinNodes
[AllPinNodesCount
] = CurNode
;
1100 /* clear current index */
1101 AllNodes
[SubIndex
] = MAXULONG
;
1106 /* decrement pin index */
1109 if (AllPinNodesCount
)
1114 /* now build the mixer source line */
1115 Status
= MMixerBuildMixerSourceLine(MixerContext
, MixerInfo
, hMixer
, Topology
, PinId
, AllPinNodesCount
, AllPinNodes
, DestinationLineID
, &SrcLine
);
1117 if (Status
== MM_STATUS_SUCCESS
)
1119 /* insert into line list */
1120 InsertTailList(&MixerInfo
->LineList
, &SrcLine
->Entry
);
1122 /* increment destination line count */
1123 DstLine
->Line
.cConnections
++;
1125 /* mark pin as reserved */
1126 MMixerSetTopologyPinReserved(Topology
, PinId
);
1129 DPRINT1("Adding PinId %lu AllPinNodesCount %lu to DestinationLine %lu\n", PinId
, AllPinNodesCount
, DestinationLineID
);
1130 for(TempIndex
= 0; TempIndex
< AllPinNodesCount
; TempIndex
++)
1131 DPRINT1("NodeIndex %lu\n", AllPinNodes
[TempIndex
]);
1138 DPRINT1("Discarding DestinationLineID %lu PinId %lu NO NODES!\n", DestinationLineID
, PinId
);
1144 return MM_STATUS_SUCCESS
;
1149 MMixerAddMixerControlsToDestinationLine(
1150 IN PMIXER_CONTEXT MixerContext
,
1151 IN OUT LPMIXER_INFO MixerInfo
,
1153 IN PTOPOLOGY Topology
,
1156 IN ULONG DestinationLineId
,
1157 OUT PULONG OutLineTerminator
)
1160 ULONG NodesCount
, LineTerminator
;
1161 MIXER_STATUS Status
;
1162 LPMIXERLINE_EXT DstLine
;
1164 /* allocate nodes index array */
1165 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
1167 /* check for success */
1168 if (Status
!= MM_STATUS_SUCCESS
)
1171 return MM_STATUS_NO_MEMORY
;
1174 /* get all destination line controls */
1175 Status
= MMixerCountMixerControls(MixerContext
, Topology
, PinId
, bInput
, TRUE
, &NodesCount
, Nodes
, &LineTerminator
);
1177 /* check for success */
1178 if (Status
!= MM_STATUS_SUCCESS
)
1180 /* failed to count controls */
1181 MixerContext
->Free(Nodes
);
1185 /* get destination mixer line */
1186 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineId
);
1193 /* add all nodes as mixer controls to the destination line */
1194 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, hMixer
, Topology
, DstLine
, NodesCount
, Nodes
);
1195 if (Status
!= MM_STATUS_SUCCESS
)
1197 /* failed to add controls */
1198 MixerContext
->Free(Nodes
);
1204 *OutLineTerminator
= LineTerminator
;
1211 MMixerApplyOutputFilterHack(
1212 IN PMIXER_CONTEXT MixerContext
,
1213 IN LPMIXER_DATA MixerData
,
1215 IN OUT PULONG PinsCount
,
1218 ULONG Count
= 0, Index
;
1219 MIXER_STATUS Status
;
1220 PKSPIN_PHYSICALCONNECTION Connection
;
1222 for(Index
= 0; Index
< *PinsCount
; Index
++)
1224 /* check if it has a physical connection */
1225 Status
= MMixerGetPhysicalConnection(MixerContext
, hMixer
, Pins
[Index
], &Connection
);
1227 if (Status
== MM_STATUS_SUCCESS
)
1230 MixerContext
->Copy(&Pins
[Index
], &Pins
[Index
+ 1], (*PinsCount
- (Index
+ 1)) * sizeof(ULONG
));
1232 /* free physical connection */
1233 MixerContext
->Free(Connection
);
1235 /* decrement index */
1238 /* decrement pin count */
1253 MMixerHandlePhysicalConnection(
1254 IN PMIXER_CONTEXT MixerContext
,
1255 IN PMIXER_LIST MixerList
,
1256 IN LPMIXER_DATA MixerData
,
1257 IN OUT LPMIXER_INFO MixerInfo
,
1259 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
1261 MIXER_STATUS Status
;
1262 ULONG PinsCount
, LineTerminator
, DestinationLineID
;
1266 /* first try to open the connected filter */
1267 OutConnection
->SymbolicLinkName
[1] = L
'\\';
1268 MixerData
= MMixerGetDataByDeviceName(MixerList
, OutConnection
->SymbolicLinkName
);
1270 /* check if the linked connection is found */
1273 /* filter references invalid physical connection */
1274 return MM_STATUS_UNSUCCESSFUL
;
1277 DPRINT("Name %S, Pin %lu bInput %lu\n", OutConnection
->SymbolicLinkName
, OutConnection
->Pin
, bInput
);
1280 ASSERT(MixerData
->MixerInfo
== NULL
|| MixerData
->MixerInfo
== MixerInfo
);
1282 /* associate with mixer */
1283 MixerData
->MixerInfo
= MixerInfo
;
1285 if (MixerData
->Topology
== NULL
)
1287 /* construct new topology */
1288 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1289 if (Status
!= MM_STATUS_SUCCESS
)
1291 /* failed to create topology */
1295 /* store topology */
1296 MixerData
->Topology
= Topology
;
1300 /* re-use existing topology */
1301 Topology
= MixerData
->Topology
;
1304 /* mark pin as consumed */
1305 MMixerSetTopologyPinReserved(Topology
, OutConnection
->Pin
);
1309 /* allocate pin index array which will hold all referenced pins */
1310 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1311 if (Status
!= MM_STATUS_SUCCESS
)
1313 /* failed to create topology */
1317 /* the mixer is an output mixer
1318 * find end pin of the node path
1321 Status
= MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext
, Topology
, OutConnection
->Pin
, FALSE
, &PinsCount
, Pins
);
1323 /* check for success */
1324 if (Status
!= MM_STATUS_SUCCESS
)
1326 /* failed to get end pin */
1327 MixerContext
->Free(Pins
);
1328 //MMixerFreeTopology(Topology);
1330 /* return error code */
1334 * some topologies do not have strict boundaries
1335 * WorkArround: remove all pin ids which have a physical connection
1336 * because bridge pins may belong to different render paths
1338 MMixerApplyOutputFilterHack(MixerContext
, MixerData
, MixerData
->hDevice
, &PinsCount
, Pins
);
1341 ASSERT(PinsCount
!= 0);
1342 ASSERT(PinsCount
== 1);
1344 /* create destination line */
1345 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Pins
[0], bInput
);
1347 /* calculate destination line id */
1348 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1350 if (Status
!= MM_STATUS_SUCCESS
)
1352 /* failed to build destination line */
1353 MixerContext
->Free(Pins
);
1355 /* return error code */
1359 /* add mixer controls to destination line */
1360 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, Pins
[0], bInput
, DestinationLineID
, &LineTerminator
);
1362 if (Status
== MM_STATUS_SUCCESS
)
1364 /* now add the rest of the source lines */
1365 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, DestinationLineID
, LineTerminator
);
1368 /* mark pin as consumed */
1369 MMixerSetTopologyPinReserved(Topology
, Pins
[0]);
1371 /* free topology pin array */
1372 MixerContext
->Free(Pins
);
1376 /* calculate destination line id */
1377 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1379 /* add mixer controls */
1380 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, OutConnection
->Pin
, bInput
, DestinationLineID
, &LineTerminator
);
1382 if (Status
== MM_STATUS_SUCCESS
)
1384 /* now add the rest of the source lines */
1385 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, MixerData
->hDevice
, Topology
, DestinationLineID
, LineTerminator
);
1393 MMixerInitializeFilter(
1394 IN PMIXER_CONTEXT MixerContext
,
1395 IN PMIXER_LIST MixerList
,
1396 IN LPMIXER_DATA MixerData
,
1397 IN LPMIXER_INFO MixerInfo
,
1398 IN PTOPOLOGY Topology
,
1400 IN ULONG bInputMixer
,
1401 IN OUT LPMIXER_INFO
* OutMixerInfo
)
1404 MIXER_STATUS Status
;
1405 PKSPIN_PHYSICALCONNECTION OutConnection
;
1408 ULONG NewMixerInfo
= FALSE
;
1410 if (MixerInfo
== NULL
)
1412 /* allocate a mixer info struct */
1413 MixerInfo
= (LPMIXER_INFO
) MixerContext
->Alloc(sizeof(MIXER_INFO
));
1417 return MM_STATUS_NO_MEMORY
;
1420 /* new mixer info */
1421 NewMixerInfo
= TRUE
;
1423 /* intialize mixer caps */
1424 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; /* FIXME */
1425 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; /* FIXME */
1426 MixerInfo
->MixCaps
.vDriverVersion
= 1; /* FIXME */
1427 MixerInfo
->MixCaps
.fdwSupport
= 0;
1428 MixerInfo
->MixCaps
.cDestinations
= 0;
1430 /* get mixer name */
1431 MMixerGetDeviceName(MixerContext
, MixerInfo
->MixCaps
.szPname
, MixerData
->hDeviceInterfaceKey
);
1433 /* initialize line list */
1434 InitializeListHead(&MixerInfo
->LineList
);
1435 InitializeListHead(&MixerInfo
->EventList
);
1437 /* associate with mixer data */
1438 MixerData
->MixerInfo
= MixerInfo
;
1441 /* store mixer info */
1442 *OutMixerInfo
= MixerInfo
;
1444 /* now allocate an array which will receive the indices of the pin
1445 * which has a ADC / DAC nodetype in its path
1447 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1448 ASSERT(Status
== MM_STATUS_SUCCESS
);
1452 /* now get all sink / source pins, which are attached to the ADC / DAC node
1453 * For sink pins (wave out) search up stream
1454 * For source pins (wave in) search down stream
1455 * The search direction is always the opposite of the current mixer type
1458 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, !bInputMixer
, &PinsFound
, Pins
);
1460 /* if there is no pin found, we have a broken topology */
1461 ASSERT(PinsFound
!= 0);
1463 /* now create a wave info struct */
1464 Status
= MMixerInitializeWaveInfo(MixerContext
, MixerList
, MixerData
, MixerInfo
->MixCaps
.szPname
, bInputMixer
, PinsFound
, Pins
);
1465 if (Status
!= MM_STATUS_SUCCESS
)
1467 /* failed to create wave info struct */
1468 MixerContext
->Free(MixerInfo
);
1469 MixerContext
->Free(Pins
);
1473 /* mark all found pins as reserved */
1474 for(Index
= 0; Index
< PinsFound
; Index
++)
1476 MMixerSetTopologyPinReserved(Topology
, Pins
[Index
]);
1481 /* pre create the mixer destination line for input mixers */
1482 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, MixerData
->hDevice
, Pins
[0], bInputMixer
);
1484 if (Status
!= MM_STATUS_SUCCESS
)
1486 /* failed to create mixer destination line */
1492 /* now get the bridge pin which is at the end of node path
1493 * For sink pins (wave out) search down stream
1494 * For source pins (wave in) search up stream
1496 MixerContext
->Free(Pins
);
1497 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1498 ASSERT(Status
== MM_STATUS_SUCCESS
);
1501 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bInputMixer
, &PinsFound
, Pins
);
1503 /* if there is no pin found, we have a broken topology */
1504 ASSERT(PinsFound
!= 0);
1506 /* there should be exactly one bridge pin */
1507 ASSERT(PinsFound
== 1);
1509 DPRINT("BridgePin %lu bInputMixer %lu\n", Pins
[0], bInputMixer
);
1511 /* does the pin have a physical connection */
1512 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Pins
[0], &OutConnection
);
1514 if (Status
== MM_STATUS_SUCCESS
)
1516 /* mark pin as reserved */
1517 MMixerSetTopologyPinReserved(Topology
, Pins
[0]);
1519 /* topology on the topoloy filter */
1520 Status
= MMixerHandlePhysicalConnection(MixerContext
, MixerList
, MixerData
, MixerInfo
, bInputMixer
, OutConnection
);
1522 /* free physical connection data */
1523 MixerContext
->Free(OutConnection
);
1528 * handle drivers which expose their topology on the same filter
1534 MixerContext
->Free(Pins
);
1539 InsertHeadList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1540 /* increment mixer count */
1541 MixerList
->MixerListCount
++;
1549 MMixerHandleAlternativeMixers(
1550 IN PMIXER_CONTEXT MixerContext
,
1551 IN PMIXER_LIST MixerList
,
1552 IN LPMIXER_DATA MixerData
,
1553 IN PTOPOLOGY Topology
)
1555 ULONG Index
, PinCount
, Reserved
;
1556 MIXER_STATUS Status
;
1557 ULONG DestinationLineID
, LineTerminator
;
1558 LPMIXERLINE_EXT DstLine
;
1560 DPRINT("DeviceName %S\n", MixerData
->DeviceName
);
1562 /* get topology pin count */
1563 MMixerGetTopologyPinCount(Topology
, &PinCount
);
1565 for(Index
= 0; Index
< PinCount
; Index
++)
1567 MMixerIsTopologyPinReserved(Topology
, Index
, &Reserved
);
1569 /* check if it has already been reserved */
1570 if (Reserved
== TRUE
)
1572 /* pin has already been reserved */
1576 DPRINT("MixerName %S Available PinID %lu\n", MixerData
->DeviceName
, Index
);
1579 //ASSERT(MixerData->MixerInfo);
1581 if (!MixerData
->MixerInfo
)
1583 DPRINT1("Expected mixer info\n");
1587 /* build the destination line */
1588 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerData
->MixerInfo
, MixerData
->hDevice
, Index
, TRUE
);
1589 if (Status
!= MM_STATUS_SUCCESS
)
1591 /* failed to build destination line */
1595 /* calculate destination line id */
1596 DestinationLineID
= (DESTINATION_LINE
+ MixerData
->MixerInfo
->MixCaps
.cDestinations
-1);
1598 /* add mixer controls to destination line */
1599 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerData
->MixerInfo
, MixerData
->hDevice
, MixerData
->Topology
, Index
, TRUE
, DestinationLineID
, &LineTerminator
);
1600 if (Status
== MM_STATUS_SUCCESS
)
1602 /* now add the rest of the source lines */
1603 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerData
->MixerInfo
, MixerData
->hDevice
, MixerData
->Topology
, DestinationLineID
, LineTerminator
);
1606 /* mark pin as consumed */
1607 MMixerSetTopologyPinReserved(Topology
, Index
);
1609 /* now grab destination line */
1610 DstLine
= MMixerGetSourceMixerLineByLineId(MixerData
->MixerInfo
, DestinationLineID
);
1612 /* set type and target as undefined */
1613 DstLine
->Line
.dwComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
1614 DstLine
->Line
.Target
.dwType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
1615 DstLine
->Line
.Target
.vDriverVersion
= 0;
1616 DstLine
->Line
.Target
.wMid
= 0;
1617 DstLine
->Line
.Target
.wPid
= 0;
1623 IN PMIXER_CONTEXT MixerContext
,
1624 IN PMIXER_LIST MixerList
,
1625 IN LPMIXER_DATA MixerData
,
1626 IN PULONG DeviceCount
)
1628 MIXER_STATUS Status
;
1631 LPMIXER_INFO MixerInfo
= NULL
;
1633 /* check if topology has already been built */
1634 if (MixerData
->Topology
== NULL
)
1636 /* build topology */
1637 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1639 if (Status
!= MM_STATUS_SUCCESS
)
1641 /* failed to build topology */
1645 /* store topology */
1646 MixerData
->Topology
= Topology
;
1650 /* re-use topology */
1651 Topology
= MixerData
->Topology
;
1654 /* check if the filter has an wave out node */
1655 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_DAC
);
1656 if (NodeIndex
!= MAXULONG
)
1659 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, NULL
, Topology
, NodeIndex
, FALSE
, &MixerInfo
);
1661 /* check for success */
1662 if (Status
== MM_STATUS_SUCCESS
)
1664 /* increment mixer count */
1669 /* reset mixer info in case of error */
1674 /* check if the filter has an wave in node */
1675 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_ADC
);
1676 if (NodeIndex
!= MAXULONG
)
1679 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, MixerInfo
, Topology
, NodeIndex
, TRUE
, &MixerInfo
);
1681 /* check for success */
1682 if (Status
== MM_STATUS_SUCCESS
)
1684 /* increment mixer count */
1690 /* TODO: apply hacks for Wave source line */
1692 /* activate midi devices */
1693 //MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology);
1702 IN PMIXER_CONTEXT MixerContext
,
1703 IN OUT LPMIXER_INFO MixerInfo
,
1704 IN PVOID MixerEventContext
,
1705 IN PMIXER_EVENT MixerEventRoutine
)
1707 //KSE_NODE Property;
1708 PEVENT_NOTIFICATION_ENTRY EventData
;
1709 //ULONG BytesReturned;
1710 //MIXER_STATUS Status;
1712 EventData
= (PEVENT_NOTIFICATION_ENTRY
)MixerContext
->AllocEventData(sizeof(EVENT_NOTIFICATION_ENTRY
));
1715 /* not enough memory */
1716 return MM_STATUS_NO_MEMORY
;
1721 Property
.Event
.Set
= KSEVENTSETID_AudioControlChange
;
1722 Property
.Event
.Flags
= KSEVENT_TYPE_TOPOLOGY
|KSEVENT_TYPE_ENABLE
;
1723 Property
.Event
.Id
= KSEVENT_CONTROL_CHANGE
;
1725 Property
.NodeId
= NodeId
;
1726 Property
.Reserved
= 0;
1728 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSP_NODE
), (PVOID
)EventData
, sizeof(KSEVENTDATA
), &BytesReturned
);
1729 if (Status
!= MM_STATUS_SUCCESS
)
1731 /* failed to add event */
1732 MixerContext
->FreeEventData(EventData
);
1737 /* initialize notification entry */
1738 EventData
->MixerEventContext
= MixerEventContext
;
1739 EventData
->MixerEventRoutine
= MixerEventRoutine
;
1742 InsertTailList(&MixerInfo
->EventList
, &EventData
->Entry
);
1743 return MM_STATUS_SUCCESS
;