2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/legacy/wdmaud/mixer.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Andrew Greenwood
11 const GUID KSNODETYPE_DAC
= {0x507AE360L
, 0xC554, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
12 const GUID KSNODETYPE_ADC
= {0x4D837FE0L
, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
13 const GUID KSNODETYPE_AGC
= {0xE88C9BA0L
, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
14 const GUID KSNODETYPE_LOUDNESS
= {0x41887440L
, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
15 const GUID KSNODETYPE_MUTE
= {0x02B223C0L
, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
16 const GUID KSNODETYPE_TONE
= {0x7607E580L
, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
17 const GUID KSNODETYPE_VOLUME
= {0x3A5ACC00L
, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
18 const GUID KSNODETYPE_PEAKMETER
= {0xa085651e, 0x5f0d, 0x4b36, {0xa8, 0x69, 0xd1, 0x95, 0xd6, 0xab, 0x4b, 0x9e}};
19 const GUID KSNODETYPE_MUX
= {0x2CEAF780, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
20 const GUID KSNODETYPE_STEREO_WIDE
= {0xA9E69800L
, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
21 const GUID KSNODETYPE_CHORUS
= {0x20173F20L
, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
22 const GUID KSNODETYPE_REVERB
= {0xEF0328E0L
, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
23 const GUID KSNODETYPE_SUPERMIX
= {0xE573ADC0L
, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
24 const GUID KSNODETYPE_SUM
= {0xDA441A60L
, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
25 const GUID KSPROPSETID_Audio
= {0x45FFAAA0L
, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
27 #define DESTINATION_LINE 0xFFFF0000
31 LPMIXER_INFO MixerInfo
,
35 LPMIXERLINE_EXT MixerLineSrc
;
38 Entry
= MixerInfo
->LineList
.Flink
;
40 while(Entry
!= &MixerInfo
->LineList
)
42 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
43 DPRINT("dwSource %x dwSource %x\n", MixerLineSrc
->Line
.dwSource
, dwSource
);
44 if (MixerLineSrc
->Line
.dwSource
== dwSource
)
55 LPMIXER_INFO MixerInfo
,
57 LPMIXERLINE_EXT
*MixerLine
,
58 LPMIXERCONTROLW
*MixerControl
,
62 LPMIXERLINE_EXT MixerLineSrc
;
66 Entry
= MixerInfo
->LineList
.Flink
;
68 while(Entry
!= &MixerInfo
->LineList
)
70 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
72 for(Index
= 0; Index
< MixerLineSrc
->Line
.cConnections
; Index
++)
74 if (MixerLineSrc
->LineControls
[Index
].dwControlID
== dwControlID
)
76 *MixerLine
= MixerLineSrc
;
77 *MixerControl
= &MixerLineSrc
->LineControls
[Index
];
78 *NodeId
= MixerLineSrc
->NodeIds
[Index
];
79 return STATUS_SUCCESS
;
85 return STATUS_NOT_FOUND
;
91 GetSourceMixerLineByLineId(
92 LPMIXER_INFO MixerInfo
,
96 LPMIXERLINE_EXT MixerLineSrc
;
99 Entry
= MixerInfo
->LineList
.Flink
;
101 while(Entry
!= &MixerInfo
->LineList
)
103 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
104 DPRINT1("dwLineID %x dwLineID %x\n", MixerLineSrc
->Line
.dwLineID
, dwLineID
);
105 if (MixerLineSrc
->Line
.dwLineID
== dwLineID
)
108 Entry
= Entry
->Flink
;
118 IN PFILE_OBJECT FileObject
)
122 ULONG NumPins
, BytesReturned
;
124 Pin
.Flags
= KSPROPERTY_TYPE_GET
;
125 Pin
.Set
= KSPROPSETID_Pin
;
126 Pin
.Id
= KSPROPERTY_PIN_CTYPES
;
128 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSPROPERTY
), (PVOID
)&NumPins
, sizeof(ULONG
), &BytesReturned
);
129 if (!NT_SUCCESS(Status
))
137 GetSysAudioDeviceCount(
138 IN PDEVICE_OBJECT DeviceObject
)
140 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
142 ULONG Count
, BytesReturned
;
145 /* setup the query request */
146 Pin
.Set
= KSPROPSETID_Sysaudio
;
147 Pin
.Id
= KSPROPERTY_SYSAUDIO_DEVICE_COUNT
;
148 Pin
.Flags
= KSPROPERTY_TYPE_GET
;
150 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
152 /* query sysaudio for the device count */
153 Status
= KsSynchronousIoControlDevice(DeviceExtension
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSPROPERTY
), (PVOID
)&Count
, sizeof(ULONG
), &BytesReturned
);
154 if (!NT_SUCCESS(Status
))
161 GetSysAudioDevicePnpName(
162 IN PDEVICE_OBJECT DeviceObject
,
163 IN ULONG DeviceIndex
,
169 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
171 /* first check if the device index is within bounds */
172 if (DeviceIndex
>= GetSysAudioDeviceCount(DeviceObject
))
173 return STATUS_INVALID_PARAMETER
;
175 /* setup the query request */
176 Pin
.Property
.Set
= KSPROPSETID_Sysaudio
;
177 Pin
.Property
.Id
= KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME
;
178 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
179 Pin
.PinId
= DeviceIndex
;
181 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
183 /* query sysaudio for the device path */
184 Status
= KsSynchronousIoControlDevice(DeviceExtension
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSPROPERTY
) + sizeof(ULONG
), NULL
, 0, &BytesReturned
);
186 /* check if the request failed */
187 if (Status
!= STATUS_BUFFER_TOO_SMALL
|| BytesReturned
== 0)
188 return STATUS_UNSUCCESSFUL
;
190 /* allocate buffer for the device */
191 *Device
= ExAllocatePool(NonPagedPool
, BytesReturned
);
193 return STATUS_INSUFFICIENT_RESOURCES
;
195 /* query sysaudio again for the device path */
196 Status
= KsSynchronousIoControlDevice(DeviceExtension
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSPROPERTY
) + sizeof(ULONG
), (PVOID
)*Device
, BytesReturned
, &BytesReturned
);
198 if (!NT_SUCCESS(Status
))
209 GetDeviceIndexFromPnpName(
210 IN PDEVICE_OBJECT DeviceObject
,
217 /* get device count */
218 Count
= GetSysAudioDeviceCount(DeviceObject
);
223 for(Index
= 0; Index
< Count
; Index
++)
225 /* get device name */
226 Status
= GetSysAudioDevicePnpName(DeviceObject
, Index
, &DeviceName
);
227 if (NT_SUCCESS(Status
))
229 if (!wcsicmp(Device
, DeviceName
))
231 /* found device index */
232 ExFreePool(DeviceName
);
235 ExFreePool(DeviceName
);
246 OUT PHANDLE DeviceHandle
,
247 OUT PFILE_OBJECT
* FileObject
)
252 /* now open the device */
253 Status
= WdmAudOpenSysAudioDevice(Device
, &hDevice
);
255 if (!NT_SUCCESS(Status
))
260 *DeviceHandle
= hDevice
;
264 Status
= ObReferenceObjectByHandle(hDevice
, FILE_READ_DATA
| FILE_WRITE_DATA
, IoFileObjectType
, KernelMode
, (PVOID
*)FileObject
, NULL
);
266 if (!NT_SUCCESS(Status
))
278 OpenSysAudioDeviceByIndex(
279 IN PDEVICE_OBJECT DeviceObject
,
280 IN ULONG DeviceIndex
,
281 IN PHANDLE DeviceHandle
,
282 IN PFILE_OBJECT
* FileObject
)
284 LPWSTR Device
= NULL
;
287 Status
= GetSysAudioDevicePnpName(DeviceObject
, DeviceIndex
, &Device
);
288 if (!NT_SUCCESS(Status
))
291 Status
= OpenDevice(Device
, DeviceHandle
, FileObject
);
293 /* free device buffer */
300 GetFilterNodeProperty(
301 IN PFILE_OBJECT FileObject
,
303 PKSMULTIPLE_ITEM
* Item
)
307 PKSMULTIPLE_ITEM MultipleItem
;
310 /* setup query request */
311 Property
.Id
= PropertyId
;
312 Property
.Flags
= KSPROPERTY_TYPE_GET
;
313 Property
.Set
= KSPROPSETID_Topology
;
315 /* query for required size */
316 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), NULL
, 0, &BytesReturned
);
318 /* check for success */
319 if (Status
!= STATUS_MORE_ENTRIES
)
322 /* allocate buffer */
323 MultipleItem
= (PKSMULTIPLE_ITEM
)ExAllocatePool(NonPagedPool
, BytesReturned
);
325 return STATUS_INSUFFICIENT_RESOURCES
;
327 /* query for required size */
328 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), (PVOID
)MultipleItem
, BytesReturned
, &BytesReturned
);
330 if (!NT_SUCCESS(Status
))
333 ExFreePool(MultipleItem
);
337 *Item
= MultipleItem
;
343 PKSMULTIPLE_ITEM MultipleItem
,
351 Guid
= (LPGUID
)(MultipleItem
+1);
353 /* iterate through node type array */
354 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
356 if (IsEqualGUIDAligned(NodeType
, Guid
))
358 /* found matching guid */
368 PKSMULTIPLE_ITEM MultipleItem
,
374 Guid
= (LPGUID
)(MultipleItem
+1);
376 /* iterate through node type array */
377 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
379 if (IsEqualGUIDAligned(NodeType
, Guid
))
381 /* found matching guid */
390 GetControlTypeFromTopologyNode(
393 if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_AGC
))
395 // automatic gain control
396 return MIXERCONTROL_CONTROLTYPE_ONOFF
;
398 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_LOUDNESS
))
401 return MIXERCONTROL_CONTROLTYPE_LOUDNESS
;
403 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_MUTE
))
406 return MIXERCONTROL_CONTROLTYPE_MUTE
;
408 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_TONE
))
412 // MIXERCONTROL_CONTROLTYPE_ONOFF if KSPROPERTY_AUDIO_BASS_BOOST is supported
413 // MIXERCONTROL_CONTROLTYPE_BASS if KSPROPERTY_AUDIO_BASS is supported
414 // MIXERCONTROL_CONTROLTYPE_TREBLE if KSPROPERTY_AUDIO_TREBLE is supported
416 return MIXERCONTROL_CONTROLTYPE_ONOFF
;
418 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_VOLUME
))
421 return MIXERCONTROL_CONTROLTYPE_VOLUME
;
423 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_PEAKMETER
))
426 return MIXERCONTROL_CONTROLTYPE_PEAKMETER
;
428 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_MUX
))
431 return MIXERCONTROL_CONTROLTYPE_MUX
;
433 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_MUX
))
436 return MIXERCONTROL_CONTROLTYPE_MUX
;
438 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_STEREO_WIDE
))
440 // stero wide control
441 return MIXERCONTROL_CONTROLTYPE_FADER
;
443 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_CHORUS
))
446 return MIXERCONTROL_CONTROLTYPE_FADER
;
448 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_REVERB
))
451 return MIXERCONTROL_CONTROLTYPE_FADER
;
453 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_SUPERMIX
))
456 // MIXERCONTROL_CONTROLTYPE_MUTE if KSPROPERTY_AUDIO_MUTE is supported
458 return MIXERCONTROL_CONTROLTYPE_VOLUME
;
465 GetPhysicalConnection(
466 IN PFILE_OBJECT FileObject
,
468 OUT PKSPIN_PHYSICALCONNECTION
*OutConnection
)
473 PKSPIN_PHYSICALCONNECTION Connection
;
475 /* setup the request */
476 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
477 Pin
.Property
.Id
= KSPROPERTY_PIN_PHYSICALCONNECTION
;
478 Pin
.Property
.Set
= KSPROPSETID_Pin
;
481 /* query the pin for the physical connection */
482 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
484 if (Status
== STATUS_NOT_FOUND
)
486 /* pin does not have a physical connection */
490 Connection
= ExAllocatePool(NonPagedPool
, BytesReturned
);
493 /* not enough memory */
494 return STATUS_INSUFFICIENT_RESOURCES
;
497 /* query the pin for the physical connection */
498 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Connection
, BytesReturned
, &BytesReturned
);
499 if (!NT_SUCCESS(Status
))
501 /* failed to query the physical connection */
502 ExFreePool(Connection
);
506 /* store connection */
507 *OutConnection
= Connection
;
513 IN PKSMULTIPLE_ITEM MultipleItem
,
517 OUT PULONG NodeReferenceCount
,
518 OUT PULONG
*NodeReference
)
520 ULONG Index
, Count
= 0;
521 PKSTOPOLOGY_CONNECTION Connection
;
524 /* KSMULTIPLE_ITEM is followed by several KSTOPOLOGY_CONNECTION */
525 Connection
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
527 /* first count all referenced nodes */
528 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
530 //DbgPrint("FromPin %u FromNode %u ToPin %u ToNode %u\n", Connection->FromNodePin, Connection->FromNode, Connection->ToNodePin, Connection->ToNode);
535 if (Connection
->FromNode
== NodeIndex
)
537 /* node id has a connection */
543 if (Connection
->ToNode
== NodeIndex
)
545 /* node id has a connection */
554 if (Connection
->FromNodePin
== NodeIndex
&& Connection
->FromNode
== KSFILTER_NODE
)
556 /* node id has a connection */
562 if (Connection
->ToNodePin
== NodeIndex
&& Connection
->ToNode
== KSFILTER_NODE
)
564 /* node id has a connection */
571 /* move to next connection */
577 /* now allocate node index array */
578 Refs
= ExAllocatePool(NonPagedPool
, sizeof(ULONG
) * Count
);
581 /* not enough memory */
582 return STATUS_INSUFFICIENT_RESOURCES
;
585 /* clear node index array */
586 RtlZeroMemory(Refs
, Count
* sizeof(ULONG
));
589 Connection
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
590 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
596 if (Connection
->FromNode
== NodeIndex
)
598 /* node id has a connection */
605 if (Connection
->ToNode
== NodeIndex
)
607 /* node id has a connection */
617 if (Connection
->FromNodePin
== NodeIndex
&& Connection
->FromNode
== KSFILTER_NODE
)
619 /* node id has a connection */
626 if (Connection
->ToNodePin
== NodeIndex
&& Connection
->ToNode
== KSFILTER_NODE
)
628 /* node id has a connection */
635 /* move to next connection */
640 *NodeReference
= Refs
;
641 *NodeReferenceCount
= Count
;
643 return STATUS_SUCCESS
;
648 GetTargetPinsByNodeConnectionIndex(
649 IN PKSMULTIPLE_ITEM NodeConnections
,
650 IN PKSMULTIPLE_ITEM NodeTypes
,
651 IN ULONG bUpDirection
,
652 IN ULONG NodeConnectionIndex
,
655 PKSTOPOLOGY_CONNECTION Connection
;
656 ULONG PinId
, NodeConnectionCount
, Index
;
657 PULONG NodeConnection
;
662 ASSERT(NodeConnectionIndex
< NodeConnections
->Count
);
664 Connection
= (PKSTOPOLOGY_CONNECTION
)(NodeConnections
+ 1);
666 DPRINT("FromNode %u FromNodePin %u -> ToNode %u ToNodePin %u\n", Connection
[NodeConnectionIndex
].FromNode
, Connection
[NodeConnectionIndex
].FromNodePin
, Connection
[NodeConnectionIndex
].ToNode
, Connection
[NodeConnectionIndex
].ToNodePin
);
668 if ((Connection
[NodeConnectionIndex
].ToNode
== KSFILTER_NODE
&& bUpDirection
== FALSE
) ||
669 (Connection
[NodeConnectionIndex
].FromNode
== KSFILTER_NODE
&& bUpDirection
== TRUE
))
671 /* iteration stops here */
673 PinId
= Connection
[NodeConnectionIndex
].FromNodePin
;
675 PinId
= Connection
[NodeConnectionIndex
].ToNodePin
;
677 DPRINT("GetTargetPinsByNodeIndex FOUND Target Pin %u Parsed %u\n", PinId
, Pins
[PinId
]);
679 /* mark pin index as a target pin */
681 return STATUS_SUCCESS
;
684 /* get all node indexes referenced by that node */
687 Status
= GetNodeIndexes(NodeConnections
, Connection
[NodeConnectionIndex
].FromNode
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
691 Status
= GetNodeIndexes(NodeConnections
, Connection
[NodeConnectionIndex
].ToNode
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
694 if (NT_SUCCESS(Status
))
696 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
698 /* iterate recursively into the nodes */
699 Status
= GetTargetPinsByNodeConnectionIndex(NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Pins
);
700 ASSERT(Status
== STATUS_SUCCESS
);
702 /* free node connection indexes */
703 ExFreePool(NodeConnection
);
713 PKSMULTIPLE_ITEM NodeTypes
,
714 PKSMULTIPLE_ITEM NodeConnections
,
716 IN ULONG bUpDirection
,
720 ULONG NodeConnectionCount
, Index
;
722 PULONG NodeConnection
;
725 ASSERT(NodeIndex
!= (ULONG
)-1);
727 /* get all node indexes referenced by that pin */
729 Status
= GetNodeIndexes(NodeConnections
, NodeIndex
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
731 Status
= GetNodeIndexes(NodeConnections
, NodeIndex
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
733 DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex
, Status
, NodeConnectionCount
);
735 if (NT_SUCCESS(Status
))
737 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
739 Status
= GetTargetPinsByNodeConnectionIndex(NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Pins
);
740 ASSERT(Status
== STATUS_SUCCESS
);
742 ExFreePool(NodeConnection
);
752 PULONG Pins
= ExAllocatePool(NonPagedPool
, PinCount
* sizeof(ULONG
));
756 RtlZeroMemory(Pins
, sizeof(ULONG
) * PinCount
);
761 PKSTOPOLOGY_CONNECTION
762 GetConnectionByIndex(
763 IN PKSMULTIPLE_ITEM MultipleItem
,
766 PKSTOPOLOGY_CONNECTION Descriptor
;
768 ASSERT(Index
< MultipleItem
->Count
);
770 Descriptor
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
771 return &Descriptor
[Index
];
776 IN PKSMULTIPLE_ITEM MultipleItem
,
781 ASSERT(Index
< MultipleItem
->Count
);
783 NodeType
= (LPGUID
)(MultipleItem
+ 1);
784 return &NodeType
[Index
];
788 GetControlsFromPinByConnectionIndex(
789 IN PKSMULTIPLE_ITEM NodeConnections
,
790 IN PKSMULTIPLE_ITEM NodeTypes
,
791 IN ULONG bUpDirection
,
792 IN ULONG NodeConnectionIndex
,
795 PKSTOPOLOGY_CONNECTION CurConnection
;
799 ULONG NodeConnectionCount
, Index
;
800 PULONG NodeConnection
;
803 /* get current connection */
804 CurConnection
= GetConnectionByIndex(NodeConnections
, NodeConnectionIndex
);
807 NodeIndex
= CurConnection
->FromNode
;
809 NodeIndex
= CurConnection
->ToNode
;
811 /* get target node type of current connection */
812 NodeType
= GetNodeType(NodeTypes
, NodeIndex
);
814 if (IsEqualGUIDAligned(NodeType
, &KSNODETYPE_SUM
) || IsEqualGUIDAligned(NodeType
, &KSNODETYPE_MUX
))
818 /* add the sum / mux node to destination line */
819 //Nodes[NodeIndex] = TRUE;
822 return STATUS_SUCCESS
;
825 /* now add the node */
826 Nodes
[NodeIndex
] = TRUE
;
829 /* get all node indexes referenced by that node */
832 Status
= GetNodeIndexes(NodeConnections
, NodeIndex
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
836 Status
= GetNodeIndexes(NodeConnections
, NodeIndex
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
839 if (NT_SUCCESS(Status
))
841 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
843 /* iterate recursively into the nodes */
844 Status
= GetControlsFromPinByConnectionIndex(NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Nodes
);
845 ASSERT(Status
== STATUS_SUCCESS
);
847 /* free node connection indexes */
848 ExFreePool(NodeConnection
);
856 IN PKSMULTIPLE_ITEM NodeConnections
,
857 IN PKSMULTIPLE_ITEM NodeTypes
,
859 IN ULONG bUpDirection
,
862 ULONG NodeConnectionCount
, Index
;
864 PULONG NodeConnection
;
867 ASSERT(PinId
!= (ULONG
)-1);
869 /* get all node indexes referenced by that pin */
871 Status
= GetNodeIndexes(NodeConnections
, PinId
, FALSE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
873 Status
= GetNodeIndexes(NodeConnections
, PinId
, FALSE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
875 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
877 /* get all associated controls */
878 Status
= GetControlsFromPinByConnectionIndex(NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Nodes
);
881 ExFreePool(NodeConnection
);
888 IN LPMIXER_INFO MixerInfo
,
889 IN PFILE_OBJECT FileObject
,
890 IN PKSMULTIPLE_ITEM NodeTypes
,
892 OUT LPMIXERCONTROLW MixerControl
)
901 /* initialize mixer control */
902 MixerControl
->cbStruct
= sizeof(MIXERCONTROLW
);
903 MixerControl
->dwControlID
= MixerInfo
->ControlId
;
906 NodeType
= GetNodeType(NodeTypes
, NodeIndex
);
907 /* store control type */
908 MixerControl
->dwControlType
= GetControlTypeFromTopologyNode(NodeType
);
910 MixerControl
->fdwControl
= MIXERCONTROL_CONTROLF_UNIFORM
; //FIXME
911 MixerControl
->cMultipleItems
= 0; //FIXME
913 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
915 MixerControl
->Bounds
.dwMinimum
= 0;
916 MixerControl
->Bounds
.dwMaximum
= 1;
918 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
920 MixerControl
->Bounds
.dwMinimum
= 0;
921 MixerControl
->Bounds
.dwMaximum
= 0xFFFF;
922 MixerControl
->Metrics
.cSteps
= 0xC0; //FIXME
925 /* setup request to retrieve name */
926 Node
.NodeId
= NodeIndex
;
927 Node
.Property
.Id
= KSPROPERTY_TOPOLOGY_NAME
;
928 Node
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
929 Node
.Property
.Set
= KSPROPSETID_Topology
;
932 /* get node name size */
933 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), NULL
, 0, &BytesReturned
);
935 if (Status
== STATUS_BUFFER_TOO_SMALL
)
937 ASSERT(BytesReturned
!= 0);
938 Name
= ExAllocatePool(NonPagedPool
, BytesReturned
);
941 /* not enough memory */
942 return STATUS_INSUFFICIENT_RESOURCES
;
946 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), (LPVOID
)Name
, BytesReturned
, &BytesReturned
);
947 if (NT_SUCCESS(Status
))
949 RtlMoveMemory(MixerControl
->szShortName
, Name
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
950 MixerControl
->szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
952 RtlMoveMemory(MixerControl
->szName
, Name
, (min(MIXER_LONG_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
953 MixerControl
->szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
956 /* free name buffer */
960 MixerInfo
->ControlId
++;
962 DPRINT("Status %x Name %S\n", Status
, MixerControl
->szName
);
963 return STATUS_SUCCESS
;
968 IN OUT LPMIXER_INFO MixerInfo
,
969 IN PFILE_OBJECT FileObject
,
970 IN PKSMULTIPLE_ITEM NodeConnections
,
971 IN PKSMULTIPLE_ITEM NodeTypes
,
972 IN ULONG DeviceIndex
,
977 LPMIXERLINE_EXT SrcLine
, DstLine
;
982 ULONG BytesReturned
, ControlCount
, Index
;
987 /* allocate src mixer line */
988 SrcLine
= (LPMIXERLINE_EXT
)ExAllocatePool(NonPagedPool
, sizeof(MIXERLINE_EXT
));
991 return STATUS_INSUFFICIENT_RESOURCES
;
994 RtlZeroMemory(SrcLine
, sizeof(MIXERLINE_EXT
));
999 ASSERT(!IsListEmpty(&MixerInfo
->LineList
));
1000 SrcLine
= GetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
1003 /* get destination line */
1004 DstLine
= GetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
1010 /* initialize mixer src line */
1011 SrcLine
->DeviceIndex
= DeviceIndex
;
1012 SrcLine
->PinId
= PinId
;
1013 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
1015 /* initialize mixer destination line */
1016 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
1017 SrcLine
->Line
.dwDestination
= 0;
1018 SrcLine
->Line
.dwSource
= DstLine
->Line
.cConnections
;
1019 SrcLine
->Line
.dwLineID
= (DstLine
->Line
.cConnections
* 0x10000);
1020 SrcLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
| MIXERLINE_LINEF_SOURCE
;
1021 SrcLine
->Line
.dwUser
= 0;
1022 SrcLine
->Line
.cChannels
= DstLine
->Line
.cChannels
;
1023 SrcLine
->Line
.cConnections
= 0;
1024 SrcLine
->Line
.Target
.dwType
= 1;
1025 SrcLine
->Line
.Target
.dwDeviceID
= DstLine
->Line
.Target
.dwDeviceID
;
1026 SrcLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
1027 SrcLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
1028 SrcLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
1029 wcscpy(SrcLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
1033 /* allocate a node arrary */
1034 Nodes
= ExAllocatePool(NonPagedPool
, sizeof(ULONG
) * NodeTypes
->Count
);
1038 /* not enough memory */
1041 ExFreePool(SrcLine
);
1043 return STATUS_INSUFFICIENT_RESOURCES
;
1046 /* clear nodes array */
1047 RtlZeroMemory(Nodes
, sizeof(ULONG
) * NodeTypes
->Count
);
1049 Status
= GetControlsFromPin(NodeConnections
, NodeTypes
, PinId
, bTargetPin
, Nodes
);
1050 if (!NT_SUCCESS(Status
))
1052 /* something went wrong */
1055 ExFreePool(SrcLine
);
1061 /* now count all nodes controlled by that pin */
1063 for(Index
= 0; Index
< NodeTypes
->Count
; Index
++)
1069 /* now allocate the line controls */
1072 SrcLine
->LineControls
= ExAllocatePool(NonPagedPool
, sizeof(MIXERCONTROLW
) * ControlCount
);
1074 if (!SrcLine
->LineControls
)
1076 /* no memory available */
1079 ExFreePool(SrcLine
);
1082 return STATUS_INSUFFICIENT_RESOURCES
;
1085 SrcLine
->NodeIds
= ExAllocatePool(NonPagedPool
, sizeof(ULONG
) * ControlCount
);
1086 if (!SrcLine
->NodeIds
)
1088 /* no memory available */
1089 ExFreePool(SrcLine
->LineControls
);
1092 ExFreePool(SrcLine
);
1095 return STATUS_INSUFFICIENT_RESOURCES
;
1098 /* zero line controls */
1099 RtlZeroMemory(SrcLine
->LineControls
, sizeof(MIXERCONTROLW
) * ControlCount
);
1100 RtlZeroMemory(SrcLine
->NodeIds
, sizeof(ULONG
) * ControlCount
);
1103 for(Index
= 0; Index
< NodeTypes
->Count
; Index
++)
1107 /* store the node index for retrieving / setting details */
1108 SrcLine
->NodeIds
[ControlCount
] = Index
;
1110 Status
= AddMixerControl(MixerInfo
, FileObject
, NodeTypes
, Index
, &SrcLine
->LineControls
[ControlCount
]);
1111 if (NT_SUCCESS(Status
))
1113 /* increment control count on success */
1118 /* store control count */
1119 SrcLine
->Line
.cControls
= ControlCount
;
1122 /* release nodes array */
1125 /* get pin category */
1128 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
1129 Pin
.Property
.Set
= KSPROPSETID_Pin
;
1130 Pin
.Property
.Id
= KSPROPERTY_PIN_CATEGORY
;
1132 /* try get pin category */
1133 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (LPVOID
)&NodeType
, sizeof(GUID
), &BytesReturned
);
1134 if (NT_SUCCESS(Status
))
1137 //map component type
1140 /* retrieve pin name */
1143 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
1144 Pin
.Property
.Set
= KSPROPSETID_Pin
;
1145 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
1147 /* try get pin name size */
1148 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
1150 if (Status
!= STATUS_MORE_ENTRIES
)
1152 SrcLine
->Line
.szShortName
[0] = L
'\0';
1153 SrcLine
->Line
.szName
[0] = L
'\0';
1157 PinName
= (LPWSTR
)ExAllocatePool(NonPagedPool
, BytesReturned
);
1160 /* try get pin name */
1161 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (LPVOID
)PinName
, BytesReturned
, &BytesReturned
);
1163 if (NT_SUCCESS(Status
))
1165 RtlMoveMemory(SrcLine
->Line
.szShortName
, PinName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
1166 SrcLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
1168 RtlMoveMemory(SrcLine
->Line
.szName
, PinName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
1169 SrcLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
1171 ExFreePool(PinName
);
1175 /* insert src line */
1178 InsertTailList(&MixerInfo
->LineList
, &SrcLine
->Entry
);
1179 DstLine
->Line
.cConnections
++;
1182 return STATUS_SUCCESS
;
1187 AddMixerSourceLines(
1188 IN OUT LPMIXER_INFO MixerInfo
,
1189 IN PFILE_OBJECT FileObject
,
1190 IN PKSMULTIPLE_ITEM NodeConnections
,
1191 IN PKSMULTIPLE_ITEM NodeTypes
,
1192 IN ULONG DeviceIndex
,
1194 IN ULONG BridgePinIndex
,
1195 IN ULONG TargetPinIndex
,
1199 NTSTATUS Status
= STATUS_SUCCESS
;
1201 for(Index
= PinsCount
; Index
> 0; Index
--)
1205 AddMixerSourceLine(MixerInfo
, FileObject
, NodeConnections
, NodeTypes
, DeviceIndex
, Index
-1, (Index
-1 == BridgePinIndex
), (Index
-1 == TargetPinIndex
));
1214 HandlePhysicalConnection(
1215 IN OUT LPMIXER_INFO MixerInfo
,
1216 IN PDEVICE_OBJECT DeviceObject
,
1218 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
1220 PULONG PinsRef
= NULL
, PinConnectionIndex
= NULL
, PinsSrcRef
;
1221 ULONG PinsRefCount
, Index
, PinConnectionIndexCount
, DeviceIndex
;
1223 HANDLE hDevice
= NULL
;
1224 PFILE_OBJECT FileObject
= NULL
;
1225 PKSMULTIPLE_ITEM NodeTypes
= NULL
;
1226 PKSMULTIPLE_ITEM NodeConnections
= NULL
;
1227 PULONG MixerControls
;
1228 ULONG MixerControlsCount
;
1231 /* open the connected filter */
1232 Status
= OpenDevice(OutConnection
->SymbolicLinkName
, &hDevice
, &FileObject
);
1233 if (!NT_SUCCESS(Status
))
1235 DPRINT1("OpenDevice failed with %x\n", Status
);
1239 /* get device index */
1240 DeviceIndex
= GetDeviceIndexFromPnpName(DeviceObject
, OutConnection
->SymbolicLinkName
);
1242 /* get connected filter pin count */
1243 PinsRefCount
= GetPinCount(FileObject
);
1244 ASSERT(PinsRefCount
);
1246 PinsRef
= AllocatePinArray(PinsRefCount
);
1250 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1254 /* get topology node types */
1255 Status
= GetFilterNodeProperty(FileObject
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
1256 if (!NT_SUCCESS(Status
))
1258 DPRINT1("GetFilterNodeProperty failed with %x\n", Status
);
1262 /* get topology connections */
1263 Status
= GetFilterNodeProperty(FileObject
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
1264 if (!NT_SUCCESS(Status
))
1266 DPRINT1("GetFilterNodeProperty failed with %x\n", Status
);
1269 /* gets connection index of the bridge pin which connects to a node */
1270 DPRINT("Pin %u\n", OutConnection
->Pin
);
1271 Status
= GetNodeIndexes(NodeConnections
, OutConnection
->Pin
, FALSE
, !bInput
, &PinConnectionIndexCount
, &PinConnectionIndex
);
1272 if (!NT_SUCCESS(Status
))
1274 DPRINT1("GetNodeIndexes failed with %x\n", Status
);
1278 /* there should be no split in the bride pin */
1279 ASSERT(PinConnectionIndexCount
== 1);
1281 /* find all target pins of this connection */
1282 Status
= GetTargetPinsByNodeConnectionIndex(NodeConnections
, NodeTypes
, FALSE
, PinConnectionIndex
[0], PinsRef
);
1283 if (!NT_SUCCESS(Status
))
1285 DPRINT1("GetTargetPinsByNodeConnectionIndex failed with %x\n", Status
);
1289 for(Index
= 0; Index
< PinsRefCount
; Index
++)
1294 /* found a target pin, now get all references */
1295 Status
= GetNodeIndexes(NodeConnections
, Index
, FALSE
, FALSE
, &MixerControlsCount
, &MixerControls
);
1296 if (!NT_SUCCESS(Status
))
1300 ASSERT(MixerControlsCount
== 1);
1303 PinsSrcRef
= AllocatePinArray(PinsRefCount
);
1307 ExFreePool(MixerControls
);
1308 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1311 /* now get all connected source pins */
1312 Status
= GetTargetPinsByNodeConnectionIndex(NodeConnections
, NodeTypes
, TRUE
, MixerControls
[0], PinsSrcRef
);
1313 if (!NT_SUCCESS(Status
))
1316 ExFreePool(MixerControls
);
1317 ExFreePool(PinsSrcRef
);
1318 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1322 /* add pins from target line */
1325 // dont add bridge pin for input mixers
1326 PinsSrcRef
[Index
] = TRUE
;
1327 PinsSrcRef
[OutConnection
->Pin
] = TRUE
;
1330 Status
= AddMixerSourceLines(MixerInfo
, FileObject
, NodeConnections
, NodeTypes
, DeviceIndex
, PinsRefCount
, OutConnection
->Pin
, Index
, PinsSrcRef
);
1332 ExFreePool(MixerControls
);
1333 ExFreePool(PinsSrcRef
);
1340 ExFreePool(PinsRef
);
1342 if (NodeConnections
)
1343 ExFreePool(NodeConnections
);
1346 ExFreePool(NodeTypes
);
1349 ObDereferenceObject(FileObject
);
1354 if (PinConnectionIndex
)
1355 ExFreePool(PinConnectionIndex
);
1365 IN PDEVICE_OBJECT DeviceObject
,
1366 IN ULONG DeviceIndex
,
1367 IN OUT LPMIXER_INFO MixerInfo
,
1369 IN PFILE_OBJECT FileObject
,
1371 IN PKSMULTIPLE_ITEM NodeTypes
,
1372 IN PKSMULTIPLE_ITEM NodeConnections
,
1381 PKSPIN_PHYSICALCONNECTION OutConnection
;
1382 LPMIXERLINE_EXT DestinationLine
;
1384 DestinationLine
= ExAllocatePool(NonPagedPool
, sizeof(MIXERLINE_EXT
));
1385 if (!DestinationLine
)
1386 return STATUS_INSUFFICIENT_RESOURCES
;
1388 /* intialize mixer caps */
1389 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; //FIXME
1390 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; //FIXME
1391 MixerInfo
->MixCaps
.vDriverVersion
= 1; //FIXME
1392 MixerInfo
->MixCaps
.fdwSupport
= 0;
1393 MixerInfo
->MixCaps
.cDestinations
= 1;
1395 /* get target pnp name */
1396 Status
= GetSysAudioDevicePnpName(DeviceObject
, DeviceIndex
, &Device
);
1397 if (NT_SUCCESS(Status
))
1399 /* find product name */
1400 Status
= FindProductName(Device
, sizeof(Buffer
) / sizeof(WCHAR
), Buffer
);
1401 if (NT_SUCCESS(Status
))
1404 wcscat(Buffer
, L
" Input");
1406 wcscat(Buffer
, L
" output");
1407 RtlMoveMemory(MixerInfo
->MixCaps
.szPname
, Buffer
, min(MAXPNAMELEN
, wcslen(Buffer
)+1) * sizeof(WCHAR
));
1408 MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] = L
'\0';
1413 /* initialize mixer destination line */
1414 RtlZeroMemory(DestinationLine
, sizeof(MIXERLINEW
));
1415 DestinationLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
1416 DestinationLine
->Line
.dwSource
= MAXULONG
;
1417 DestinationLine
->Line
.dwLineID
= DESTINATION_LINE
;
1418 DestinationLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
;
1419 DestinationLine
->Line
.dwUser
= 0;
1420 DestinationLine
->Line
.dwComponentType
= (bInput
== 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
);
1421 DestinationLine
->Line
.cChannels
= 2; //FIXME
1422 wcscpy(DestinationLine
->Line
.szShortName
, L
"Summe"); //FIXME
1423 wcscpy(DestinationLine
->Line
.szName
, L
"Summe"); //FIXME
1424 DestinationLine
->Line
.Target
.dwType
= (bInput
== 0 ? MIXERLINE_TARGETTYPE_WAVEOUT
: MIXERLINE_TARGETTYPE_WAVEIN
);
1425 DestinationLine
->Line
.Target
.dwDeviceID
= !bInput
;
1426 DestinationLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
1427 DestinationLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
1428 DestinationLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
1429 wcscpy(DestinationLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
1431 /* initialize source line list */
1432 InitializeListHead(&MixerInfo
->LineList
);
1434 /* insert destination line */
1435 InsertHeadList(&MixerInfo
->LineList
, &DestinationLine
->Entry
);
1437 Pins
= AllocatePinArray(PinCount
);
1439 return STATUS_INSUFFICIENT_RESOURCES
;
1443 Status
= GetTargetPins(NodeTypes
, NodeConnections
, NodeIndex
, TRUE
, Pins
, PinCount
);
1447 Status
= GetTargetPins(NodeTypes
, NodeConnections
, NodeIndex
, FALSE
, Pins
, PinCount
);
1450 for(Index
= 0; Index
< PinCount
; Index
++)
1454 Status
= GetPhysicalConnection(FileObject
, Index
, &OutConnection
);
1455 if (NT_SUCCESS(Status
))
1457 Status
= HandlePhysicalConnection(MixerInfo
, DeviceObject
, bInput
, OutConnection
);
1458 ExFreePool(OutConnection
);
1464 return STATUS_SUCCESS
;
1468 WdmAudMixerInitialize(
1469 IN PDEVICE_OBJECT DeviceObject
)
1471 ULONG DeviceCount
, Index
, Count
, NodeIndex
, PinCount
;
1474 PFILE_OBJECT FileObject
;
1475 PKSMULTIPLE_ITEM NodeTypes
, NodeConnections
;
1476 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1478 /* get device extension */
1479 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1482 /* get number of devices */
1483 DeviceCount
= GetSysAudioDeviceCount(DeviceObject
);
1487 /* no audio devices available atm */
1488 DeviceExtension
->MixerInfoCount
= 0;
1489 DeviceExtension
->MixerInfo
= NULL
;
1490 return STATUS_SUCCESS
;
1493 /* each virtual audio device can at most have an input + output mixer */
1494 DeviceExtension
->MixerInfo
= ExAllocatePool(NonPagedPool
, sizeof(MIXER_INFO
) * DeviceCount
* 2);
1495 if (!DeviceExtension
->MixerInfo
)
1497 /* not enough memory */
1498 return STATUS_INSUFFICIENT_RESOURCES
;
1501 /* clear mixer info */
1502 RtlZeroMemory(DeviceExtension
->MixerInfo
, sizeof(MIXER_INFO
) * DeviceCount
* 2);
1508 /* open the virtual audio device */
1509 Status
= OpenSysAudioDeviceByIndex(DeviceObject
, Index
, &hDevice
, &FileObject
);
1511 if (NT_SUCCESS(Status
))
1513 /* retrieve all available node types */
1514 Status
= GetFilterNodeProperty(FileObject
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
1515 if (!NT_SUCCESS(Status
))
1517 ObDereferenceObject(FileObject
);
1522 Status
= GetFilterNodeProperty(FileObject
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
1523 if (!NT_SUCCESS(Status
))
1525 ObDereferenceObject(FileObject
);
1527 ExFreePool(NodeTypes
);
1531 /* get num of pins */
1532 PinCount
= GetPinCount(FileObject
);
1533 /* get the first available dac node index */
1534 NodeIndex
= GetNodeTypeIndex(NodeTypes
, (LPGUID
)&KSNODETYPE_DAC
);
1535 if (NodeIndex
!= (ULONG
)-1)
1537 Status
= InitializeMixer(DeviceObject
, Index
, &DeviceExtension
->MixerInfo
[Count
], hDevice
, FileObject
, PinCount
, NodeTypes
, NodeConnections
, NodeIndex
, FALSE
);
1538 if (NT_SUCCESS(Status
))
1540 /* increment mixer offset */
1545 /* get the first available adc node index */
1546 NodeIndex
= GetNodeTypeIndex(NodeTypes
, (LPGUID
)&KSNODETYPE_ADC
);
1547 if (NodeIndex
!= (ULONG
)-1)
1549 Status
= InitializeMixer(DeviceObject
, Index
, &DeviceExtension
->MixerInfo
[Count
], hDevice
, FileObject
, PinCount
, NodeTypes
, NodeConnections
, NodeIndex
, TRUE
);
1550 if (NT_SUCCESS(Status
))
1552 /* increment mixer offset */
1557 /* free node connections array */
1558 ExFreePool(NodeTypes
);
1559 ExFreePool(NodeConnections
);
1561 /* close virtual audio device */
1562 ObDereferenceObject(FileObject
);
1566 /* increment virtual audio device index */
1568 }while(Index
< DeviceCount
);
1570 /* store mixer count */
1571 DeviceExtension
->MixerInfoCount
= Count
;
1579 WdmAudMixerCapabilities(
1580 IN PDEVICE_OBJECT DeviceObject
,
1581 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1582 IN PWDMAUD_CLIENT ClientInfo
,
1583 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension
)
1585 if ((ULONG
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1587 /* invalid parameter */
1588 return STATUS_INVALID_PARAMETER
;
1591 /* copy cached mixer caps */
1592 RtlMoveMemory(&DeviceInfo
->u
.MixCaps
, &DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
].MixCaps
, sizeof(MIXERCAPSW
));
1594 return STATUS_SUCCESS
;
1599 WdmAudControlOpenMixer(
1600 IN PDEVICE_OBJECT DeviceObject
,
1602 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1603 IN PWDMAUD_CLIENT ClientInfo
)
1606 PWDMAUD_HANDLE Handels
;
1607 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1609 DPRINT("WdmAudControlOpenMixer\n");
1611 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1614 if (DeviceInfo
->DeviceIndex
>= DeviceExtension
->MixerInfoCount
)
1616 /* mixer index doesnt exist */
1617 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
1620 for(Index
= 0; Index
< ClientInfo
->NumPins
; Index
++)
1622 if (ClientInfo
->hPins
[Index
].Handle
== (HANDLE
)DeviceInfo
->DeviceIndex
&& ClientInfo
->hPins
[Index
].Type
== MIXER_DEVICE_TYPE
)
1624 /* re-use pseudo handle */
1625 DeviceInfo
->hDevice
= (HANDLE
)DeviceInfo
->DeviceIndex
;
1626 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1630 Handels
= ExAllocatePool(NonPagedPool
, sizeof(WDMAUD_HANDLE
) * (ClientInfo
->NumPins
+1));
1634 if (ClientInfo
->NumPins
)
1636 RtlMoveMemory(Handels
, ClientInfo
->hPins
, sizeof(WDMAUD_HANDLE
) * ClientInfo
->NumPins
);
1637 ExFreePool(ClientInfo
->hPins
);
1640 ClientInfo
->hPins
= Handels
;
1641 ClientInfo
->hPins
[ClientInfo
->NumPins
].Handle
= (HANDLE
)DeviceInfo
->DeviceIndex
;
1642 ClientInfo
->hPins
[ClientInfo
->NumPins
].Type
= MIXER_DEVICE_TYPE
;
1643 ClientInfo
->NumPins
++;
1647 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(WDMAUD_DEVICE_INFO
));
1649 DeviceInfo
->hDevice
= (HANDLE
)DeviceInfo
->DeviceIndex
;
1651 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1657 IN PDEVICE_OBJECT DeviceObject
,
1659 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1660 IN PWDMAUD_CLIENT ClientInfo
)
1662 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1663 LPMIXERLINE_EXT MixerLineSrc
;
1665 /* get device extension */
1666 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1668 if (DeviceInfo
->Flags
== MIXER_GETLINEINFOF_DESTINATION
)
1670 if ((ULONG
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1672 /* invalid parameter */
1673 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1676 if (DeviceInfo
->u
.MixLine
.dwDestination
!= 0)
1678 /* invalid parameter */
1679 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1681 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DESTINATION_LINE
);
1682 ASSERT(MixerLineSrc
);
1684 /* copy cached data */
1685 RtlCopyMemory(&DeviceInfo
->u
.MixLine
, &MixerLineSrc
->Line
, sizeof(MIXERLINEW
));
1686 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1688 else if (DeviceInfo
->Flags
== MIXER_GETLINEINFOF_SOURCE
)
1690 if ((ULONG
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1692 /* invalid parameter */
1693 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1696 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DESTINATION_LINE
);
1697 ASSERT(MixerLineSrc
);
1699 if (DeviceInfo
->u
.MixLine
.dwSource
>= MixerLineSrc
->Line
.cConnections
)
1701 DPRINT1("dwSource %u Destinations %u\n", DeviceInfo
->u
.MixLine
.dwSource
, MixerLineSrc
->Line
.cConnections
);
1702 /* invalid parameter */
1703 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1706 MixerLineSrc
= GetSourceMixerLine(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixLine
.dwSource
);
1709 DPRINT("Line %u Name %S\n", MixerLineSrc
->Line
.dwSource
, MixerLineSrc
->Line
.szName
);
1710 RtlCopyMemory(&DeviceInfo
->u
.MixLine
, &MixerLineSrc
->Line
, sizeof(MIXERLINEW
));
1712 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1714 else if (DeviceInfo
->Flags
== MIXER_GETLINEINFOF_LINEID
)
1716 if ((ULONG
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1718 /* invalid parameter */
1719 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1722 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixLine
.dwLineID
);
1723 ASSERT(MixerLineSrc
);
1725 /* copy cached data */
1726 RtlCopyMemory(&DeviceInfo
->u
.MixLine
, &MixerLineSrc
->Line
, sizeof(MIXERLINEW
));
1727 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1731 DPRINT1("Flags %x\n", DeviceInfo
->Flags
);
1735 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
1741 WdmAudGetLineControls(
1742 IN PDEVICE_OBJECT DeviceObject
,
1744 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1745 IN PWDMAUD_CLIENT ClientInfo
)
1747 LPMIXERLINE_EXT MixerLineSrc
;
1748 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1751 /* get device extension */
1752 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1754 if (DeviceInfo
->Flags
== MIXER_GETLINECONTROLSF_ALL
)
1756 if ((ULONG
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1758 /* invalid parameter */
1759 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1762 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixControls
.dwLineID
);
1763 ASSERT(MixerLineSrc
);
1766 RtlMoveMemory(DeviceInfo
->u
.MixControls
.pamxctrl
, MixerLineSrc
->LineControls
, min(MixerLineSrc
->Line
.cControls
, DeviceInfo
->u
.MixControls
.cControls
) * sizeof(MIXERCONTROLW
));
1768 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1770 else if (DeviceInfo
->Flags
== MIXER_GETLINECONTROLSF_ONEBYTYPE
)
1772 if ((ULONG
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1774 /* invalid parameter */
1775 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1778 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixControls
.dwLineID
);
1779 ASSERT(MixerLineSrc
);
1782 for(Index
= 0; Index
< MixerLineSrc
->Line
.cControls
; Index
++)
1784 if (DeviceInfo
->u
.MixControls
.dwControlType
== MixerLineSrc
->LineControls
[Index
].dwControlType
)
1786 RtlMoveMemory(DeviceInfo
->u
.MixControls
.pamxctrl
, &MixerLineSrc
->LineControls
[Index
], sizeof(MIXERCONTROLW
));
1787 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1790 DPRINT1("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x\n", DeviceInfo
->u
.MixControls
.dwControlType
, DeviceInfo
->u
.MixControls
.dwLineID
);
1791 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(WDMAUD_DEVICE_INFO
));
1796 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
1801 SetGetMuteControlDetails(
1802 IN PDEVICE_OBJECT DeviceObject
,
1805 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1808 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
1811 PFILE_OBJECT FileObject
;
1813 ULONG BytesReturned
;
1814 LPMIXERCONTROLDETAILS_BOOLEAN Input
;
1816 if (DeviceInfo
->u
.MixDetails
.cbDetails
!= sizeof(MIXERCONTROLDETAILS_BOOLEAN
))
1817 return STATUS_INVALID_PARAMETER
;
1820 Input
= (LPMIXERCONTROLDETAILS_BOOLEAN
)DeviceInfo
->u
.MixDetails
.paDetails
;
1827 Value
= Input
->fValue
;
1829 /* open virtual audio device */
1830 Status
= OpenSysAudioDeviceByIndex(DeviceObject
, DeviceId
, &hDevice
, &FileObject
);
1832 if (!NT_SUCCESS(Status
))
1838 /* setup the request */
1839 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
1841 Property
.NodeProperty
.NodeId
= NodeId
;
1842 Property
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_MUTE
;
1843 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_TOPOLOGY
;
1844 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
1845 Property
.Channel
= MAXULONG
;
1848 Property
.NodeProperty
.Property
.Flags
|= KSPROPERTY_TYPE_SET
;
1850 Property
.NodeProperty
.Property
.Flags
|= KSPROPERTY_TYPE_GET
;
1852 /* send the request */
1853 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), (PVOID
)&Value
, sizeof(BOOL
), &BytesReturned
);
1855 ObDereferenceObject(FileObject
);
1861 Input
->fValue
= Value
;
1864 DPRINT("Status %x bSet %u NodeId %u Value %u\n", Status
, bSet
, NodeId
, Value
);
1870 WdmAudSetControlDetails(
1871 IN PDEVICE_OBJECT DeviceObject
,
1873 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1874 IN PWDMAUD_CLIENT ClientInfo
)
1876 LPMIXERLINE_EXT MixerLine
;
1877 LPMIXERCONTROLW MixerControl
;
1879 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1882 DPRINT1("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n",
1883 DeviceInfo
->u
.MixDetails
.cbStruct
, sizeof(MIXERCONTROLDETAILS
), DeviceInfo
->u
.MixDetails
.dwControlID
, DeviceInfo
->u
.MixDetails
.cChannels
, DeviceInfo
->u
.MixDetails
.cMultipleItems
, DeviceInfo
->u
.MixDetails
.cbDetails
, DeviceInfo
->u
.MixDetails
.paDetails
, DeviceInfo
->Flags
);
1885 if (DeviceInfo
->Flags
& MIXER_GETCONTROLDETAILSF_LISTTEXT
)
1888 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
1891 /* get device extension */
1892 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1894 /* get mixer control */
1895 Status
= GetMixerControlById(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixDetails
.dwControlID
, &MixerLine
, &MixerControl
, &NodeId
);
1897 if (!NT_SUCCESS(Status
))
1899 DPRINT1("MixerControl %x not found\n", DeviceInfo
->u
.MixDetails
.dwControlID
);
1900 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1903 Status
= STATUS_NOT_IMPLEMENTED
;
1904 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
1906 /* send the request */
1907 Status
= SetGetMuteControlDetails(DeviceObject
, MixerLine
->DeviceIndex
, NodeId
, DeviceInfo
, TRUE
);
1910 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
1916 WdmAudGetControlDetails(
1917 IN PDEVICE_OBJECT DeviceObject
,
1919 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1920 IN PWDMAUD_CLIENT ClientInfo
)
1922 LPMIXERLINE_EXT MixerLine
;
1923 LPMIXERCONTROLW MixerControl
;
1925 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1928 DPRINT1("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n",
1929 DeviceInfo
->u
.MixDetails
.cbStruct
, sizeof(MIXERCONTROLDETAILS
), DeviceInfo
->u
.MixDetails
.dwControlID
, DeviceInfo
->u
.MixDetails
.cChannels
, DeviceInfo
->u
.MixDetails
.cMultipleItems
, DeviceInfo
->u
.MixDetails
.cbDetails
, DeviceInfo
->u
.MixDetails
.paDetails
, DeviceInfo
->Flags
);
1931 if (DeviceInfo
->Flags
& MIXER_GETCONTROLDETAILSF_LISTTEXT
)
1934 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
1937 /* get device extension */
1938 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1940 /* get mixer control */
1941 Status
= GetMixerControlById(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixDetails
.dwControlID
, &MixerLine
, &MixerControl
, &NodeId
);
1943 if (!NT_SUCCESS(Status
))
1945 DPRINT1("MixerControl %x not found\n", DeviceInfo
->u
.MixDetails
.dwControlID
);
1946 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1949 Status
= STATUS_NOT_IMPLEMENTED
;
1950 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
1952 /* send the request */
1953 Status
= SetGetMuteControlDetails(DeviceObject
, MixerLine
->DeviceIndex
, NodeId
, DeviceInfo
, FALSE
);
1956 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));