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; /* FIXME */
58 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
60 MixerControl
->Bounds
.dwMinimum
= 0;
61 MixerControl
->Bounds
.dwMaximum
= 1;
63 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
65 MixerControl
->Bounds
.dwMinimum
= 0;
66 MixerControl
->Bounds
.dwMaximum
= 0xFFFF;
67 MixerControl
->Metrics
.cSteps
= 0xC0; /* FIXME */
70 /* setup request to retrieve name */
71 Node
.NodeId
= NodeIndex
;
72 Node
.Property
.Id
= KSPROPERTY_TOPOLOGY_NAME
;
73 Node
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
74 Node
.Property
.Set
= KSPROPSETID_Topology
;
77 /* get node name size */
78 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), NULL
, 0, &BytesReturned
);
80 if (Status
== MM_STATUS_MORE_ENTRIES
)
82 ASSERT(BytesReturned
!= 0);
83 Name
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
86 /* not enough memory */
87 return MM_STATUS_NO_MEMORY
;
91 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), (LPVOID
)Name
, BytesReturned
, &BytesReturned
);
93 if (Status
== MM_STATUS_SUCCESS
)
95 MixerContext
->Copy(MixerControl
->szShortName
, Name
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
96 MixerControl
->szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
98 MixerContext
->Copy(MixerControl
->szName
, Name
, (min(MIXER_LONG_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
99 MixerControl
->szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
102 /* free name buffer */
103 MixerContext
->Free(Name
);
106 MixerInfo
->ControlId
++;
108 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUX
)
110 KSNODEPROPERTY Property
;
113 /* setup the request */
114 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY
));
116 Property
.NodeId
= NodeIndex
;
117 Property
.Property
.Id
= KSPROPERTY_AUDIO_MUX_SOURCE
;
118 Property
.Property
.Flags
= KSPROPERTY_TYPE_SET
;
119 Property
.Property
.Set
= KSPROPSETID_Audio
;
121 /* get node volume level info */
122 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY
), (PVOID
)&PinId
, sizeof(ULONG
), &BytesReturned
);
124 DPRINT1("Status %x NodeIndex %u PinId %u\n", Status
, NodeIndex
, PinId
);
128 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
130 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
132 PKSPROPERTY_DESCRIPTION Desc
;
133 PKSPROPERTY_MEMBERSHEADER Members
;
134 PKSPROPERTY_STEPPING_LONG Range
;
136 Length
= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) + sizeof(KSPROPERTY_STEPPING_LONG
);
137 Desc
= (PKSPROPERTY_DESCRIPTION
)MixerContext
->Alloc(Length
);
140 /* setup the request */
141 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
143 Property
.NodeProperty
.NodeId
= NodeIndex
;
144 Property
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
145 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
;
146 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
148 /* get node volume level info */
149 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), Desc
, Length
, &BytesReturned
);
151 if (Status
== MM_STATUS_SUCCESS
)
153 LPMIXERVOLUME_DATA VolumeData
;
154 ULONG Steps
, MaxRange
, Index
;
157 Members
= (PKSPROPERTY_MEMBERSHEADER
)(Desc
+ 1);
158 Range
= (PKSPROPERTY_STEPPING_LONG
)(Members
+ 1);
160 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
);
162 MaxRange
= Range
->Bounds
.UnsignedMaximum
- Range
->Bounds
.UnsignedMinimum
;
167 VolumeData
= (LPMIXERVOLUME_DATA
)MixerContext
->Alloc(sizeof(MIXERVOLUME_DATA
));
169 return MM_STATUS_NO_MEMORY
;
171 Steps
= MaxRange
/ Range
->SteppingDelta
+ 1;
173 /* store mixer control info there */
174 VolumeData
->Header
.dwControlID
= MixerControl
->dwControlID
;
175 VolumeData
->SignedMaximum
= Range
->Bounds
.SignedMaximum
;
176 VolumeData
->SignedMinimum
= Range
->Bounds
.SignedMinimum
;
177 VolumeData
->SteppingDelta
= Range
->SteppingDelta
;
178 VolumeData
->ValuesCount
= Steps
;
179 VolumeData
->InputSteppingDelta
= 0x10000 / Steps
;
181 VolumeData
->Values
= (PLONG
)MixerContext
->Alloc(sizeof(LONG
) * Steps
);
182 if (!VolumeData
->Values
)
184 MixerContext
->Free(Desc
);
185 MixerContext
->Free(VolumeData
);
186 return MM_STATUS_NO_MEMORY
;
189 Value
= Range
->Bounds
.SignedMinimum
;
190 for(Index
= 0; Index
< Steps
; Index
++)
192 VolumeData
->Values
[Index
] = Value
;
193 Value
+= Range
->SteppingDelta
;
195 InsertTailList(&MixerLine
->LineControlsExtraData
, &VolumeData
->Header
.Entry
);
198 MixerContext
->Free(Desc
);
201 DPRINT("Status %x Name %S\n", Status
, MixerControl
->szName
);
202 return MM_STATUS_SUCCESS
;
206 MMixerCreateDestinationLine(
207 IN PMIXER_CONTEXT MixerContext
,
208 IN LPMIXER_INFO MixerInfo
,
209 IN ULONG bInputMixer
,
212 LPMIXERLINE_EXT DestinationLine
;
214 /* allocate a mixer destination line */
215 DestinationLine
= (LPMIXERLINE_EXT
) MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
219 return MM_STATUS_NO_MEMORY
;
222 /* initialize mixer destination line */
223 DestinationLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
224 DestinationLine
->Line
.dwSource
= MAXULONG
;
225 DestinationLine
->Line
.dwLineID
= MixerInfo
->MixCaps
.cDestinations
+ DESTINATION_LINE
;
226 DestinationLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
;
227 DestinationLine
->Line
.dwUser
= 0;
228 DestinationLine
->Line
.dwDestination
= MixerInfo
->MixCaps
.cDestinations
;
229 DestinationLine
->Line
.dwComponentType
= (bInputMixer
== 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
);
230 DestinationLine
->Line
.cChannels
= 2; /* FIXME */
234 MixerContext
->Copy(DestinationLine
->Line
.szShortName
, LineName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
235 DestinationLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
237 MixerContext
->Copy(DestinationLine
->Line
.szName
, LineName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(LineName
)+1)) * sizeof(WCHAR
));
238 DestinationLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
242 DestinationLine
->Line
.Target
.dwType
= (bInputMixer
== 0 ? MIXERLINE_TARGETTYPE_WAVEOUT
: MIXERLINE_TARGETTYPE_WAVEIN
);
243 DestinationLine
->Line
.Target
.dwDeviceID
= 0; //FIXME
244 DestinationLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
245 DestinationLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
246 DestinationLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
248 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == 0);
249 wcscpy(DestinationLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
251 /* initialize extra line */
252 InitializeListHead(&DestinationLine
->LineControlsExtraData
);
254 /* insert into mixer info */
255 InsertTailList(&MixerInfo
->LineList
, &DestinationLine
->Entry
);
257 /* increment destination count */
258 MixerInfo
->MixCaps
.cDestinations
++;
261 return MM_STATUS_SUCCESS
;
266 IN PMIXER_CONTEXT MixerContext
,
267 IN LPMIXER_INFO MixerInfo
,
269 IN OUT LPWSTR
* OutBuffer
)
279 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
280 Pin
.Property
.Set
= KSPROPSETID_Pin
;
281 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
283 /* try get pin name size */
284 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
286 /* check if buffer overflowed */
287 if (Status
== MM_STATUS_MORE_ENTRIES
)
289 /* allocate buffer */
290 Buffer
= (LPWSTR
)MixerContext
->Alloc(BytesReturned
);
294 return MM_STATUS_NO_MEMORY
;
297 /* try get pin name */
298 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Buffer
, BytesReturned
, &BytesReturned
);
299 if (Status
!= MM_STATUS_SUCCESS
)
301 /* failed to get pin name */
302 MixerContext
->Free((PVOID
)Buffer
);
306 /* successfully obtained pin name */
308 return MM_STATUS_SUCCESS
;
311 /* failed to get pin name */
316 MMixerBuildMixerDestinationLine(
317 IN PMIXER_CONTEXT MixerContext
,
318 IN OUT LPMIXER_INFO MixerInfo
,
325 /* try get pin name */
326 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, PinId
, &PinName
);
327 if (Status
== MM_STATUS_SUCCESS
)
329 /* create mixer destination line */
331 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, PinName
);
334 MixerContext
->Free(PinName
);
338 /* create mixer destination line unlocalized */
339 Status
= MMixerCreateDestinationLine(MixerContext
, MixerInfo
, bInput
, L
"No Name");
347 IN PMIXER_CONTEXT MixerContext
,
348 IN LPMIXER_DATA MixerData
,
349 OUT PTOPOLOGY
* OutTopology
)
352 PKSMULTIPLE_ITEM NodeTypes
= NULL
;
353 PKSMULTIPLE_ITEM NodeConnections
= NULL
;
356 if (MixerData
->Topology
)
358 /* re-use existing topology */
359 *OutTopology
= MixerData
->Topology
;
361 return MM_STATUS_SUCCESS
;
364 /* get connected filter pin count */
365 PinsCount
= MMixerGetFilterPinCount(MixerContext
, MixerData
->hDevice
);
369 /* referenced filter does not have any pins */
370 return MM_STATUS_UNSUCCESSFUL
;
373 /* get topology node types */
374 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
375 if (Status
!= MM_STATUS_SUCCESS
)
377 /* failed to get topology node types */
381 /* get topology connections */
382 Status
= MMixerGetFilterTopologyProperty(MixerContext
, MixerData
->hDevice
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
383 if (Status
!= MM_STATUS_SUCCESS
)
385 /* failed to get topology connections */
386 MixerContext
->Free(NodeTypes
);
390 /* create a topology */
391 Status
= MMixerCreateTopology(MixerContext
, PinsCount
, NodeConnections
, NodeTypes
, OutTopology
);
393 /* free node types & connections */
394 MixerContext
->Free(NodeConnections
);
395 MixerContext
->Free(NodeTypes
);
397 if (Status
== MM_STATUS_SUCCESS
)
399 /* store topology object */
400 MixerData
->Topology
= *OutTopology
;
408 MMixerCountMixerControls(
409 IN PMIXER_CONTEXT MixerContext
,
410 IN PTOPOLOGY Topology
,
412 IN ULONG bInputMixer
,
414 OUT PULONG OutNodesCount
,
416 OUT PULONG OutLineTerminator
)
419 ULONG NodesCount
, NodeIndex
, Count
, bTerminator
;
422 /* allocate an array to store all nodes which are upstream of this pin */
423 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
425 if (Status
!= MM_STATUS_SUCCESS
)
428 return STATUS_NO_MEMORY
;
431 /* mark result array as zero */
435 MMixerGetNextNodesFromPinIndex(MixerContext
, Topology
, PinId
, bUpStream
, &NodesCount
, Nodes
);
437 /* assume no topology split before getting line terminator */
438 ASSERT(NodesCount
== 1);
441 NodeIndex
= Nodes
[0];
446 /* check if the node is a terminator */
447 MMixerIsNodeTerminator(Topology
, NodeIndex
, &bTerminator
);
451 /* found terminator */
454 /* add mux source for source destination line */
455 OutNodes
[Count
] = NodeIndex
;
462 OutNodes
[Count
] = NodeIndex
;
464 /* increment node count */
467 /* get next nodes upstream */
468 MMixerGetNextNodesFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bUpStream
, &NodesCount
, Nodes
);
470 /* assume there is a node connected */
471 ASSERT(NodesCount
!= 0);
472 ASSERT(NodesCount
== 1);
474 /* use first index */
475 NodeIndex
= Nodes
[0];
479 /* free node index */
480 MixerContext
->Free(Nodes
);
482 /* store nodes count */
483 *OutNodesCount
= Count
;
485 /* store line terminator */
486 *OutLineTerminator
= NodeIndex
;
489 return MM_STATUS_SUCCESS
;
493 MMixerGetChannelCountEnhanced(
494 IN PMIXER_CONTEXT MixerContext
,
495 IN LPMIXER_INFO MixerInfo
,
497 OUT PULONG MaxChannels
)
499 KSPROPERTY_DESCRIPTION Description
;
500 PKSPROPERTY_DESCRIPTION NewDescription
;
501 PKSPROPERTY_MEMBERSHEADER Header
;
506 /* try #1 obtain it via description */
507 Request
.NodeId
= NodeId
;
508 Request
.Reserved
= 0;
509 Request
.Property
.Set
= KSPROPSETID_Audio
;
510 Request
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
| KSPROPERTY_TYPE_TOPOLOGY
;
511 Request
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
514 /* get description */
515 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_NODE
), (PVOID
)&Description
, sizeof(KSPROPERTY_DESCRIPTION
), &BytesReturned
);
516 if (Status
== MM_STATUS_SUCCESS
)
518 if (Description
.DescriptionSize
>= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) && (Description
.MembersListCount
> 0))
520 /* allocate new description */
521 NewDescription
= MixerContext
->Alloc(Description
.DescriptionSize
);
525 /* not enough memory */
526 return MM_STATUS_NO_MEMORY
;
529 /* get description */
530 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_NODE
), (PVOID
)NewDescription
, Description
.DescriptionSize
, &BytesReturned
);
531 if (Status
== MM_STATUS_SUCCESS
)
534 Header
= (PKSPROPERTY_MEMBERSHEADER
)(NewDescription
+ 1);
536 if (Header
->Flags
& KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL
)
538 /* found enhanced flag */
539 ASSERT(Header
->MembersCount
> 1);
541 /* store channel count */
542 *MaxChannels
= Header
->MembersCount
;
544 /* free description */
545 MixerContext
->Free(NewDescription
);
548 return MM_STATUS_SUCCESS
;
552 /* free description */
553 MixerContext
->Free(NewDescription
);
557 /* failed to get channel count enhanced */
558 return MM_STATUS_UNSUCCESSFUL
;
562 MMixerGetChannelCountLegacy(
563 IN PMIXER_CONTEXT MixerContext
,
564 IN LPMIXER_INFO MixerInfo
,
566 OUT PULONG MaxChannels
)
570 KSNODEPROPERTY_AUDIO_CHANNEL Channel
;
574 Channel
.Reserved
= 0;
575 Channel
.NodeProperty
.NodeId
= NodeId
;
576 Channel
.NodeProperty
.Reserved
= 0;
577 Channel
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_TOPOLOGY
;
578 Channel
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
580 Channel
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
584 /* get channel volume */
585 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Channel
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), (PVOID
)&Volume
, sizeof(LONG
), &BytesReturned
);
586 if (Status
!= MM_STATUS_SUCCESS
)
589 /* increment channel count */
594 /* store channel count */
595 *MaxChannels
= Channel
.Channel
;
600 MMixerGetMaxChannelsForNode(
601 IN PMIXER_CONTEXT MixerContext
,
602 IN LPMIXER_INFO MixerInfo
,
604 OUT PULONG MaxChannels
)
608 /* try to get it enhanced */
609 Status
= MMixerGetChannelCountEnhanced(MixerContext
, MixerInfo
, NodeId
, MaxChannels
);
611 if (Status
!= MM_STATUS_SUCCESS
)
613 /* get it old-fashioned way */
614 MMixerGetChannelCountLegacy(MixerContext
, MixerInfo
, NodeId
, MaxChannels
);
619 MMixerAddMixerControlsToMixerLineByNodeIndexArray(
620 IN PMIXER_CONTEXT MixerContext
,
621 IN LPMIXER_INFO MixerInfo
,
622 IN PTOPOLOGY Topology
,
623 IN OUT LPMIXERLINE_EXT DstLine
,
627 ULONG Index
, Count
, bReserved
;
632 /* store nodes array */
633 DstLine
->NodeIds
= Nodes
;
635 /* allocate MIXERCONTROLSW array */
636 DstLine
->LineControls
= MixerContext
->Alloc(NodesCount
* sizeof(MIXERCONTROLW
));
638 if (!DstLine
->LineControls
)
641 return MM_STATUS_NO_MEMORY
;
644 /* initialize control count */
647 for(Index
= 0; Index
< NodesCount
; Index
++)
649 /* check if the node has already been reserved to a line */
650 MMixerIsTopologyNodeReserved(Topology
, Nodes
[Index
], &bReserved
);
654 /* node is already used, skip it */
658 /* set node status as used */
659 MMixerSetTopologyNodeReserved(Topology
, Nodes
[Index
]);
661 /* query node type */
662 NodeType
= MMixerGetNodeTypeFromTopology(Topology
, Nodes
[Index
]);
664 if (IsEqualGUIDAligned(NodeType
, &KSNODETYPE_VOLUME
))
666 /* calculate maximum channel count for node */
667 MMixerGetMaxChannelsForNode(MixerContext
, MixerInfo
, Nodes
[Index
], &MaxChannels
);
669 DPRINT("NodeId %lu MaxChannels %lu Line %S Id %lu\n", Nodes
[Index
], MaxChannels
, DstLine
->Line
.szName
, DstLine
->Line
.dwLineID
);
670 /* calculate maximum channels */
671 DstLine
->Line
.cChannels
= min(DstLine
->Line
.cChannels
, MaxChannels
);
675 /* now add the mixer control */
676 Status
= MMixerAddMixerControl(MixerContext
, MixerInfo
, Topology
, Nodes
[Index
], DstLine
, &DstLine
->LineControls
[Count
]);
678 if (Status
== MM_STATUS_SUCCESS
)
680 /* increment control count */
685 /* store control count */
686 DstLine
->Line
.cControls
= Count
;
689 return MM_STATUS_SUCCESS
;
693 MMixerGetComponentAndTargetType(
694 IN PMIXER_CONTEXT MixerContext
,
695 IN OUT LPMIXER_INFO MixerInfo
,
697 OUT PULONG ComponentType
,
698 OUT PULONG TargetType
)
700 KSPIN_DATAFLOW DataFlow
;
701 KSPIN_COMMUNICATION Communication
;
706 BOOLEAN BridgePin
= FALSE
;
707 PKSPIN_PHYSICALCONNECTION Connection
;
709 /* first dataflow type */
710 Status
= MMixerGetPinDataFlowAndCommunication(MixerContext
, MixerInfo
->hMixer
, PinId
, &DataFlow
, &Communication
);
712 if (Status
!= MM_STATUS_SUCCESS
)
714 /* failed to get dataflow */
718 /* now get pin category guid */
719 Request
.PinId
= PinId
;
720 Request
.Reserved
= 0;
721 Request
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
722 Request
.Property
.Set
= KSPROPSETID_Pin
;
723 Request
.Property
.Id
= KSPROPERTY_PIN_CATEGORY
;
726 /* get pin category */
727 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_PROPERTY
, (PVOID
)&Request
, sizeof(KSP_PIN
), &Guid
, sizeof(GUID
), &BytesReturned
);
728 if (Status
!= MM_STATUS_SUCCESS
)
730 /* failed to get dataflow */
734 /* check if it has a physical connection */
735 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerInfo
->hMixer
, PinId
, &Connection
);
736 if (Status
== MM_STATUS_SUCCESS
)
738 /* pin is a brige pin */
741 /* free physical connection */
742 MixerContext
->Free(Connection
);
745 if (DataFlow
== KSPIN_DATAFLOW_IN
)
747 if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_MICROPHONE
) ||
748 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DESKTOP_MICROPHONE
))
750 /* type microphone */
751 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
752 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
;
754 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_LEGACY_AUDIO_CONNECTOR
) ||
755 IsEqualGUIDAligned(&Guid
, &KSCATEGORY_AUDIO
) ||
756 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPEAKER
))
759 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
760 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT
;
762 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_CD_PLAYER
))
765 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
766 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC
;
768 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SYNTHESIZER
))
770 /* type synthesizer */
771 *TargetType
= MIXERLINE_TARGETTYPE_MIDIOUT
;
772 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER
;
774 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_LINE_CONNECTOR
))
777 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
778 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_LINE
;
780 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_TELEPHONE
) ||
781 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_PHONE_LINE
) ||
782 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DOWN_LINE_PHONE
))
785 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
786 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE
;
788 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ANALOG_CONNECTOR
))
792 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
794 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
796 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_ANALOG
;
798 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPDIF_INTERFACE
))
802 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
804 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
806 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_DIGITAL
;
811 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
812 *ComponentType
= MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED
;
813 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId
, BridgePin
);
818 if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPEAKER
) ||
819 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DESKTOP_SPEAKER
) ||
820 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ROOM_SPEAKER
) ||
821 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_COMMUNICATION_SPEAKER
))
824 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
825 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
827 else if (IsEqualGUIDAligned(&Guid
, &KSCATEGORY_AUDIO
) ||
828 IsEqualGUIDAligned(&Guid
, &PINNAME_CAPTURE
))
831 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
832 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
834 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_HEADPHONES
) ||
835 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO
))
837 /* type head phones */
838 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
839 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_HEADPHONES
;
841 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_TELEPHONE
) ||
842 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_PHONE_LINE
) ||
843 IsEqualGUIDAligned(&Guid
, &KSNODETYPE_DOWN_LINE_PHONE
))
846 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
847 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_TELEPHONE
;
849 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_ANALOG_CONNECTOR
))
854 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
855 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
859 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
860 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
863 else if (IsEqualGUIDAligned(&Guid
, &KSNODETYPE_SPDIF_INTERFACE
))
868 *TargetType
= MIXERLINE_TARGETTYPE_WAVEOUT
;
869 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
;
873 *TargetType
= MIXERLINE_TARGETTYPE_WAVEIN
;
874 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
880 *TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
881 *ComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
882 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId
, BridgePin
);
887 return MM_STATUS_SUCCESS
;
891 MMixerBuildMixerSourceLine(
892 IN PMIXER_CONTEXT MixerContext
,
893 IN OUT LPMIXER_INFO MixerInfo
,
894 IN PTOPOLOGY Topology
,
898 IN ULONG DestinationLineID
,
899 OUT LPMIXERLINE_EXT
* OutSrcLine
)
901 LPMIXERLINE_EXT SrcLine
, DstLine
;
904 ULONG ComponentType
, TargetType
;
906 /* get component and target type */
907 Status
= MMixerGetComponentAndTargetType(MixerContext
, MixerInfo
, PinId
, &ComponentType
, &TargetType
);
908 if (Status
!= MM_STATUS_SUCCESS
)
910 /* failed to get component status */
911 TargetType
= MIXERLINE_TARGETTYPE_UNDEFINED
;
912 ComponentType
= MIXERLINE_COMPONENTTYPE_DST_UNDEFINED
;
915 /* construct source line */
916 SrcLine
= (LPMIXERLINE_EXT
)MixerContext
->Alloc(sizeof(MIXERLINE_EXT
));
921 return MM_STATUS_NO_MEMORY
;
924 /* get destination line */
925 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineID
);
928 /* initialize mixer src line */
929 SrcLine
->hDevice
= MixerInfo
->hMixer
;
930 SrcLine
->PinId
= PinId
;
931 SrcLine
->NodeIds
= Nodes
;
933 /* initialize mixer line */
934 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
935 SrcLine
->Line
.dwDestination
= MixerInfo
->MixCaps
.cDestinations
-1;
936 SrcLine
->Line
.dwSource
= DstLine
->Line
.cConnections
;
937 SrcLine
->Line
.dwLineID
= (DstLine
->Line
.cConnections
* SOURCE_LINE
)+ (MixerInfo
->MixCaps
.cDestinations
-1);
938 SrcLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
| MIXERLINE_LINEF_SOURCE
;
939 SrcLine
->Line
.dwComponentType
= ComponentType
;
940 SrcLine
->Line
.dwUser
= 0;
941 SrcLine
->Line
.cChannels
= DstLine
->Line
.cChannels
;
942 SrcLine
->Line
.cConnections
= 0;
943 SrcLine
->Line
.Target
.dwType
= TargetType
;
944 SrcLine
->Line
.Target
.dwDeviceID
= DstLine
->Line
.Target
.dwDeviceID
;
945 SrcLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
946 SrcLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
947 SrcLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
948 InitializeListHead(&SrcLine
->LineControlsExtraData
);
951 ASSERT(MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] == L
'\0');
952 wcscpy(SrcLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
955 Status
= MMixerGetPinName(MixerContext
, MixerInfo
, PinId
, &PinName
);
957 if (Status
== MM_STATUS_SUCCESS
)
959 /* store pin name as line name */
960 MixerContext
->Copy(SrcLine
->Line
.szShortName
, PinName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
961 SrcLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
963 MixerContext
->Copy(SrcLine
->Line
.szName
, PinName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
964 SrcLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
966 /* free pin name buffer */
967 MixerContext
->Free(PinName
);
970 /* add the controls to mixer line */
971 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, Topology
, SrcLine
, NodesCount
, Nodes
);
972 if (Status
!= MM_STATUS_SUCCESS
)
979 *OutSrcLine
= SrcLine
;
981 return MM_STATUS_SUCCESS
;
985 MMixerAddMixerSourceLines(
986 IN PMIXER_CONTEXT MixerContext
,
987 IN OUT LPMIXER_INFO MixerInfo
,
988 IN PTOPOLOGY Topology
,
989 IN ULONG DestinationLineID
,
990 IN ULONG LineTerminator
)
992 PULONG AllNodes
, AllPins
, AllPinNodes
;
993 ULONG AllNodesCount
, AllPinsCount
, AllPinNodesCount
;
994 ULONG Index
, SubIndex
, PinId
, CurNode
, bConnected
;
996 LPMIXERLINE_EXT DstLine
, SrcLine
;
998 /* get destination line */
999 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineID
);
1002 /* allocate an array to store all nodes which are upstream of the line terminator */
1003 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllNodes
);
1005 /* check for success */
1006 if (Status
!= MM_STATUS_SUCCESS
)
1009 return MM_STATUS_NO_MEMORY
;
1012 /* allocate an array to store all nodes which are downstream of a particular pin */
1013 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &AllPinNodes
);
1015 /* allocate an array to store all pins which are upstream of this pin */
1016 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &AllPins
);
1018 /* check for success */
1019 if (Status
!= MM_STATUS_SUCCESS
)
1022 MixerContext
->Free(AllNodes
);
1023 return MM_STATUS_NO_MEMORY
;
1026 /* get all nodes which indirectly / directly connect to this node */
1028 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllNodesCount
, AllNodes
);
1030 /* get all pins which indirectly / directly connect to this node */
1032 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, LineTerminator
, TRUE
, &AllPinsCount
, AllPins
);
1034 DPRINT1("LineTerminator %lu\n", LineTerminator
);
1035 DPRINT1("PinCount %lu\n", AllPinsCount
);
1036 DPRINT1("AllNodesCount %lu\n", AllNodesCount
);
1038 /* now construct the source lines which are attached to the destination line */
1039 Index
= AllPinsCount
;
1043 /* get current pin id */
1044 PinId
= AllPins
[Index
- 1];
1046 /* reset nodes count */
1047 AllPinNodesCount
= 0;
1049 /* now scan all nodes and add them to AllPinNodes array when they are connected to this pin */
1050 for(SubIndex
= 0; SubIndex
< AllNodesCount
; SubIndex
++)
1052 /* get current node index */
1053 CurNode
= AllNodes
[SubIndex
];
1055 if (CurNode
!= MAXULONG
&& CurNode
!= LineTerminator
)
1057 /* check if that node is connected in some way to the current pin */
1058 Status
= MMixerIsNodeConnectedToPin(MixerContext
, Topology
, CurNode
, PinId
, TRUE
, &bConnected
);
1060 if (Status
!= MM_STATUS_SUCCESS
)
1065 /* it is connected */
1066 AllPinNodes
[AllPinNodesCount
] = CurNode
;
1069 /* clear current index */
1070 AllNodes
[SubIndex
] = MAXULONG
;
1075 /* decrement pin index */
1078 if (AllPinNodesCount
)
1083 /* now build the mixer source line */
1084 Status
= MMixerBuildMixerSourceLine(MixerContext
, MixerInfo
, Topology
, PinId
, AllPinNodesCount
, AllPinNodes
, DestinationLineID
, &SrcLine
);
1086 if (Status
== MM_STATUS_SUCCESS
)
1088 /* insert into line list */
1089 InsertTailList(&MixerInfo
->LineList
, &SrcLine
->Entry
);
1091 /* increment destination line count */
1092 DstLine
->Line
.cConnections
++;
1094 DPRINT1("Adding PinId %lu AllPinNodesCount %lu to DestinationLine %lu\n", PinId
, AllPinNodesCount
, DestinationLineID
);
1095 for(TempIndex
= 0; TempIndex
< AllPinNodesCount
; TempIndex
++)
1096 DPRINT1("NodeIndex %lu\n", AllPinNodes
[TempIndex
]);
1103 DPRINT1("Discarding DestinationLineID %lu PinId %lu NO NODES!\n", DestinationLineID
, PinId
);
1109 return MM_STATUS_SUCCESS
;
1114 MMixerAddMixerControlsToDestinationLine(
1115 IN PMIXER_CONTEXT MixerContext
,
1116 IN OUT LPMIXER_INFO MixerInfo
,
1117 IN PTOPOLOGY Topology
,
1120 IN ULONG DestinationLineId
,
1121 OUT PULONG OutLineTerminator
)
1124 ULONG NodesCount
, LineTerminator
;
1125 MIXER_STATUS Status
;
1126 LPMIXERLINE_EXT DstLine
;
1128 /* allocate nodes index array */
1129 Status
= MMixerAllocateTopologyNodeArray(MixerContext
, Topology
, &Nodes
);
1131 /* check for success */
1132 if (Status
!= MM_STATUS_SUCCESS
)
1135 return MM_STATUS_NO_MEMORY
;
1138 /* get all destination line controls */
1139 Status
= MMixerCountMixerControls(MixerContext
, Topology
, PinId
, bInput
, TRUE
, &NodesCount
, Nodes
, &LineTerminator
);
1141 /* check for success */
1142 if (Status
!= MM_STATUS_SUCCESS
)
1144 /* failed to count controls */
1145 MixerContext
->Free(Nodes
);
1149 /* get destination mixer line */
1150 DstLine
= MMixerGetSourceMixerLineByLineId(MixerInfo
, DestinationLineId
);
1157 /* add all nodes as mixer controls to the destination line */
1158 Status
= MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext
, MixerInfo
, Topology
, DstLine
, NodesCount
, Nodes
);
1159 if (Status
!= MM_STATUS_SUCCESS
)
1161 /* failed to add controls */
1162 MixerContext
->Free(Nodes
);
1168 *OutLineTerminator
= LineTerminator
;
1175 MMixerApplyOutputFilterHack(
1176 IN PMIXER_CONTEXT MixerContext
,
1177 IN LPMIXER_DATA MixerData
,
1178 IN OUT PULONG PinsCount
,
1181 ULONG Count
= 0, Index
;
1182 MIXER_STATUS Status
;
1183 PKSPIN_PHYSICALCONNECTION Connection
;
1185 for(Index
= 0; Index
< *PinsCount
; Index
++)
1187 /* check if it has a physical connection */
1188 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Pins
[Index
], &Connection
);
1190 if (Status
== MM_STATUS_SUCCESS
)
1193 MixerContext
->Copy(&Pins
[Index
], &Pins
[Index
+ 1], (*PinsCount
- (Index
+ 1)) * sizeof(ULONG
));
1195 /* free physical connection */
1196 MixerContext
->Free(Connection
);
1198 /* decrement index */
1201 /* decrement pin count */
1216 MMixerHandlePhysicalConnection(
1217 IN PMIXER_CONTEXT MixerContext
,
1218 IN PMIXER_LIST MixerList
,
1219 IN LPMIXER_DATA MixerData
,
1220 IN OUT LPMIXER_INFO MixerInfo
,
1222 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
1224 MIXER_STATUS Status
;
1225 ULONG PinsCount
, LineTerminator
, DestinationLineID
;
1229 /* first try to open the connected filter */
1230 OutConnection
->SymbolicLinkName
[1] = L
'\\';
1231 MixerData
= MMixerGetDataByDeviceName(MixerList
, OutConnection
->SymbolicLinkName
);
1233 /* check if the linked connection is found */
1236 /* filter references invalid physical connection */
1237 return MM_STATUS_UNSUCCESSFUL
;
1240 DPRINT1("Name %S, Pin %lu bInput %lu\n", OutConnection
->SymbolicLinkName
, OutConnection
->Pin
, bInput
);
1242 if (MixerInfo
->hMixer
!= NULL
)
1244 /* dont replace mixer destination handles */
1245 DPRINT1("MixerInfo hDevice %p MixerData hDevice %p\n", MixerInfo
->hMixer
, MixerData
->hDevice
);
1246 ASSERT(MixerInfo
->hMixer
== MixerData
->hDevice
);
1249 /* store connected mixer handle */
1250 MixerInfo
->hMixer
= MixerData
->hDevice
;
1252 if (MixerData
->Topology
== NULL
)
1254 /* construct new topology */
1255 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1256 if (Status
!= MM_STATUS_SUCCESS
)
1258 /* failed to create topology */
1262 /* store topology */
1263 MixerData
->Topology
= Topology
;
1267 /* re-use existing topology */
1268 Topology
= MixerData
->Topology
;
1271 /* allocate pin index array which will hold all referenced pins */
1272 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1273 ASSERT(Status
== MM_STATUS_SUCCESS
);
1277 /* the mixer is an output mixer
1278 * find end pin of the node path
1281 Status
= MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext
, Topology
, OutConnection
->Pin
, FALSE
, &PinsCount
, Pins
);
1283 /* check for success */
1284 if (Status
!= MM_STATUS_SUCCESS
)
1286 /* failed to get end pin */
1287 MixerContext
->Free(Pins
);
1288 //MMixerFreeTopology(Topology);
1290 /* return error code */
1294 * some topologies do not have strict boundaries
1295 * WorkArround: remove all pin ids which have a physical connection
1296 * because bridge pins may belong to different render paths
1298 MMixerApplyOutputFilterHack(MixerContext
, MixerData
, &PinsCount
, Pins
);
1301 ASSERT(PinsCount
!= 0);
1302 ASSERT(PinsCount
== 1);
1304 /* create destination line */
1305 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, Pins
[0], bInput
);
1307 /* calculate destination line id */
1308 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1310 if (Status
!= MM_STATUS_SUCCESS
)
1312 /* failed to build destination line */
1313 MixerContext
->Free(Pins
);
1315 /* return error code */
1319 /* add mixer controls to destination line */
1320 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, Topology
, Pins
[0], bInput
, DestinationLineID
, &LineTerminator
);
1322 if (Status
== MM_STATUS_SUCCESS
)
1324 /* now add the rest of the source lines */
1325 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, Topology
, DestinationLineID
, LineTerminator
);
1330 /* calculate destination line id */
1331 DestinationLineID
= (DESTINATION_LINE
+ MixerInfo
->MixCaps
.cDestinations
-1);
1333 /* add mixer controls */
1334 Status
= MMixerAddMixerControlsToDestinationLine(MixerContext
, MixerInfo
, Topology
, OutConnection
->Pin
, bInput
, DestinationLineID
, &LineTerminator
);
1336 if (Status
== MM_STATUS_SUCCESS
)
1338 /* now add the rest of the source lines */
1339 Status
= MMixerAddMixerSourceLines(MixerContext
, MixerInfo
, Topology
, DestinationLineID
, LineTerminator
);
1347 MMixerInitializeFilter(
1348 IN PMIXER_CONTEXT MixerContext
,
1349 IN PMIXER_LIST MixerList
,
1350 IN LPMIXER_DATA MixerData
,
1351 IN LPMIXER_INFO MixerInfo
,
1352 IN PTOPOLOGY Topology
,
1354 IN ULONG bInputMixer
,
1355 IN OUT LPMIXER_INFO
* OutMixerInfo
)
1358 MIXER_STATUS Status
;
1359 PKSPIN_PHYSICALCONNECTION OutConnection
;
1362 ULONG NewMixerInfo
= FALSE
;
1364 if (MixerInfo
== NULL
)
1366 /* allocate a mixer info struct */
1367 MixerInfo
= (LPMIXER_INFO
) MixerContext
->Alloc(sizeof(MIXER_INFO
));
1371 return MM_STATUS_NO_MEMORY
;
1374 /* new mixer info */
1375 NewMixerInfo
= TRUE
;
1377 /* intialize mixer caps */
1378 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; /* FIXME */
1379 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; /* FIXME */
1380 MixerInfo
->MixCaps
.vDriverVersion
= 1; /* FIXME */
1381 MixerInfo
->MixCaps
.fdwSupport
= 0;
1382 MixerInfo
->MixCaps
.cDestinations
= 0;
1384 /* get mixer name */
1385 MMixerGetDeviceName(MixerContext
, MixerInfo
->MixCaps
.szPname
, MixerData
->hDeviceInterfaceKey
);
1387 /* initialize line list */
1388 InitializeListHead(&MixerInfo
->LineList
);
1389 InitializeListHead(&MixerInfo
->EventList
);
1392 /* store mixer info */
1393 *OutMixerInfo
= MixerInfo
;
1395 /* now allocate an array which will receive the indices of the pin
1396 * which has a ADC / DAC nodetype in its path
1398 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1399 ASSERT(Status
== MM_STATUS_SUCCESS
);
1403 /* now get all sink / source pins, which are attached to the ADC / DAC node
1404 * For sink pins (wave out) search up stream
1405 * For source pins (wave in) search down stream
1406 * The search direction is always the opposite of the current mixer type
1409 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, !bInputMixer
, &PinsFound
, Pins
);
1411 /* if there is no pin found, we have a broken topology */
1412 ASSERT(PinsFound
!= 0);
1414 /* now create a wave info struct */
1415 Status
= MMixerInitializeWaveInfo(MixerContext
, MixerList
, MixerData
, MixerInfo
->MixCaps
.szPname
, bInputMixer
, PinsFound
, Pins
);
1416 if (Status
!= MM_STATUS_SUCCESS
)
1418 /* failed to create wave info struct */
1419 MixerContext
->Free(MixerInfo
);
1420 MixerContext
->Free(Pins
);
1426 /* pre create the mixer destination line for input mixers */
1427 Status
= MMixerBuildMixerDestinationLine(MixerContext
, MixerInfo
, Pins
[0], bInputMixer
);
1429 if (Status
!= MM_STATUS_SUCCESS
)
1431 /* failed to create mixer destination line */
1437 /* now get the bridge pin which is at the end of node path
1438 * For sink pins (wave out) search down stream
1439 * For source pins (wave in) search up stream
1441 MixerContext
->Free(Pins
);
1442 Status
= MMixerAllocateTopologyPinArray(MixerContext
, Topology
, &Pins
);
1443 ASSERT(Status
== MM_STATUS_SUCCESS
);
1446 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext
, Topology
, NodeIndex
, bInputMixer
, &PinsFound
, Pins
);
1448 /* if there is no pin found, we have a broken topology */
1449 ASSERT(PinsFound
!= 0);
1451 /* there should be exactly one bridge pin */
1452 ASSERT(PinsFound
== 1);
1454 DPRINT("BridgePin %lu bInputMixer %lu\n", Pins
[0], bInputMixer
);
1456 /* does the pin have a physical connection */
1457 Status
= MMixerGetPhysicalConnection(MixerContext
, MixerData
->hDevice
, Pins
[0], &OutConnection
);
1459 if (Status
== MM_STATUS_SUCCESS
)
1461 /* topology on the topoloy filter */
1462 Status
= MMixerHandlePhysicalConnection(MixerContext
, MixerList
, MixerData
, MixerInfo
, bInputMixer
, OutConnection
);
1464 /* free physical connection data */
1465 MixerContext
->Free(OutConnection
);
1470 * handle drivers which expose their topology on the same filter
1473 MixerInfo
->hMixer
= MixerData
->hDevice
;
1477 MixerContext
->Free(Pins
);
1482 InsertHeadList(&MixerList
->MixerList
, &MixerInfo
->Entry
);
1483 /* increment mixer count */
1484 MixerList
->MixerListCount
++;
1493 IN PMIXER_CONTEXT MixerContext
,
1494 IN PMIXER_LIST MixerList
,
1495 IN LPMIXER_DATA MixerData
,
1496 IN PULONG DeviceCount
)
1498 MIXER_STATUS Status
;
1501 LPMIXER_INFO MixerInfo
= NULL
;
1503 /* check if topology has already been built */
1504 if (MixerData
->Topology
== NULL
)
1506 /* build topology */
1507 Status
= MMixerBuildTopology(MixerContext
, MixerData
, &Topology
);
1509 if (Status
!= MM_STATUS_SUCCESS
)
1511 /* failed to build topology */
1515 /* store topology */
1516 MixerData
->Topology
= Topology
;
1520 /* re-use topology */
1521 Topology
= MixerData
->Topology
;
1524 /* check if the filter has an wave out node */
1525 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_DAC
);
1526 if (NodeIndex
!= MAXULONG
)
1529 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, NULL
, Topology
, NodeIndex
, FALSE
, &MixerInfo
);
1531 /* check for success */
1532 if (Status
== MM_STATUS_SUCCESS
)
1534 /* increment mixer count */
1539 /* reset mixer info in case of error */
1544 /* check if the filter has an wave in node */
1545 NodeIndex
= MMixerGetNodeIndexFromGuid(Topology
, &KSNODETYPE_ADC
);
1546 if (NodeIndex
!= MAXULONG
)
1549 Status
= MMixerInitializeFilter(MixerContext
, MixerList
, MixerData
, MixerInfo
, Topology
, NodeIndex
, TRUE
, &MixerInfo
);
1551 /* check for success */
1552 if (Status
== MM_STATUS_SUCCESS
)
1554 /* increment mixer count */
1560 /* TODO: handle alternative mixer types + apply hacks for Wave source line */
1562 /* activate midi devices */
1563 MMixerInitializeMidiForFilter(MixerContext
, MixerList
, MixerData
, Topology
);
1572 IN PMIXER_CONTEXT MixerContext
,
1573 IN OUT LPMIXER_INFO MixerInfo
,
1574 IN PVOID MixerEventContext
,
1575 IN PMIXER_EVENT MixerEventRoutine
)
1577 //KSE_NODE Property;
1578 PEVENT_NOTIFICATION_ENTRY EventData
;
1579 //ULONG BytesReturned;
1580 //MIXER_STATUS Status;
1582 EventData
= (PEVENT_NOTIFICATION_ENTRY
)MixerContext
->AllocEventData(sizeof(EVENT_NOTIFICATION_ENTRY
));
1585 /* not enough memory */
1586 return MM_STATUS_NO_MEMORY
;
1591 Property
.Event
.Set
= KSEVENTSETID_AudioControlChange
;
1592 Property
.Event
.Flags
= KSEVENT_TYPE_TOPOLOGY
|KSEVENT_TYPE_ENABLE
;
1593 Property
.Event
.Id
= KSEVENT_CONTROL_CHANGE
;
1595 Property
.NodeId
= NodeId
;
1596 Property
.Reserved
= 0;
1598 Status
= MixerContext
->Control(MixerInfo
->hMixer
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSP_NODE
), (PVOID
)EventData
, sizeof(KSEVENTDATA
), &BytesReturned
);
1599 if (Status
!= MM_STATUS_SUCCESS
)
1601 /* failed to add event */
1602 MixerContext
->FreeEventData(EventData
);
1607 /* initialize notification entry */
1608 EventData
->MixerEventContext
= MixerEventContext
;
1609 EventData
->MixerEventRoutine
;
1612 InsertTailList(&MixerInfo
->EventList
, &EventData
->Entry
);
1613 return MM_STATUS_SUCCESS
;