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
,
35 IN PTOPOLOGY Topology
,
37 IN LPMIXERLINE_EXT MixerLine
,
38 OUT LPMIXERCONTROLW MixerControl
)
46 /* initialize mixer control */
47 MixerControl
->cbStruct
= sizeof(MIXERCONTROLW
);
48 MixerControl
->dwControlID
= MixerInfo
->ControlId
;
51 NodeType
= MMixerGetNodeTypeFromTopology(Topology
, NodeIndex
);
52 /* store control type */
53 MixerControl
->dwControlType
= MMixerGetControlTypeFromTopologyNode(NodeType
);
55 MixerControl
->fdwControl
= MIXERCONTROL_CONTROLF_UNIFORM
; /* FIXME */
56 MixerControl
->cMultipleItems
= 0;
58 /* setup request to retrieve name */
59 Node
.NodeId
= NodeIndex
;
60 Node
.Property
.Id
= KSPROPERTY_TOPOLOGY_NAME
;
61 Node
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
62 Node
.Property
.Set
= KSPROPSETID_Topology
;
65 /* get node name size */
66 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), NULL
, 0, &BytesReturned
);
68 if (Status
== MM_STATUS_MORE_ENTRIES
)
70 ASSERT(BytesReturned
!= 0);
71 Name
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
74 /* not enough memory */
75 return MM_STATUS_NO_MEMORY
;
79 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), (LPVOID
)Name
, BytesReturned
, &BytesReturned
);
81 if (Status
== MM_STATUS_SUCCESS
)
83 MixerContext
->Copy(MixerControl
->szShortName
, Name
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
84 MixerControl
->szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
86 MixerContext
->Copy(MixerControl
->szName
, Name
, (min(MIXER_LONG_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
87 MixerControl
->szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
90 /* free name buffer */
91 MixerContext
->Free(Name
);
94 MixerInfo
->ControlId
++;
96 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUX
)
101 /* allocate topology nodes array */
102 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
104 if (Status
!= MM_STATUS_SUCCESS
)
107 return STATUS_NO_MEMORY
;
110 /* get connected node count */
111 MMixerGetNextNodesFromNodeIndex(MixerContext
, Topology
, NodeIndex
, TRUE
, &NodesCount
, Nodes
);
114 MixerContext
->Free(Nodes
);
116 /* setup mux bounds */
117 MixerControl
->Bounds
.dwMinimum
= 0;
118 MixerControl
->Bounds
.dwMaximum
= NodesCount
- 1;
119 MixerControl
->Metrics
.dwReserved
[0] = NodesCount
;
120 MixerControl
->cMultipleItems
= NodesCount
;
121 MixerControl
->fdwControl
|= MIXERCONTROL_CONTROLF_MULTIPLE
;
123 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
125 MixerControl
->Bounds
.dwMinimum
= 0;
126 MixerControl
->Bounds
.dwMaximum
= 1;
128 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_ONOFF
)
130 /* only needs to set bounds */
131 MixerControl
->Bounds
.dwMinimum
= 0;
132 MixerControl
->Bounds
.dwMaximum
= 1;
134 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
136 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
138 PKSPROPERTY_DESCRIPTION Desc
;
139 PKSPROPERTY_MEMBERSHEADER Members
;
140 PKSPROPERTY_STEPPING_LONG Range
;
142 MixerControl
->Bounds
.dwMinimum
= 0;
143 MixerControl
->Bounds
.dwMaximum
= 0xFFFF;
144 MixerControl
->Metrics
.cSteps
= 0xC0; /* FIXME */
146 Length
= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) + sizeof(KSPROPERTY_STEPPING_LONG
);
147 Desc
= (PKSPROPERTY_DESCRIPTION
)MixerContext
->Alloc(Length
);
150 /* setup the request */
151 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
153 Property
.NodeProperty
.NodeId
= NodeIndex
;
154 Property
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
155 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
| KSPROPERTY_TYPE_TOPOLOGY
;
156 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
158 /* get node volume level info */
159 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), Desc
, Length
, &BytesReturned
);
161 if (Status
== MM_STATUS_SUCCESS
)
163 LPMIXERVOLUME_DATA VolumeData
;
164 ULONG Steps
, MaxRange
, Index
;
167 Members
= (PKSPROPERTY_MEMBERSHEADER
)(Desc
+ 1);
168 Range
= (PKSPROPERTY_STEPPING_LONG
)(Members
+ 1);
170 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
);
172 MaxRange
= Range
->Bounds
.UnsignedMaximum
- Range
->Bounds
.UnsignedMinimum
;
177 VolumeData
= (LPMIXERVOLUME_DATA
)MixerContext
->Alloc(sizeof(MIXERVOLUME_DATA
));
179 return MM_STATUS_NO_MEMORY
;
181 Steps
= MaxRange
/ Range
->SteppingDelta
+ 1;
183 /* store mixer control info there */
184 VolumeData
->Header
.dwControlID
= MixerControl
->dwControlID
;
185 VolumeData
->SignedMaximum
= Range
->Bounds
.SignedMaximum
;
186 VolumeData
->SignedMinimum
= Range
->Bounds
.SignedMinimum
;
187 VolumeData
->SteppingDelta
= Range
->SteppingDelta
;
188 VolumeData
->ValuesCount
= Steps
;
189 VolumeData
->InputSteppingDelta
= 0x10000 / Steps
;
191 VolumeData
->Values
= (PLONG
)MixerContext
->Alloc(sizeof(LONG
) * Steps
);
192 if (!VolumeData
->Values
)
194 MixerContext
->Free(Desc
);
195 MixerContext
->Free(VolumeData
);
196 return MM_STATUS_NO_MEMORY
;
199 Value
= Range
->Bounds
.SignedMinimum
;
200 for(Index
= 0; Index
< Steps
; Index
++)
202 VolumeData
->Values
[Index
] = Value
;
203 Value
+= Range
->SteppingDelta
;
205 InsertTailList(&MixerLine
->LineControlsExtraData
, &VolumeData
->Header
.Entry
);
208 MixerContext
->Free(Desc
);
211 DPRINT("Status %x Name %S\n", Status
, MixerControl
->szName
);
212 return MM_STATUS_SUCCESS
;
216 MMixerCreateDestinationLine(
217 IN PMIXER_CONTEXT MixerContext
,
218 IN LPMIXER_INFO MixerInfo
,
219 IN ULONG bInputMixer
,
222 LPMIXERLINE_EXT DestinationLine
;
224 /* allocate a mixer destination line */
225 DestinationLine
= (LPMIXERLINE_EXT
) MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
229 return MM_STATUS_NO_MEMORY
;
232 /* initialize mixer destination line */
233 DestinationLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
234 DestinationLine
->Line
.dwSource
= MAXULONG
;
235 DestinationLine
->Line
.dwLineID
= MixerInfo
->MixCaps
.cDestinations
+ DESTINATION_LINE
;
236 DestinationLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
;
237 DestinationLine
->Line
.dwUser
= 0;
238 DestinationLine
->Line
.dwDestination
= MixerInfo
->MixCaps
.cDestinations
;
239 DestinationLine
->Line
.dwComponentType
= (bInputMixer
== 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
);
240 DestinationLine
->Line
.cChannels
= 2; /* FIXME */
244 MixerContext
->Copy(DestinationLine
->Line
.szShortName
, LineName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
245 DestinationLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
247 MixerContext
->Copy(DestinationLine
->Line
.szName
, LineName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
248 DestinationLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
252 DestinationLine
->Line
.Target
.dwType
= (bInputMixer
== 0 ? MIXERLINE_TARGETTYPE_WAVEOUT
: MIXERLINE_TARGETTYPE_WAVEIN
);
253 DestinationLine
->Line
.Target
.dwDeviceID
= 0; //FIXME
254 DestinationLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
255 DestinationLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
256 DestinationLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
258 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == 0);
259 wcscpy(DestinationLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
261 /* initialize extra line */
262 InitializeListHead(&DestinationLine
->LineControlsExtraData
);
264 /* insert into mixer info */
265 InsertTailList(&MixerInfo
->LineList
, &DestinationLine
->Entry
);
267 /* increment destination count */
268 MixerInfo
->MixCaps
.cDestinations
++;
271 return MM_STATUS_SUCCESS
;
276 IN PMIXER_CONTEXT MixerContext
,
277 IN LPMIXER_INFO MixerInfo
,
279 IN OUT LPWSTR
* OutBuffer
)
289 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
290 Pin
.Property
.Set
= KSPROPSETID_Pin
;
291 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
293 /* try get pin name size */
294 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
296 /* check if buffer overflowed */
297 if (Status
== MM_STATUS_MORE_ENTRIES
)
299 /* allocate buffer */
300 Buffer
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
304 return MM_STATUS_NO_MEMORY
;
307 /* try get pin name */
308 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Buffer
, BytesReturned
, &BytesReturned
);
309 if (Status
!= MM_STATUS_SUCCESS
)
311 /* failed to get pin name */
312 MixerContext
->Free((PVOID
)Buffer
);
316 /* successfully obtained pin name */
318 return MM_STATUS_SUCCESS
;
321 /* failed to get pin name */
326 MMixerBuildMixerDestinationLine(
327 IN PMIXER_CONTEXT MixerContext
,
328 IN OUT LPMIXER_INFO MixerInfo
,
335 /* try get pin name */
336 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, PinId
, &PinName
);
337 if (Status
== MM_STATUS_SUCCESS
)
339 /* create mixer destination line */
341 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, PinName
);
344 MixerContext
->Free(PinName
);
348 /* create mixer destination line unlocalized */
349 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, L
"No Name");
357 IN PMIXER_CONTEXT MixerContext
,
358 IN LPMIXER_DATA MixerData
,
359 OUT PTOPOLOGY
* OutTopology
)
362 PKSMULTIPLE_ITEM NodeTypes
= NULL
;
363 PKSMULTIPLE_ITEM NodeConnections
= NULL
;
366 if (MixerData
->Topology
)
368 /* re-use existing topology */
369 *OutTopology
= MixerData
->Topology
;
371 return MM_STATUS_SUCCESS
;
374 /* get connected filter pin count */
375 PinsCount
= MMixerGetFilterPinCount(MixerContext
, MixerData
->hDevice
);
379 /* referenced filter does not have any pins */
380 return MM_STATUS_UNSUCCESSFUL
;
383 /* get topology node types */
384 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
385 if (Status
!= MM_STATUS_SUCCESS
)
387 /* failed to get topology node types */
391 /* get topology connections */
392 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
393 if (Status
!= MM_STATUS_SUCCESS
)
395 /* failed to get topology connections */
396 MixerContext
->Free(NodeTypes
);
400 /* create a topology */
401 Status
= MMixerCreateTopology(MixerContext
, PinsCount
, NodeConnections
, NodeTypes
, OutTopology
);
403 /* free node types & connections */
404 MixerContext
->Free(NodeConnections
);
405 MixerContext
->Free(NodeTypes
);
407 if (Status
== MM_STATUS_SUCCESS
)
409 /* store topology object */
410 MixerData
->Topology
= *OutTopology
;
418 MMixerCountMixerControls(
419 IN PMIXER_CONTEXT MixerContext
,
420 IN PTOPOLOGY Topology
,
422 IN ULONG bInputMixer
,
424 OUT PULONG OutNodesCount
,
426 OUT PULONG OutLineTerminator
)
429 ULONG NodesCount
, NodeIndex
, Count
, bTerminator
;
432 /* allocate an array to store all nodes which are upstream of this pin */
433 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
435 if (Status
!= MM_STATUS_SUCCESS
)
438 return STATUS_NO_MEMORY
;
441 /* mark result array as zero */
445 MMixerGetNextNodesFromPinIndex(MixerContext
, Topology
, PinId
, bUpStream
, &NodesCount
, Nodes
);
447 /* assume no topology split before getting line terminator */
448 ASSERT(NodesCount
== 1);
451 NodeIndex
= Nodes
[0];
456 /* check if the node is a terminator */
457 MMixerIsNodeTerminator(Topology
, NodeIndex
, &bTerminator
);
461 /* found terminator */
464 /* add mux source for source destination line */
465 OutNodes
[Count
] = NodeIndex
;
472 OutNodes
[Count
] = NodeIndex
;
474 /* increment node count */
477 /* get next nodes upstream */
478 MMixerGetNextNodesFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bUpStream
, &NodesCount
, Nodes
);
480 /* assume there is a node connected */
481 ASSERT(NodesCount
!= 0);
482 ASSERT(NodesCount
== 1);
484 /* use first index */
485 NodeIndex
= Nodes
[0];
489 /* free node index */
490 MixerContext
->Free(Nodes
);
492 /* store nodes count */
493 *OutNodesCount
= Count
;
495 /* store line terminator */
496 *OutLineTerminator
= NodeIndex
;
499 return MM_STATUS_SUCCESS
;
503 MMixerGetChannelCountEnhanced(
504 IN PMIXER_CONTEXT MixerContext
,
505 IN LPMIXER_INFO MixerInfo
,
507 OUT PULONG MaxChannels
)
509 KSPROPERTY_DESCRIPTION Description
;
510 PKSPROPERTY_DESCRIPTION NewDescription
;
511 PKSPROPERTY_MEMBERSHEADER Header
;
516 /* try #1 obtain it via description */
517 Request
.NodeId
= NodeId
;
518 Request
.Reserved
= 0;
519 Request
.Property
.Set
= KSPROPSETID_Audio
;
520 Request
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
| KSPROPERTY_TYPE_TOPOLOGY
;
521 Request
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
524 /* get description */
525 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_NODE
), (PVOID
)&Description
, sizeof(KSPROPERTY_DESCRIPTION
), &BytesReturned
);
526 if (Status
== MM_STATUS_SUCCESS
)
528 if (Description
.DescriptionSize
>= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) && (Description
.MembersListCount
> 0))
530 /* allocate new description */
531 NewDescription
= MixerContext
->Alloc(Description
.DescriptionSize
);
535 /* not enough memory */
536 return MM_STATUS_NO_MEMORY
;
539 /* get description */
540 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_NODE
), (PVOID
)NewDescription
, Description
.DescriptionSize
, &BytesReturned
);
541 if (Status
== MM_STATUS_SUCCESS
)
544 Header
= (PKSPROPERTY_MEMBERSHEADER
)(NewDescription
+ 1);
546 if (Header
->Flags
& KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL
)
548 /* found enhanced flag */
549 ASSERT(Header
->MembersCount
> 1);
551 /* store channel count */
552 *MaxChannels
= Header
->MembersCount
;
554 /* free description */
555 MixerContext
->Free(NewDescription
);
558 return MM_STATUS_SUCCESS
;
562 /* free description */
563 MixerContext
->Free(NewDescription
);
567 /* failed to get channel count enhanced */
568 return MM_STATUS_UNSUCCESSFUL
;
572 MMixerGetChannelCountLegacy(
573 IN PMIXER_CONTEXT MixerContext
,
574 IN LPMIXER_INFO MixerInfo
,
576 OUT PULONG MaxChannels
)
580 KSNODEPROPERTY_AUDIO_CHANNEL Channel
;
584 Channel
.Reserved
= 0;
585 Channel
.NodeProperty
.NodeId
= NodeId
;
586 Channel
.NodeProperty
.Reserved
= 0;
587 Channel
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_TOPOLOGY
;
588 Channel
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
590 Channel
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
594 /* get channel volume */
595 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Channel
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), (PVOID
)&Volume
, sizeof(LONG
), &BytesReturned
);
596 if (Status
!= MM_STATUS_SUCCESS
)
599 /* increment channel count */
604 /* store channel count */
605 *MaxChannels
= Channel
.Channel
;
610 MMixerGetMaxChannelsForNode(
611 IN PMIXER_CONTEXT MixerContext
,
612 IN LPMIXER_INFO MixerInfo
,
614 OUT PULONG MaxChannels
)
618 /* try to get it enhanced */
619 Status
= MMixerGetChannelCountEnhanced(MixerContext
, MixerInfo
, NodeId
, MaxChannels
);
621 if (Status
!= MM_STATUS_SUCCESS
)
623 /* get it old-fashioned way */
624 MMixerGetChannelCountLegacy(MixerContext
, MixerInfo
, NodeId
, MaxChannels
);
629 MMixerAddMixerControlsToMixerLineByNodeIndexArray(
630 IN PMIXER_CONTEXT MixerContext
,
631 IN LPMIXER_INFO MixerInfo
,
632 IN PTOPOLOGY Topology
,
633 IN OUT LPMIXERLINE_EXT DstLine
,
637 ULONG Index
, Count
, bReserved
;
642 /* store nodes array */
643 DstLine
->NodeIds
= Nodes
;
645 /* allocate MIXERCONTROLSW array */
646 DstLine
->LineControls
= MixerContext
->Alloc(NodesCount
* sizeof(MIXERCONTROLW
));
648 if (!DstLine
->LineControls
)
651 return MM_STATUS_NO_MEMORY
;
654 /* initialize control count */
657 for(Index
= 0; Index
< NodesCount
; Index
++)
659 /* check if the node has already been reserved to a line */
660 MMixerIsTopologyNodeReserved(Topology
, Nodes
[Index
], &bReserved
);
664 /* node is already used, skip it */
668 /* set node status as used */
669 MMixerSetTopologyNodeReserved(Topology
, Nodes
[Index
]);
671 /* query node type */
672 NodeType
= MMixerGetNodeTypeFromTopology(Topology
, Nodes
[Index
]);
674 if (IsEqualGUIDAligned(NodeType
, &KSNODETYPE_VOLUME
))
676 /* calculate maximum channel count for node */
677 MMixerGetMaxChannelsForNode(MixerContext
, MixerInfo
, Nodes
[Index
], &MaxChannels
);
679 DPRINT("NodeId %lu MaxChannels %lu Line %S Id %lu\n", Nodes
[Index
], MaxChannels
, DstLine
->Line
.szName
, DstLine
->Line
.dwLineID
);
680 /* calculate maximum channels */
681 DstLine
->Line
.cChannels
= min(DstLine
->Line
.cChannels
, MaxChannels
);
685 /* now add the mixer control */
686 Status
= MMixerAddMixerControl(MixerContext
, MixerInfo
, Topology
, Nodes
[Index
], DstLine
, &DstLine
->LineControls
[Count
]);
688 if (Status
== MM_STATUS_SUCCESS
)
690 /* increment control count */
695 /* store control count */
696 DstLine
->Line
.cControls
= Count
;
699 return MM_STATUS_SUCCESS
;
703 MMixerGetComponentAndTargetType(
704 IN PMIXER_CONTEXT MixerContext
,
705 IN OUT LPMIXER_INFO MixerInfo
,
707 OUT PULONG ComponentType
,
708 OUT PULONG TargetType
)
710 KSPIN_DATAFLOW DataFlow
;
711 KSPIN_COMMUNICATION Communication
;
716 BOOLEAN BridgePin
= FALSE
;
717 PKSPIN_PHYSICALCONNECTION Connection
;
719 /* first dataflow type */
720 Status
= MMixerGetPinDataFlowAndCommunication(MixerContext
, MixerInfo
->hMixer
, PinId
, &DataFlow
, &Communication
);
722 if (Status
!= MM_STATUS_SUCCESS
)
724 /* failed to get dataflow */
728 /* now get pin category guid */
729 Request
.PinId
= PinId
;
730 Request
.Reserved
= 0;
731 Request
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
732 Request
.Property
.Set
= KSPROPSETID_Pin
;
733 Request
.Property
.Id
= KSPROPERTY_PIN_CATEGORY
;
736 /* get pin category */
737 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_PIN
), &Guid
, sizeof(GUID
), &BytesReturned
);
738 if (Status
!= MM_STATUS_SUCCESS
)
740 /* failed to get dataflow */
744 /* check if it has a physical connection */
745 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerInfo
->hMixer
, PinId
, &Connection
);
746 if (Status
== MM_STATUS_SUCCESS
)
748 /* pin is a brige pin */
751 /* free physical connection */
752 MixerContext
->Free(Connection
);
755 if (DataFlow
== KSPIN_DATAFLOW_IN
)
757 if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_MICROPHONE
) ||
758 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DESKTOP_MICROPHONE
))
760 /* type microphone */
761 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
762 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
;
764 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_LEGACY_AUDIO_CONNECTOR
) ||
765 IsEqualGUIDAligned(&Guid
, &KSCATEGORY_AUDIO
) ||
766 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPEAKER
))
769 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
770 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT
;
772 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_CD_PLAYER
))
775 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
776 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC
;
778 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SYNTHESIZER
))
780 /* type synthesizer */
781 *TargetType
= MIXERLINE_TARGETTYPE_MIDIOUT
;
782 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER
;
784 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_LINE_CONNECTOR
))
787 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
788 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_LINE
;
790 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_TELEPHONE
) ||
791 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_PHONE_LINE
) ||
792 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DOWN_LINE_PHONE
))
795 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
796 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE
;
798 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ANALOG_CONNECTOR
))
802 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
804 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
806 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_ANALOG
;
808 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPDIF_INTERFACE
))
812 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
814 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
816 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_DIGITAL
;
821 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
822 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED
;
823 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId
, BridgePin
);
828 if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPEAKER
) ||
829 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DESKTOP_SPEAKER
) ||
830 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ROOM_SPEAKER
) ||
831 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_COMMUNICATION_SPEAKER
))
834 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
835 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
837 else if (IsEqualGUIDAligned(&Guid
, &KSCATEGORY_AUDIO
) ||
838 IsEqualGUIDAligned(&Guid
, &PINNAME_CAPTURE
))
841 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
842 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
844 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_HEADPHONES
) ||
845 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO
))
847 /* type head phones */
848 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
849 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_HEADPHONES
;
851 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_TELEPHONE
) ||
852 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_PHONE_LINE
) ||
853 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DOWN_LINE_PHONE
))
856 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
857 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_TELEPHONE
;
859 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ANALOG_CONNECTOR
))
864 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
865 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
869 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
870 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
873 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPDIF_INTERFACE
))
878 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
879 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
883 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
884 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
890 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
891 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
892 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId
, BridgePin
);
897 return MM_STATUS_SUCCESS
;
901 MMixerBuildMixerSourceLine(
902 IN PMIXER_CONTEXT MixerContext
,
903 IN OUT LPMIXER_INFO MixerInfo
,
904 IN PTOPOLOGY Topology
,
908 IN ULONG DestinationLineID
,
909 OUT LPMIXERLINE_EXT
* OutSrcLine
)
911 LPMIXERLINE_EXT SrcLine
, DstLine
;
914 ULONG ComponentType
, TargetType
;
916 /* get component and target type */
917 Status
= MMixerGetComponentAndTargetType(MixerContext
, MixerInfo
, PinId
, &ComponentType
, &TargetType
);
918 if (Status
!= MM_STATUS_SUCCESS
)
920 /* failed to get component status */
921 TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
922 ComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
925 /* construct source line */
926 SrcLine
= (LPMIXERLINE_EXT
)MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
931 return MM_STATUS_NO_MEMORY
;
934 /* get destination line */
935 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineID
);
938 /* initialize mixer src line */
939 SrcLine
->hDevice
= MixerInfo
->hMixer
;
940 SrcLine
->PinId
= PinId
;
941 SrcLine
->NodeIds
= Nodes
;
943 /* initialize mixer line */
944 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
945 SrcLine
->Line
.dwDestination
= MixerInfo
->MixCaps
.cDestinations
-1;
946 SrcLine
->Line
.dwSource
= DstLine
->Line
.cConnections
;
947 SrcLine
->Line
.dwLineID
= (DstLine
->Line
.cConnections
* SOURCE_LINE
)+ (MixerInfo
->MixCaps
.cDestinations
-1);
948 SrcLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
| MIXERLINE_LINEF_SOURCE
;
949 SrcLine
->Line
.dwComponentType
= ComponentType
;
950 SrcLine
->Line
.dwUser
= 0;
951 SrcLine
->Line
.cChannels
= DstLine
->Line
.cChannels
;
952 SrcLine
->Line
.cConnections
= 0;
953 SrcLine
->Line
.Target
.dwType
= TargetType
;
954 SrcLine
->Line
.Target
.dwDeviceID
= DstLine
->Line
.Target
.dwDeviceID
;
955 SrcLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
956 SrcLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
957 SrcLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
958 InitializeListHead(&SrcLine
->LineControlsExtraData
);
961 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == L
'\0');
962 wcscpy(SrcLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
965 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, PinId
, &PinName
);
967 if (Status
== MM_STATUS_SUCCESS
)
969 /* store pin name as line name */
970 MixerContext
->Copy(SrcLine
->Line
.szShortName
, PinName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
971 SrcLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
973 MixerContext
->Copy(SrcLine
->Line
.szName
, PinName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
974 SrcLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
976 /* free pin name buffer */
977 MixerContext
->Free(PinName
);
980 /* add the controls to mixer line */
981 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, Topology
, SrcLine
, NodesCount
, Nodes
);
982 if (Status
!= MM_STATUS_SUCCESS
)
989 *OutSrcLine
= SrcLine
;
991 return MM_STATUS_SUCCESS
;
995 MMixerAddMixerSourceLines(
996 IN PMIXER_CONTEXT MixerContext
,
997 IN OUT LPMIXER_INFO MixerInfo
,
998 IN PTOPOLOGY Topology
,
999 IN ULONG DestinationLineID
,
1000 IN ULONG LineTerminator
)
1002 PULONG AllNodes
, AllPins
, AllPinNodes
;
1003 ULONG AllNodesCount
, AllPinsCount
, AllPinNodesCount
;
1004 ULONG Index
, SubIndex
, PinId
, CurNode
, bConnected
;
1005 MIXER_STATUS Status
;
1006 LPMIXERLINE_EXT DstLine
, SrcLine
;
1008 /* get destination line */
1009 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineID
);
1012 /* allocate an array to store all nodes which are upstream of the line terminator */
1013 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllNodes
);
1015 /* check for success */
1016 if (Status
!= MM_STATUS_SUCCESS
)
1019 return MM_STATUS_NO_MEMORY
;
1022 /* allocate an array to store all nodes which are downstream of a particular pin */
1023 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllPinNodes
);
1025 /* allocate an array to store all pins which are upstream of this pin */
1026 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &AllPins
);
1028 /* check for success */
1029 if (Status
!= MM_STATUS_SUCCESS
)
1032 MixerContext
->Free(AllNodes
);
1033 return MM_STATUS_NO_MEMORY
;
1036 /* get all nodes which indirectly / directly connect to this node */
1038 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllNodesCount
, AllNodes
);
1040 /* get all pins which indirectly / directly connect to this node */
1042 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllPinsCount
, AllPins
);
1044 DPRINT1("LineTerminator %lu\n", LineTerminator
);
1045 DPRINT1("PinCount %lu\n", AllPinsCount
);
1046 DPRINT1("AllNodesCount %lu\n", AllNodesCount
);
1048 /* now construct the source lines which are attached to the destination line */
1049 Index
= AllPinsCount
;
1053 /* get current pin id */
1054 PinId
= AllPins
[Index
- 1];
1056 /* reset nodes count */
1057 AllPinNodesCount
= 0;
1059 /* now scan all nodes and add them to AllPinNodes array when they are connected to this pin */
1060 for(SubIndex
= 0; SubIndex
< AllNodesCount
; SubIndex
++)
1062 /* get current node index */
1063 CurNode
= AllNodes
[SubIndex
];
1065 if (CurNode
!= MAXULONG
&& CurNode
!= LineTerminator
)
1067 /* check if that node is connected in some way to the current pin */
1068 Status
= MMixerIsNodeConnectedToPin(MixerContext
, Topology
, CurNode
, PinId
, TRUE
, &bConnected
);
1070 if (Status
!= MM_STATUS_SUCCESS
)
1075 /* it is connected */
1076 AllPinNodes
[AllPinNodesCount
] = CurNode
;
1079 /* clear current index */
1080 AllNodes
[SubIndex
] = MAXULONG
;
1085 /* decrement pin index */
1088 if (AllPinNodesCount
)
1093 /* now build the mixer source line */
1094 Status
= MMixerBuildMixerSourceLine(MixerContext
, MixerInfo
, Topology
, PinId
, AllPinNodesCount
, AllPinNodes
, DestinationLineID
, &SrcLine
);
1096 if (Status
== MM_STATUS_SUCCESS
)
1098 /* insert into line list */
1099 InsertTailList(&MixerInfo
->LineList
, &SrcLine
->Entry
);
1101 /* increment destination line count */
1102 DstLine
->Line
.cConnections
++;
1104 DPRINT1("Adding PinId %lu AllPinNodesCount %lu to DestinationLine %lu\n", PinId
, AllPinNodesCount
, DestinationLineID
);
1105 for(TempIndex
= 0; TempIndex
< AllPinNodesCount
; TempIndex
++)
1106 DPRINT1("NodeIndex %lu\n", AllPinNodes
[TempIndex
]);
1113 DPRINT1("Discarding DestinationLineID %lu PinId %lu NO NODES!\n", DestinationLineID
, PinId
);
1119 return MM_STATUS_SUCCESS
;
1124 MMixerAddMixerControlsToDestinationLine(
1125 IN PMIXER_CONTEXT MixerContext
,
1126 IN OUT LPMIXER_INFO MixerInfo
,
1127 IN PTOPOLOGY Topology
,
1130 IN ULONG DestinationLineId
,
1131 OUT PULONG OutLineTerminator
)
1134 ULONG NodesCount
, LineTerminator
;
1135 MIXER_STATUS Status
;
1136 LPMIXERLINE_EXT DstLine
;
1138 /* allocate nodes index array */
1139 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
1141 /* check for success */
1142 if (Status
!= MM_STATUS_SUCCESS
)
1145 return MM_STATUS_NO_MEMORY
;
1148 /* get all destination line controls */
1149 Status
= MMixerCountMixerControls(MixerContext
, Topology
, PinId
, bInput
, TRUE
, &NodesCount
, Nodes
, &LineTerminator
);
1151 /* check for success */
1152 if (Status
!= MM_STATUS_SUCCESS
)
1154 /* failed to count controls */
1155 MixerContext
->Free(Nodes
);
1159 /* get destination mixer line */
1160 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineId
);
1167 /* add all nodes as mixer controls to the destination line */
1168 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, Topology
, DstLine
, NodesCount
, Nodes
);
1169 if (Status
!= MM_STATUS_SUCCESS
)
1171 /* failed to add controls */
1172 MixerContext
->Free(Nodes
);
1178 *OutLineTerminator
= LineTerminator
;
1185 MMixerApplyOutputFilterHack(
1186 IN PMIXER_CONTEXT MixerContext
,
1187 IN LPMIXER_DATA MixerData
,
1188 IN OUT PULONG PinsCount
,
1191 ULONG Count
= 0, Index
;
1192 MIXER_STATUS Status
;
1193 PKSPIN_PHYSICALCONNECTION Connection
;
1195 for(Index
= 0; Index
< *PinsCount
; Index
++)
1197 /* check if it has a physical connection */
1198 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Pins
[Index
], &Connection
);
1200 if (Status
== MM_STATUS_SUCCESS
)
1203 MixerContext
->Copy(&Pins
[Index
], &Pins
[Index
+ 1], (*PinsCount
- (Index
+ 1)) * sizeof(ULONG
));
1205 /* free physical connection */
1206 MixerContext
->Free(Connection
);
1208 /* decrement index */
1211 /* decrement pin count */
1226 MMixerHandlePhysicalConnection(
1227 IN PMIXER_CONTEXT MixerContext
,
1228 IN PMIXER_LIST MixerList
,
1229 IN LPMIXER_DATA MixerData
,
1230 IN OUT LPMIXER_INFO MixerInfo
,
1232 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
1234 MIXER_STATUS Status
;
1235 ULONG PinsCount
, LineTerminator
, DestinationLineID
;
1239 /* first try to open the connected filter */
1240 OutConnection
->SymbolicLinkName
[1] = L
'\\';
1241 MixerData
= MMixerGetDataByDeviceName(MixerList
, OutConnection
->SymbolicLinkName
);
1243 /* check if the linked connection is found */
1246 /* filter references invalid physical connection */
1247 return MM_STATUS_UNSUCCESSFUL
;
1250 DPRINT1("Name %S, Pin %lu bInput %lu\n", OutConnection
->SymbolicLinkName
, OutConnection
->Pin
, bInput
);
1252 if (MixerInfo
->hMixer
!= NULL
)
1254 /* dont replace mixer destination handles */
1255 DPRINT1("MixerInfo hDevice %p MixerData hDevice %p\n", MixerInfo
->hMixer
, MixerData
->hDevice
);
1256 ASSERT(MixerInfo
->hMixer
== MixerData
->hDevice
);
1259 /* store connected mixer handle */
1260 MixerInfo
->hMixer
= MixerData
->hDevice
;
1262 if (MixerData
->Topology
== NULL
)
1264 /* construct new topology */
1265 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1266 if (Status
!= MM_STATUS_SUCCESS
)
1268 /* failed to create topology */
1272 /* store topology */
1273 MixerData
->Topology
= Topology
;
1277 /* re-use existing topology */
1278 Topology
= MixerData
->Topology
;
1281 /* allocate pin index array which will hold all referenced pins */
1282 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1283 ASSERT(Status
== MM_STATUS_SUCCESS
);
1287 /* the mixer is an output mixer
1288 * find end pin of the node path
1291 Status
= MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext
, Topology
, OutConnection
->Pin
, FALSE
, &PinsCount
, Pins
);
1293 /* check for success */
1294 if (Status
!= MM_STATUS_SUCCESS
)
1296 /* failed to get end pin */
1297 MixerContext
->Free(Pins
);
1298 //MMixerFreeTopology(Topology);
1300 /* return error code */
1304 * some topologies do not have strict boundaries
1305 * WorkArround: remove all pin ids which have a physical connection
1306 * because bridge pins may belong to different render paths
1308 MMixerApplyOutputFilterHack(MixerContext
, MixerData
, &PinsCount
, Pins
);
1311 ASSERT(PinsCount
!= 0);
1312 ASSERT(PinsCount
== 1);
1314 /* create destination line */
1315 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, Pins
[0], bInput
);
1317 /* calculate destination line id */
1318 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1320 if (Status
!= MM_STATUS_SUCCESS
)
1322 /* failed to build destination line */
1323 MixerContext
->Free(Pins
);
1325 /* return error code */
1329 /* add mixer controls to destination line */
1330 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, Topology
, Pins
[0], bInput
, DestinationLineID
, &LineTerminator
);
1332 if (Status
== MM_STATUS_SUCCESS
)
1334 /* now add the rest of the source lines */
1335 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, Topology
, DestinationLineID
, LineTerminator
);
1340 /* calculate destination line id */
1341 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1343 /* add mixer controls */
1344 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, Topology
, OutConnection
->Pin
, bInput
, DestinationLineID
, &LineTerminator
);
1346 if (Status
== MM_STATUS_SUCCESS
)
1348 /* now add the rest of the source lines */
1349 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, Topology
, DestinationLineID
, LineTerminator
);
1357 MMixerInitializeFilter(
1358 IN PMIXER_CONTEXT MixerContext
,
1359 IN PMIXER_LIST MixerList
,
1360 IN LPMIXER_DATA MixerData
,
1361 IN LPMIXER_INFO MixerInfo
,
1362 IN PTOPOLOGY Topology
,
1364 IN ULONG bInputMixer
,
1365 IN OUT LPMIXER_INFO
* OutMixerInfo
)
1368 MIXER_STATUS Status
;
1369 PKSPIN_PHYSICALCONNECTION OutConnection
;
1372 ULONG NewMixerInfo
= FALSE
;
1374 if (MixerInfo
== NULL
)
1376 /* allocate a mixer info struct */
1377 MixerInfo
= (LPMIXER_INFO
) MixerContext
->Alloc(sizeof(MIXER_INFO
));
1381 return MM_STATUS_NO_MEMORY
;
1384 /* new mixer info */
1385 NewMixerInfo
= TRUE
;
1387 /* intialize mixer caps */
1388 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; /* FIXME */
1389 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; /* FIXME */
1390 MixerInfo
->MixCaps
.vDriverVersion
= 1; /* FIXME */
1391 MixerInfo
->MixCaps
.fdwSupport
= 0;
1392 MixerInfo
->MixCaps
.cDestinations
= 0;
1394 /* get mixer name */
1395 MMixerGetDeviceName(MixerContext
, MixerInfo
->MixCaps
.szPname
, MixerData
->hDeviceInterfaceKey
);
1397 /* initialize line list */
1398 InitializeListHead(&MixerInfo
->LineList
);
1399 InitializeListHead(&MixerInfo
->EventList
);
1402 /* store mixer info */
1403 *OutMixerInfo
= MixerInfo
;
1405 /* now allocate an array which will receive the indices of the pin
1406 * which has a ADC / DAC nodetype in its path
1408 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1409 ASSERT(Status
== MM_STATUS_SUCCESS
);
1413 /* now get all sink / source pins, which are attached to the ADC / DAC node
1414 * For sink pins (wave out) search up stream
1415 * For source pins (wave in) search down stream
1416 * The search direction is always the opposite of the current mixer type
1419 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, !bInputMixer
, &PinsFound
, Pins
);
1421 /* if there is no pin found, we have a broken topology */
1422 ASSERT(PinsFound
!= 0);
1424 /* now create a wave info struct */
1425 Status
= MMixerInitializeWaveInfo(MixerContext
, MixerList
, MixerData
, MixerInfo
->MixCaps
.szPname
, bInputMixer
, PinsFound
, Pins
);
1426 if (Status
!= MM_STATUS_SUCCESS
)
1428 /* failed to create wave info struct */
1429 MixerContext
->Free(MixerInfo
);
1430 MixerContext
->Free(Pins
);
1436 /* pre create the mixer destination line for input mixers */
1437 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, Pins
[0], bInputMixer
);
1439 if (Status
!= MM_STATUS_SUCCESS
)
1441 /* failed to create mixer destination line */
1447 /* now get the bridge pin which is at the end of node path
1448 * For sink pins (wave out) search down stream
1449 * For source pins (wave in) search up stream
1451 MixerContext
->Free(Pins
);
1452 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1453 ASSERT(Status
== MM_STATUS_SUCCESS
);
1456 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bInputMixer
, &PinsFound
, Pins
);
1458 /* if there is no pin found, we have a broken topology */
1459 ASSERT(PinsFound
!= 0);
1461 /* there should be exactly one bridge pin */
1462 ASSERT(PinsFound
== 1);
1464 DPRINT("BridgePin %lu bInputMixer %lu\n", Pins
[0], bInputMixer
);
1466 /* does the pin have a physical connection */
1467 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Pins
[0], &OutConnection
);
1469 if (Status
== MM_STATUS_SUCCESS
)
1471 /* topology on the topoloy filter */
1472 Status
= MMixerHandlePhysicalConnection(MixerContext
, MixerList
, MixerData
, MixerInfo
, bInputMixer
, OutConnection
);
1474 /* free physical connection data */
1475 MixerContext
->Free(OutConnection
);
1480 * handle drivers which expose their topology on the same filter
1483 MixerInfo
->hMixer
= MixerData
->hDevice
;
1487 MixerContext
->Free(Pins
);
1492 InsertHeadList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1493 /* increment mixer count */
1494 MixerList
->MixerListCount
++;
1503 IN PMIXER_CONTEXT MixerContext
,
1504 IN PMIXER_LIST MixerList
,
1505 IN LPMIXER_DATA MixerData
,
1506 IN PULONG DeviceCount
)
1508 MIXER_STATUS Status
;
1511 LPMIXER_INFO MixerInfo
= NULL
;
1513 /* check if topology has already been built */
1514 if (MixerData
->Topology
== NULL
)
1516 /* build topology */
1517 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1519 if (Status
!= MM_STATUS_SUCCESS
)
1521 /* failed to build topology */
1525 /* store topology */
1526 MixerData
->Topology
= Topology
;
1530 /* re-use topology */
1531 Topology
= MixerData
->Topology
;
1534 /* check if the filter has an wave out node */
1535 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_DAC
);
1536 if (NodeIndex
!= MAXULONG
)
1539 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, NULL
, Topology
, NodeIndex
, FALSE
, &MixerInfo
);
1541 /* check for success */
1542 if (Status
== MM_STATUS_SUCCESS
)
1544 /* increment mixer count */
1549 /* reset mixer info in case of error */
1554 /* check if the filter has an wave in node */
1555 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_ADC
);
1556 if (NodeIndex
!= MAXULONG
)
1559 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, MixerInfo
, Topology
, NodeIndex
, TRUE
, &MixerInfo
);
1561 /* check for success */
1562 if (Status
== MM_STATUS_SUCCESS
)
1564 /* increment mixer count */
1570 /* TODO: handle alternative mixer types + apply hacks for Wave source line */
1572 /* activate midi devices */
1573 MMixerInitializeMidiForFilter(MixerContext
, MixerList
, MixerData
, Topology
);
1582 IN PMIXER_CONTEXT MixerContext
,
1583 IN OUT LPMIXER_INFO MixerInfo
,
1584 IN PVOID MixerEventContext
,
1585 IN PMIXER_EVENT MixerEventRoutine
)
1587 //KSE_NODE Property;
1588 PEVENT_NOTIFICATION_ENTRY EventData
;
1589 //ULONG BytesReturned;
1590 //MIXER_STATUS Status;
1592 EventData
= (PEVENT_NOTIFICATION_ENTRY
)MixerContext
->AllocEventData(sizeof(EVENT_NOTIFICATION_ENTRY
));
1595 /* not enough memory */
1596 return MM_STATUS_NO_MEMORY
;
1601 Property
.Event
.Set
= KSEVENTSETID_AudioControlChange
;
1602 Property
.Event
.Flags
= KSEVENT_TYPE_TOPOLOGY
|KSEVENT_TYPE_ENABLE
;
1603 Property
.Event
.Id
= KSEVENT_CONTROL_CHANGE
;
1605 Property
.NodeId
= NodeId
;
1606 Property
.Reserved
= 0;
1608 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSP_NODE
), (PVOID
)EventData
, sizeof(KSEVENTDATA
), &BytesReturned
);
1609 if (Status
!= MM_STATUS_SUCCESS
)
1611 /* failed to add event */
1612 MixerContext
->FreeEventData(EventData
);
1617 /* initialize notification entry */
1618 EventData
->MixerEventContext
= MixerEventContext
;
1619 EventData
->MixerEventRoutine
;
1622 InsertTailList(&MixerInfo
->EventList
, &EventData
->Entry
);
1623 return MM_STATUS_SUCCESS
;