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
)
54 GetMixerControlDataById(
59 LPMIXERCONTROL_DATA Control
;
62 Entry
= ListHead
->Flink
;
64 while(Entry
!= ListHead
)
66 Control
= (LPMIXERCONTROL_DATA
)CONTAINING_RECORD(Entry
, MIXERCONTROL_DATA
, Entry
);
67 DPRINT("dwSource %x dwSource %x\n", Control
->dwControlID
, dwControlId
);
68 if (Control
->dwControlID
== dwControlId
)
78 LPMIXER_INFO MixerInfo
,
80 LPMIXERLINE_EXT
*MixerLine
,
81 LPMIXERCONTROLW
*MixerControl
,
85 LPMIXERLINE_EXT MixerLineSrc
;
89 Entry
= MixerInfo
->LineList
.Flink
;
91 while(Entry
!= &MixerInfo
->LineList
)
93 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
95 for(Index
= 0; Index
< MixerLineSrc
->Line
.cControls
; Index
++)
97 if (MixerLineSrc
->LineControls
[Index
].dwControlID
== dwControlID
)
100 *MixerLine
= MixerLineSrc
;
102 *MixerControl
= &MixerLineSrc
->LineControls
[Index
];
104 *NodeId
= MixerLineSrc
->NodeIds
[Index
];
105 return STATUS_SUCCESS
;
108 Entry
= Entry
->Flink
;
111 return STATUS_NOT_FOUND
;
115 GetSourceMixerLineByComponentType(
116 LPMIXER_INFO MixerInfo
,
117 DWORD dwComponentType
)
120 LPMIXERLINE_EXT MixerLineSrc
;
122 /* get first entry */
123 Entry
= MixerInfo
->LineList
.Flink
;
125 while(Entry
!= &MixerInfo
->LineList
)
127 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
128 if (MixerLineSrc
->Line
.dwComponentType
== dwComponentType
)
131 Entry
= Entry
->Flink
;
138 GetSourceMixerLineByLineId(
139 LPMIXER_INFO MixerInfo
,
143 LPMIXERLINE_EXT MixerLineSrc
;
145 /* get first entry */
146 Entry
= MixerInfo
->LineList
.Flink
;
148 while(Entry
!= &MixerInfo
->LineList
)
150 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
151 DPRINT("dwLineID %x dwLineID %x\n", MixerLineSrc
->Line
.dwLineID
, dwLineID
);
152 if (MixerLineSrc
->Line
.dwLineID
== dwLineID
)
155 Entry
= Entry
->Flink
;
165 IN PFILE_OBJECT FileObject
)
169 ULONG NumPins
, BytesReturned
;
171 Pin
.Flags
= KSPROPERTY_TYPE_GET
;
172 Pin
.Set
= KSPROPSETID_Pin
;
173 Pin
.Id
= KSPROPERTY_PIN_CTYPES
;
175 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSPROPERTY
), (PVOID
)&NumPins
, sizeof(ULONG
), &BytesReturned
);
176 if (!NT_SUCCESS(Status
))
184 GetSysAudioDeviceCount(
185 IN PDEVICE_OBJECT DeviceObject
)
187 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
189 ULONG Count
, BytesReturned
;
192 /* setup the query request */
193 Pin
.Set
= KSPROPSETID_Sysaudio
;
194 Pin
.Id
= KSPROPERTY_SYSAUDIO_DEVICE_COUNT
;
195 Pin
.Flags
= KSPROPERTY_TYPE_GET
;
197 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
199 /* query sysaudio for the device count */
200 Status
= KsSynchronousIoControlDevice(DeviceExtension
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSPROPERTY
), (PVOID
)&Count
, sizeof(ULONG
), &BytesReturned
);
201 if (!NT_SUCCESS(Status
))
208 GetSysAudioDevicePnpName(
209 IN PDEVICE_OBJECT DeviceObject
,
210 IN ULONG DeviceIndex
,
216 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
218 /* first check if the device index is within bounds */
219 if (DeviceIndex
>= GetSysAudioDeviceCount(DeviceObject
))
220 return STATUS_INVALID_PARAMETER
;
222 /* setup the query request */
223 Pin
.Property
.Set
= KSPROPSETID_Sysaudio
;
224 Pin
.Property
.Id
= KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME
;
225 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
226 Pin
.PinId
= DeviceIndex
;
228 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
230 /* query sysaudio for the device path */
231 Status
= KsSynchronousIoControlDevice(DeviceExtension
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSPROPERTY
) + sizeof(ULONG
), NULL
, 0, &BytesReturned
);
233 /* check if the request failed */
234 if (Status
!= STATUS_BUFFER_TOO_SMALL
|| BytesReturned
== 0)
235 return STATUS_UNSUCCESSFUL
;
237 /* allocate buffer for the device */
238 *Device
= ExAllocatePool(NonPagedPool
, BytesReturned
);
240 return STATUS_INSUFFICIENT_RESOURCES
;
242 /* query sysaudio again for the device path */
243 Status
= KsSynchronousIoControlDevice(DeviceExtension
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSPROPERTY
) + sizeof(ULONG
), (PVOID
)*Device
, BytesReturned
, &BytesReturned
);
245 if (!NT_SUCCESS(Status
))
256 GetDeviceIndexFromPnpName(
257 IN PDEVICE_OBJECT DeviceObject
,
264 /* get device count */
265 Count
= GetSysAudioDeviceCount(DeviceObject
);
270 for(Index
= 0; Index
< Count
; Index
++)
272 /* get device name */
273 Status
= GetSysAudioDevicePnpName(DeviceObject
, Index
, &DeviceName
);
274 if (NT_SUCCESS(Status
))
276 if (!wcsicmp(Device
, DeviceName
))
278 /* found device index */
279 ExFreePool(DeviceName
);
282 ExFreePool(DeviceName
);
293 OUT PHANDLE DeviceHandle
,
294 OUT PFILE_OBJECT
* FileObject
)
299 /* now open the device */
300 Status
= WdmAudOpenSysAudioDevice(Device
, &hDevice
);
302 if (!NT_SUCCESS(Status
))
307 *DeviceHandle
= hDevice
;
311 Status
= ObReferenceObjectByHandle(hDevice
, FILE_READ_DATA
| FILE_WRITE_DATA
, IoFileObjectType
, KernelMode
, (PVOID
*)FileObject
, NULL
);
313 if (!NT_SUCCESS(Status
))
325 OpenSysAudioDeviceByIndex(
326 IN PDEVICE_OBJECT DeviceObject
,
327 IN ULONG DeviceIndex
,
328 IN PHANDLE DeviceHandle
,
329 IN PFILE_OBJECT
* FileObject
)
331 LPWSTR Device
= NULL
;
334 Status
= GetSysAudioDevicePnpName(DeviceObject
, DeviceIndex
, &Device
);
335 if (!NT_SUCCESS(Status
))
338 Status
= OpenDevice(Device
, DeviceHandle
, FileObject
);
340 /* free device buffer */
347 GetFilterNodeProperty(
348 IN PFILE_OBJECT FileObject
,
350 PKSMULTIPLE_ITEM
* Item
)
354 PKSMULTIPLE_ITEM MultipleItem
;
357 /* setup query request */
358 Property
.Id
= PropertyId
;
359 Property
.Flags
= KSPROPERTY_TYPE_GET
;
360 Property
.Set
= KSPROPSETID_Topology
;
362 /* query for required size */
363 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), NULL
, 0, &BytesReturned
);
365 /* check for success */
366 if (Status
!= STATUS_MORE_ENTRIES
)
369 /* allocate buffer */
370 MultipleItem
= (PKSMULTIPLE_ITEM
)ExAllocatePool(NonPagedPool
, BytesReturned
);
372 return STATUS_INSUFFICIENT_RESOURCES
;
374 /* query for required size */
375 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), (PVOID
)MultipleItem
, BytesReturned
, &BytesReturned
);
377 if (!NT_SUCCESS(Status
))
380 ExFreePool(MultipleItem
);
384 *Item
= MultipleItem
;
390 PKSMULTIPLE_ITEM MultipleItem
,
398 Guid
= (LPGUID
)(MultipleItem
+1);
400 /* iterate through node type array */
401 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
403 if (IsEqualGUIDAligned(NodeType
, Guid
))
405 /* found matching guid */
415 PKSMULTIPLE_ITEM MultipleItem
,
421 Guid
= (LPGUID
)(MultipleItem
+1);
423 /* iterate through node type array */
424 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
426 if (IsEqualGUIDAligned(NodeType
, Guid
))
428 /* found matching guid */
437 GetControlTypeFromTopologyNode(
440 if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_AGC
))
442 // automatic gain control
443 return MIXERCONTROL_CONTROLTYPE_ONOFF
;
445 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_LOUDNESS
))
448 return MIXERCONTROL_CONTROLTYPE_LOUDNESS
;
450 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_MUTE
))
453 return MIXERCONTROL_CONTROLTYPE_MUTE
;
455 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_TONE
))
459 // MIXERCONTROL_CONTROLTYPE_ONOFF if KSPROPERTY_AUDIO_BASS_BOOST is supported
460 // MIXERCONTROL_CONTROLTYPE_BASS if KSPROPERTY_AUDIO_BASS is supported
461 // MIXERCONTROL_CONTROLTYPE_TREBLE if KSPROPERTY_AUDIO_TREBLE is supported
463 return MIXERCONTROL_CONTROLTYPE_ONOFF
;
465 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_VOLUME
))
468 return MIXERCONTROL_CONTROLTYPE_VOLUME
;
470 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_PEAKMETER
))
473 return MIXERCONTROL_CONTROLTYPE_PEAKMETER
;
475 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_MUX
))
478 return MIXERCONTROL_CONTROLTYPE_MUX
;
480 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_MUX
))
483 return MIXERCONTROL_CONTROLTYPE_MUX
;
485 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_STEREO_WIDE
))
487 // stero wide control
488 return MIXERCONTROL_CONTROLTYPE_FADER
;
490 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_CHORUS
))
493 return MIXERCONTROL_CONTROLTYPE_FADER
;
495 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_REVERB
))
498 return MIXERCONTROL_CONTROLTYPE_FADER
;
500 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_SUPERMIX
))
503 // MIXERCONTROL_CONTROLTYPE_MUTE if KSPROPERTY_AUDIO_MUTE is supported
505 return MIXERCONTROL_CONTROLTYPE_VOLUME
;
512 GetPhysicalConnection(
513 IN PFILE_OBJECT FileObject
,
515 OUT PKSPIN_PHYSICALCONNECTION
*OutConnection
)
520 PKSPIN_PHYSICALCONNECTION Connection
;
522 /* setup the request */
523 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
524 Pin
.Property
.Id
= KSPROPERTY_PIN_PHYSICALCONNECTION
;
525 Pin
.Property
.Set
= KSPROPSETID_Pin
;
528 /* query the pin for the physical connection */
529 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
531 if (Status
== STATUS_NOT_FOUND
)
533 /* pin does not have a physical connection */
537 Connection
= ExAllocatePool(NonPagedPool
, BytesReturned
);
540 /* not enough memory */
541 return STATUS_INSUFFICIENT_RESOURCES
;
544 /* query the pin for the physical connection */
545 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Connection
, BytesReturned
, &BytesReturned
);
546 if (!NT_SUCCESS(Status
))
548 /* failed to query the physical connection */
549 ExFreePool(Connection
);
553 /* store connection */
554 *OutConnection
= Connection
;
560 IN PKSMULTIPLE_ITEM MultipleItem
,
564 OUT PULONG NodeReferenceCount
,
565 OUT PULONG
*NodeReference
)
567 ULONG Index
, Count
= 0;
568 PKSTOPOLOGY_CONNECTION Connection
;
571 /* KSMULTIPLE_ITEM is followed by several KSTOPOLOGY_CONNECTION */
572 Connection
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
574 /* first count all referenced nodes */
575 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
577 //DbgPrint("FromPin %u FromNode %u ToPin %u ToNode %u\n", Connection->FromNodePin, Connection->FromNode, Connection->ToNodePin, Connection->ToNode);
582 if (Connection
->FromNode
== NodeIndex
)
584 /* node id has a connection */
590 if (Connection
->ToNode
== NodeIndex
)
592 /* node id has a connection */
601 if (Connection
->FromNodePin
== NodeIndex
&& Connection
->FromNode
== KSFILTER_NODE
)
603 /* node id has a connection */
609 if (Connection
->ToNodePin
== NodeIndex
&& Connection
->ToNode
== KSFILTER_NODE
)
611 /* node id has a connection */
618 /* move to next connection */
624 /* now allocate node index array */
625 Refs
= ExAllocatePool(NonPagedPool
, sizeof(ULONG
) * Count
);
628 /* not enough memory */
629 return STATUS_INSUFFICIENT_RESOURCES
;
632 /* clear node index array */
633 RtlZeroMemory(Refs
, Count
* sizeof(ULONG
));
636 Connection
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
637 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
643 if (Connection
->FromNode
== NodeIndex
)
645 /* node id has a connection */
652 if (Connection
->ToNode
== NodeIndex
)
654 /* node id has a connection */
664 if (Connection
->FromNodePin
== NodeIndex
&& Connection
->FromNode
== KSFILTER_NODE
)
666 /* node id has a connection */
673 if (Connection
->ToNodePin
== NodeIndex
&& Connection
->ToNode
== KSFILTER_NODE
)
675 /* node id has a connection */
682 /* move to next connection */
687 *NodeReference
= Refs
;
688 *NodeReferenceCount
= Count
;
690 return STATUS_SUCCESS
;
695 GetTargetPinsByNodeConnectionIndex(
696 IN PKSMULTIPLE_ITEM NodeConnections
,
697 IN PKSMULTIPLE_ITEM NodeTypes
,
698 IN ULONG bUpDirection
,
699 IN ULONG NodeConnectionIndex
,
702 PKSTOPOLOGY_CONNECTION Connection
;
703 ULONG PinId
, NodeConnectionCount
, Index
;
704 PULONG NodeConnection
;
709 ASSERT(NodeConnectionIndex
< NodeConnections
->Count
);
711 Connection
= (PKSTOPOLOGY_CONNECTION
)(NodeConnections
+ 1);
713 DPRINT("FromNode %u FromNodePin %u -> ToNode %u ToNodePin %u\n", Connection
[NodeConnectionIndex
].FromNode
, Connection
[NodeConnectionIndex
].FromNodePin
, Connection
[NodeConnectionIndex
].ToNode
, Connection
[NodeConnectionIndex
].ToNodePin
);
715 if ((Connection
[NodeConnectionIndex
].ToNode
== KSFILTER_NODE
&& bUpDirection
== FALSE
) ||
716 (Connection
[NodeConnectionIndex
].FromNode
== KSFILTER_NODE
&& bUpDirection
== TRUE
))
718 /* iteration stops here */
720 PinId
= Connection
[NodeConnectionIndex
].FromNodePin
;
722 PinId
= Connection
[NodeConnectionIndex
].ToNodePin
;
724 DPRINT("GetTargetPinsByNodeIndex FOUND Target Pin %u Parsed %u\n", PinId
, Pins
[PinId
]);
726 /* mark pin index as a target pin */
728 return STATUS_SUCCESS
;
731 /* get all node indexes referenced by that node */
734 Status
= GetNodeIndexes(NodeConnections
, Connection
[NodeConnectionIndex
].FromNode
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
738 Status
= GetNodeIndexes(NodeConnections
, Connection
[NodeConnectionIndex
].ToNode
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
741 if (NT_SUCCESS(Status
))
743 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
745 /* iterate recursively into the nodes */
746 Status
= GetTargetPinsByNodeConnectionIndex(NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Pins
);
747 ASSERT(Status
== STATUS_SUCCESS
);
749 /* free node connection indexes */
750 ExFreePool(NodeConnection
);
760 PKSMULTIPLE_ITEM NodeTypes
,
761 PKSMULTIPLE_ITEM NodeConnections
,
763 IN ULONG bUpDirection
,
767 ULONG NodeConnectionCount
, Index
;
769 PULONG NodeConnection
;
772 ASSERT(NodeIndex
!= (ULONG
)-1);
774 /* get all node indexes referenced by that pin */
776 Status
= GetNodeIndexes(NodeConnections
, NodeIndex
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
778 Status
= GetNodeIndexes(NodeConnections
, NodeIndex
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
780 DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex
, Status
, NodeConnectionCount
);
782 if (NT_SUCCESS(Status
))
784 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
786 Status
= GetTargetPinsByNodeConnectionIndex(NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Pins
);
787 ASSERT(Status
== STATUS_SUCCESS
);
789 ExFreePool(NodeConnection
);
799 PULONG Pins
= ExAllocatePool(NonPagedPool
, PinCount
* sizeof(ULONG
));
803 RtlZeroMemory(Pins
, sizeof(ULONG
) * PinCount
);
808 PKSTOPOLOGY_CONNECTION
809 GetConnectionByIndex(
810 IN PKSMULTIPLE_ITEM MultipleItem
,
813 PKSTOPOLOGY_CONNECTION Descriptor
;
815 ASSERT(Index
< MultipleItem
->Count
);
817 Descriptor
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
818 return &Descriptor
[Index
];
823 IN PKSMULTIPLE_ITEM MultipleItem
,
828 ASSERT(Index
< MultipleItem
->Count
);
830 NodeType
= (LPGUID
)(MultipleItem
+ 1);
831 return &NodeType
[Index
];
835 GetControlsFromPinByConnectionIndex(
836 IN PKSMULTIPLE_ITEM NodeConnections
,
837 IN PKSMULTIPLE_ITEM NodeTypes
,
838 IN ULONG bUpDirection
,
839 IN ULONG NodeConnectionIndex
,
842 PKSTOPOLOGY_CONNECTION CurConnection
;
846 ULONG NodeConnectionCount
, Index
;
847 PULONG NodeConnection
;
850 /* get current connection */
851 CurConnection
= GetConnectionByIndex(NodeConnections
, NodeConnectionIndex
);
854 NodeIndex
= CurConnection
->FromNode
;
856 NodeIndex
= CurConnection
->ToNode
;
858 /* get target node type of current connection */
859 NodeType
= GetNodeType(NodeTypes
, NodeIndex
);
861 if (IsEqualGUIDAligned(NodeType
, &KSNODETYPE_SUM
) || IsEqualGUIDAligned(NodeType
, &KSNODETYPE_MUX
))
865 /* add the sum / mux node to destination line */
866 Nodes
[NodeIndex
] = TRUE
;
869 return STATUS_SUCCESS
;
872 /* now add the node */
873 Nodes
[NodeIndex
] = TRUE
;
876 /* get all node indexes referenced by that node */
879 Status
= GetNodeIndexes(NodeConnections
, NodeIndex
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
883 Status
= GetNodeIndexes(NodeConnections
, NodeIndex
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
886 if (NT_SUCCESS(Status
))
888 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
890 /* iterate recursively into the nodes */
891 Status
= GetControlsFromPinByConnectionIndex(NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Nodes
);
892 ASSERT(Status
== STATUS_SUCCESS
);
894 /* free node connection indexes */
895 ExFreePool(NodeConnection
);
903 IN PKSMULTIPLE_ITEM NodeConnections
,
904 IN PKSMULTIPLE_ITEM NodeTypes
,
906 IN ULONG bUpDirection
,
909 ULONG NodeConnectionCount
, Index
;
911 PULONG NodeConnection
;
914 ASSERT(PinId
!= (ULONG
)-1);
916 /* get all node indexes referenced by that pin */
918 Status
= GetNodeIndexes(NodeConnections
, PinId
, FALSE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
920 Status
= GetNodeIndexes(NodeConnections
, PinId
, FALSE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
922 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
924 /* get all associated controls */
925 Status
= GetControlsFromPinByConnectionIndex(NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Nodes
);
928 ExFreePool(NodeConnection
);
935 IN LPMIXER_INFO MixerInfo
,
936 IN PFILE_OBJECT FileObject
,
937 IN PKSMULTIPLE_ITEM NodeTypes
,
939 IN LPMIXERLINE_EXT MixerLine
,
940 OUT LPMIXERCONTROLW MixerControl
)
948 /* initialize mixer control */
949 MixerControl
->cbStruct
= sizeof(MIXERCONTROLW
);
950 MixerControl
->dwControlID
= MixerInfo
->ControlId
;
953 NodeType
= GetNodeType(NodeTypes
, NodeIndex
);
954 /* store control type */
955 MixerControl
->dwControlType
= GetControlTypeFromTopologyNode(NodeType
);
957 MixerControl
->fdwControl
= MIXERCONTROL_CONTROLF_UNIFORM
; //FIXME
958 MixerControl
->cMultipleItems
= 0; //FIXME
960 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
962 MixerControl
->Bounds
.dwMinimum
= 0;
963 MixerControl
->Bounds
.dwMaximum
= 1;
965 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
967 MixerControl
->Bounds
.dwMinimum
= 0;
968 MixerControl
->Bounds
.dwMaximum
= 0xFFFF;
969 MixerControl
->Metrics
.cSteps
= 0xC0; //FIXME
972 /* setup request to retrieve name */
973 Node
.NodeId
= NodeIndex
;
974 Node
.Property
.Id
= KSPROPERTY_TOPOLOGY_NAME
;
975 Node
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
976 Node
.Property
.Set
= KSPROPSETID_Topology
;
979 /* get node name size */
980 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), NULL
, 0, &BytesReturned
);
982 if (Status
== STATUS_BUFFER_TOO_SMALL
)
984 ASSERT(BytesReturned
!= 0);
985 Name
= ExAllocatePool(NonPagedPool
, BytesReturned
);
988 /* not enough memory */
989 return STATUS_INSUFFICIENT_RESOURCES
;
993 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), (LPVOID
)Name
, BytesReturned
, &BytesReturned
);
994 if (NT_SUCCESS(Status
))
996 RtlMoveMemory(MixerControl
->szShortName
, Name
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
997 MixerControl
->szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
999 RtlMoveMemory(MixerControl
->szName
, Name
, (min(MIXER_LONG_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
1000 MixerControl
->szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
1003 /* free name buffer */
1007 MixerInfo
->ControlId
++;
1009 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUX
)
1011 KSNODEPROPERTY Property
;
1014 /* setup the request */
1015 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY
));
1017 Property
.NodeId
= NodeIndex
;
1018 Property
.Property
.Id
= KSPROPERTY_AUDIO_MUX_SOURCE
;
1019 Property
.Property
.Flags
= KSPROPERTY_TYPE_SET
;
1020 Property
.Property
.Set
= KSPROPSETID_Audio
;
1022 /* get node volume level info */
1023 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY
), (PVOID
)&PinId
, sizeof(ULONG
), &BytesReturned
);
1025 DPRINT1("Status %x NodeIndex %u PinId %u\n", Status
, NodeIndex
, PinId
);
1029 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
1031 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
1033 PKSPROPERTY_DESCRIPTION Desc
;
1034 PKSPROPERTY_MEMBERSHEADER Members
;
1035 PKSPROPERTY_STEPPING_LONG Range
;
1037 Length
= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) + sizeof(KSPROPERTY_STEPPING_LONG
);
1038 Desc
= ExAllocatePool(NonPagedPool
, Length
);
1040 RtlZeroMemory(Desc
, Length
);
1042 /* setup the request */
1043 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
1045 Property
.NodeProperty
.NodeId
= NodeIndex
;
1046 Property
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
1047 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
;
1048 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
1050 /* get node volume level info */
1051 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), Desc
, Length
, &BytesReturned
);
1053 if (NT_SUCCESS(Status
))
1055 LPMIXERVOLUME_DATA VolumeData
;
1056 ULONG Steps
, MaxRange
, Index
;
1059 Members
= (PKSPROPERTY_MEMBERSHEADER
)(Desc
+ 1);
1060 Range
= (PKSPROPERTY_STEPPING_LONG
)(Members
+ 1); //98304
1062 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
);
1064 MaxRange
= Range
->Bounds
.UnsignedMaximum
- Range
->Bounds
.UnsignedMinimum
;
1069 VolumeData
= ExAllocatePool(NonPagedPool
, sizeof(MIXERVOLUME_DATA
));
1071 return STATUS_INSUFFICIENT_RESOURCES
;
1073 Steps
= MaxRange
/ Range
->SteppingDelta
+ 1;
1075 /* store mixer control info there */
1076 VolumeData
->Header
.dwControlID
= MixerControl
->dwControlID
;
1077 VolumeData
->SignedMaximum
= Range
->Bounds
.SignedMaximum
;
1078 VolumeData
->SignedMinimum
= Range
->Bounds
.SignedMinimum
;
1079 VolumeData
->SteppingDelta
= Range
->SteppingDelta
;
1080 VolumeData
->ValuesCount
= Steps
;
1081 VolumeData
->InputSteppingDelta
= 0x10000 / Steps
;
1083 VolumeData
->Values
= ExAllocatePool(NonPagedPool
, sizeof(LONG
) * Steps
);
1084 if (!VolumeData
->Values
)
1087 ExFreePool(VolumeData
);
1089 return STATUS_INSUFFICIENT_RESOURCES
;
1092 Value
= Range
->Bounds
.SignedMinimum
;
1093 for(Index
= 0; Index
< Steps
; Index
++)
1095 VolumeData
->Values
[Index
] = Value
;
1096 Value
+= Range
->SteppingDelta
;
1098 InsertTailList(&MixerLine
->LineControlsExtraData
, &VolumeData
->Header
.Entry
);
1105 DPRINT("Status %x Name %S\n", Status
, MixerControl
->szName
);
1106 return STATUS_SUCCESS
;
1111 IN OUT LPMIXER_INFO MixerInfo
,
1112 IN PFILE_OBJECT FileObject
,
1113 IN PKSMULTIPLE_ITEM NodeConnections
,
1114 IN PKSMULTIPLE_ITEM NodeTypes
,
1115 IN ULONG DeviceIndex
,
1117 IN ULONG bBridgePin
,
1118 IN ULONG bTargetPin
)
1120 LPMIXERLINE_EXT SrcLine
, DstLine
;
1125 ULONG BytesReturned
, ControlCount
, Index
;
1130 /* allocate src mixer line */
1131 SrcLine
= (LPMIXERLINE_EXT
)ExAllocatePool(NonPagedPool
, sizeof(MIXERLINE_EXT
));
1134 return STATUS_INSUFFICIENT_RESOURCES
;
1137 RtlZeroMemory(SrcLine
, sizeof(MIXERLINE_EXT
));
1142 ASSERT(!IsListEmpty(&MixerInfo
->LineList
));
1143 SrcLine
= GetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
1146 /* get destination line */
1147 DstLine
= GetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
1153 /* initialize mixer src line */
1154 SrcLine
->DeviceIndex
= DeviceIndex
;
1155 SrcLine
->PinId
= PinId
;
1156 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
1158 /* initialize mixer destination line */
1159 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
1160 SrcLine
->Line
.dwDestination
= 0;
1161 SrcLine
->Line
.dwSource
= DstLine
->Line
.cConnections
;
1162 SrcLine
->Line
.dwLineID
= (DstLine
->Line
.cConnections
* 0x10000);
1163 SrcLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
| MIXERLINE_LINEF_SOURCE
;
1164 SrcLine
->Line
.dwUser
= 0;
1165 SrcLine
->Line
.cChannels
= DstLine
->Line
.cChannels
;
1166 SrcLine
->Line
.cConnections
= 0;
1167 SrcLine
->Line
.Target
.dwType
= 1;
1168 SrcLine
->Line
.Target
.dwDeviceID
= DstLine
->Line
.Target
.dwDeviceID
;
1169 SrcLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
1170 SrcLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
1171 SrcLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
1172 InitializeListHead(&SrcLine
->LineControlsExtraData
);
1173 wcscpy(SrcLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
1177 /* allocate a node arrary */
1178 Nodes
= ExAllocatePool(NonPagedPool
, sizeof(ULONG
) * NodeTypes
->Count
);
1182 /* not enough memory */
1185 ExFreePool(SrcLine
);
1187 return STATUS_INSUFFICIENT_RESOURCES
;
1190 /* clear nodes array */
1191 RtlZeroMemory(Nodes
, sizeof(ULONG
) * NodeTypes
->Count
);
1193 Status
= GetControlsFromPin(NodeConnections
, NodeTypes
, PinId
, bTargetPin
, Nodes
);
1194 if (!NT_SUCCESS(Status
))
1196 /* something went wrong */
1199 ExFreePool(SrcLine
);
1205 /* now count all nodes controlled by that pin */
1207 for(Index
= 0; Index
< NodeTypes
->Count
; Index
++)
1213 /* now allocate the line controls */
1216 SrcLine
->LineControls
= ExAllocatePool(NonPagedPool
, sizeof(MIXERCONTROLW
) * ControlCount
);
1218 if (!SrcLine
->LineControls
)
1220 /* no memory available */
1223 ExFreePool(SrcLine
);
1226 return STATUS_INSUFFICIENT_RESOURCES
;
1229 SrcLine
->NodeIds
= ExAllocatePool(NonPagedPool
, sizeof(ULONG
) * ControlCount
);
1230 if (!SrcLine
->NodeIds
)
1232 /* no memory available */
1233 ExFreePool(SrcLine
->LineControls
);
1236 ExFreePool(SrcLine
);
1239 return STATUS_INSUFFICIENT_RESOURCES
;
1242 /* zero line controls */
1243 RtlZeroMemory(SrcLine
->LineControls
, sizeof(MIXERCONTROLW
) * ControlCount
);
1244 RtlZeroMemory(SrcLine
->NodeIds
, sizeof(ULONG
) * ControlCount
);
1247 for(Index
= 0; Index
< NodeTypes
->Count
; Index
++)
1251 /* store the node index for retrieving / setting details */
1252 SrcLine
->NodeIds
[ControlCount
] = Index
;
1254 Status
= AddMixerControl(MixerInfo
, FileObject
, NodeTypes
, Index
, SrcLine
, &SrcLine
->LineControls
[ControlCount
]);
1255 if (NT_SUCCESS(Status
))
1257 /* increment control count on success */
1262 /* store control count */
1263 SrcLine
->Line
.cControls
= ControlCount
;
1266 /* release nodes array */
1269 /* get pin category */
1272 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
1273 Pin
.Property
.Set
= KSPROPSETID_Pin
;
1274 Pin
.Property
.Id
= KSPROPERTY_PIN_CATEGORY
;
1276 /* try get pin category */
1277 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (LPVOID
)&NodeType
, sizeof(GUID
), &BytesReturned
);
1278 if (NT_SUCCESS(Status
))
1281 //map component type
1284 /* retrieve pin name */
1287 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
1288 Pin
.Property
.Set
= KSPROPSETID_Pin
;
1289 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
1291 /* try get pin name size */
1292 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
1294 if (Status
!= STATUS_MORE_ENTRIES
)
1296 SrcLine
->Line
.szShortName
[0] = L
'\0';
1297 SrcLine
->Line
.szName
[0] = L
'\0';
1301 PinName
= (LPWSTR
)ExAllocatePool(NonPagedPool
, BytesReturned
);
1304 /* try get pin name */
1305 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (LPVOID
)PinName
, BytesReturned
, &BytesReturned
);
1307 if (NT_SUCCESS(Status
))
1309 RtlMoveMemory(SrcLine
->Line
.szShortName
, PinName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
1310 SrcLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
1312 RtlMoveMemory(SrcLine
->Line
.szName
, PinName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
1313 SrcLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
1315 ExFreePool(PinName
);
1319 /* insert src line */
1322 InsertTailList(&MixerInfo
->LineList
, &SrcLine
->Entry
);
1323 DstLine
->Line
.cConnections
++;
1326 return STATUS_SUCCESS
;
1331 AddMixerSourceLines(
1332 IN OUT LPMIXER_INFO MixerInfo
,
1333 IN PFILE_OBJECT FileObject
,
1334 IN PKSMULTIPLE_ITEM NodeConnections
,
1335 IN PKSMULTIPLE_ITEM NodeTypes
,
1336 IN ULONG DeviceIndex
,
1338 IN ULONG BridgePinIndex
,
1339 IN ULONG TargetPinIndex
,
1343 NTSTATUS Status
= STATUS_SUCCESS
;
1345 for(Index
= PinsCount
; Index
> 0; Index
--)
1349 AddMixerSourceLine(MixerInfo
, FileObject
, NodeConnections
, NodeTypes
, DeviceIndex
, Index
-1, (Index
-1 == BridgePinIndex
), (Index
-1 == TargetPinIndex
));
1358 HandlePhysicalConnection(
1359 IN OUT LPMIXER_INFO MixerInfo
,
1360 IN PDEVICE_OBJECT DeviceObject
,
1362 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
1364 PULONG PinsRef
= NULL
, PinConnectionIndex
= NULL
, PinsSrcRef
;
1365 ULONG PinsRefCount
, Index
, PinConnectionIndexCount
, DeviceIndex
;
1367 HANDLE hDevice
= NULL
;
1368 PFILE_OBJECT FileObject
= NULL
;
1369 PKSMULTIPLE_ITEM NodeTypes
= NULL
;
1370 PKSMULTIPLE_ITEM NodeConnections
= NULL
;
1371 PULONG MixerControls
;
1372 ULONG MixerControlsCount
;
1375 /* open the connected filter */
1376 Status
= OpenDevice(OutConnection
->SymbolicLinkName
, &hDevice
, &FileObject
);
1377 if (!NT_SUCCESS(Status
))
1379 DPRINT1("OpenDevice failed with %x\n", Status
);
1383 /* get device index */
1384 DeviceIndex
= GetDeviceIndexFromPnpName(DeviceObject
, OutConnection
->SymbolicLinkName
);
1386 /* get connected filter pin count */
1387 PinsRefCount
= GetPinCount(FileObject
);
1388 ASSERT(PinsRefCount
);
1390 PinsRef
= AllocatePinArray(PinsRefCount
);
1394 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1398 /* get topology node types */
1399 Status
= GetFilterNodeProperty(FileObject
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
1400 if (!NT_SUCCESS(Status
))
1402 DPRINT1("GetFilterNodeProperty failed with %x\n", Status
);
1406 /* get topology connections */
1407 Status
= GetFilterNodeProperty(FileObject
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
1408 if (!NT_SUCCESS(Status
))
1410 DPRINT1("GetFilterNodeProperty failed with %x\n", Status
);
1413 /* gets connection index of the bridge pin which connects to a node */
1414 DPRINT("Pin %u\n", OutConnection
->Pin
);
1415 Status
= GetNodeIndexes(NodeConnections
, OutConnection
->Pin
, FALSE
, !bInput
, &PinConnectionIndexCount
, &PinConnectionIndex
);
1416 if (!NT_SUCCESS(Status
))
1418 DPRINT1("GetNodeIndexes failed with %x\n", Status
);
1422 /* there should be no split in the bride pin */
1423 ASSERT(PinConnectionIndexCount
== 1);
1425 /* find all target pins of this connection */
1426 Status
= GetTargetPinsByNodeConnectionIndex(NodeConnections
, NodeTypes
, FALSE
, PinConnectionIndex
[0], PinsRef
);
1427 if (!NT_SUCCESS(Status
))
1429 DPRINT1("GetTargetPinsByNodeConnectionIndex failed with %x\n", Status
);
1433 for(Index
= 0; Index
< PinsRefCount
; Index
++)
1438 /* found a target pin, now get all references */
1439 Status
= GetNodeIndexes(NodeConnections
, Index
, FALSE
, FALSE
, &MixerControlsCount
, &MixerControls
);
1440 if (!NT_SUCCESS(Status
))
1444 ASSERT(MixerControlsCount
== 1);
1447 PinsSrcRef
= AllocatePinArray(PinsRefCount
);
1451 ExFreePool(MixerControls
);
1452 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1455 /* now get all connected source pins */
1456 Status
= GetTargetPinsByNodeConnectionIndex(NodeConnections
, NodeTypes
, TRUE
, MixerControls
[0], PinsSrcRef
);
1457 if (!NT_SUCCESS(Status
))
1460 ExFreePool(MixerControls
);
1461 ExFreePool(PinsSrcRef
);
1462 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1466 /* add pins from target line */
1469 // dont add bridge pin for input mixers
1470 PinsSrcRef
[Index
] = TRUE
;
1471 PinsSrcRef
[OutConnection
->Pin
] = TRUE
;
1473 PinsSrcRef
[OutConnection
->Pin
] = TRUE
;
1475 Status
= AddMixerSourceLines(MixerInfo
, FileObject
, NodeConnections
, NodeTypes
, DeviceIndex
, PinsRefCount
, OutConnection
->Pin
, Index
, PinsSrcRef
);
1477 ExFreePool(MixerControls
);
1478 ExFreePool(PinsSrcRef
);
1485 ExFreePool(PinsRef
);
1487 if (NodeConnections
)
1488 ExFreePool(NodeConnections
);
1491 ExFreePool(NodeTypes
);
1494 ObDereferenceObject(FileObject
);
1499 if (PinConnectionIndex
)
1500 ExFreePool(PinConnectionIndex
);
1510 IN PDEVICE_OBJECT DeviceObject
,
1511 IN ULONG DeviceIndex
,
1512 IN OUT LPMIXER_INFO MixerInfo
,
1514 IN PFILE_OBJECT FileObject
,
1516 IN PKSMULTIPLE_ITEM NodeTypes
,
1517 IN PKSMULTIPLE_ITEM NodeConnections
,
1526 PKSPIN_PHYSICALCONNECTION OutConnection
;
1527 LPMIXERLINE_EXT DestinationLine
;
1529 DestinationLine
= ExAllocatePool(NonPagedPool
, sizeof(MIXERLINE_EXT
));
1530 if (!DestinationLine
)
1531 return STATUS_INSUFFICIENT_RESOURCES
;
1533 /* intialize mixer caps */
1534 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; //FIXME
1535 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; //FIXME
1536 MixerInfo
->MixCaps
.vDriverVersion
= 1; //FIXME
1537 MixerInfo
->MixCaps
.fdwSupport
= 0;
1538 MixerInfo
->MixCaps
.cDestinations
= 1;
1539 MixerInfo
->DeviceIndex
= DeviceIndex
;
1541 /* get target pnp name */
1542 Status
= GetSysAudioDevicePnpName(DeviceObject
, DeviceIndex
, &Device
);
1543 if (NT_SUCCESS(Status
))
1545 /* find product name */
1546 Status
= FindProductName(Device
, sizeof(Buffer
) / sizeof(WCHAR
), Buffer
);
1547 if (NT_SUCCESS(Status
))
1550 wcscat(Buffer
, L
" Input");
1552 wcscat(Buffer
, L
" output");
1553 RtlMoveMemory(MixerInfo
->MixCaps
.szPname
, Buffer
, min(MAXPNAMELEN
, wcslen(Buffer
)+1) * sizeof(WCHAR
));
1554 MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] = L
'\0';
1559 /* initialize mixer destination line */
1560 RtlZeroMemory(DestinationLine
, sizeof(MIXERLINE_EXT
));
1561 DestinationLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
1562 DestinationLine
->Line
.dwSource
= MAXULONG
;
1563 DestinationLine
->Line
.dwLineID
= DESTINATION_LINE
;
1564 DestinationLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
;
1565 DestinationLine
->Line
.dwUser
= 0;
1566 DestinationLine
->Line
.dwComponentType
= (bInput
== 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
);
1567 DestinationLine
->Line
.cChannels
= 2; //FIXME
1568 wcscpy(DestinationLine
->Line
.szShortName
, L
"Summe"); //FIXME
1569 wcscpy(DestinationLine
->Line
.szName
, L
"Summe"); //FIXME
1570 DestinationLine
->Line
.Target
.dwType
= (bInput
== 0 ? MIXERLINE_TARGETTYPE_WAVEOUT
: MIXERLINE_TARGETTYPE_WAVEIN
);
1571 DestinationLine
->Line
.Target
.dwDeviceID
= !bInput
;
1572 DestinationLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
1573 DestinationLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
1574 DestinationLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
1575 wcscpy(DestinationLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
1577 /* initialize source line list */
1578 InitializeListHead(&MixerInfo
->LineList
);
1579 InitializeListHead(&DestinationLine
->LineControlsExtraData
);
1581 /* insert destination line */
1582 InsertHeadList(&MixerInfo
->LineList
, &DestinationLine
->Entry
);
1584 Pins
= AllocatePinArray(PinCount
);
1586 return STATUS_INSUFFICIENT_RESOURCES
;
1590 Status
= GetTargetPins(NodeTypes
, NodeConnections
, NodeIndex
, TRUE
, Pins
, PinCount
);
1594 Status
= GetTargetPins(NodeTypes
, NodeConnections
, NodeIndex
, FALSE
, Pins
, PinCount
);
1597 for(Index
= 0; Index
< PinCount
; Index
++)
1601 Status
= GetPhysicalConnection(FileObject
, Index
, &OutConnection
);
1602 if (NT_SUCCESS(Status
))
1604 Status
= HandlePhysicalConnection(MixerInfo
, DeviceObject
, bInput
, OutConnection
);
1605 ExFreePool(OutConnection
);
1611 return STATUS_SUCCESS
;
1615 WdmAudMixerInitialize(
1616 IN PDEVICE_OBJECT DeviceObject
)
1618 ULONG DeviceCount
, Index
, Count
, NodeIndex
, PinCount
;
1621 PFILE_OBJECT FileObject
;
1622 PKSMULTIPLE_ITEM NodeTypes
, NodeConnections
;
1623 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1625 /* get device extension */
1626 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1629 /* get number of devices */
1630 DeviceCount
= GetSysAudioDeviceCount(DeviceObject
);
1634 /* no audio devices available atm */
1635 DeviceExtension
->MixerInfoCount
= 0;
1636 DeviceExtension
->MixerInfo
= NULL
;
1637 return STATUS_SUCCESS
;
1640 /* each virtual audio device can at most have an input + output mixer */
1641 DeviceExtension
->MixerInfo
= ExAllocatePool(NonPagedPool
, sizeof(MIXER_INFO
) * DeviceCount
* 2);
1642 if (!DeviceExtension
->MixerInfo
)
1644 /* not enough memory */
1645 return STATUS_INSUFFICIENT_RESOURCES
;
1648 /* clear mixer info */
1649 RtlZeroMemory(DeviceExtension
->MixerInfo
, sizeof(MIXER_INFO
) * DeviceCount
* 2);
1655 /* open the virtual audio device */
1656 Status
= OpenSysAudioDeviceByIndex(DeviceObject
, Index
, &hDevice
, &FileObject
);
1658 if (NT_SUCCESS(Status
))
1660 /* retrieve all available node types */
1661 Status
= GetFilterNodeProperty(FileObject
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
1662 if (!NT_SUCCESS(Status
))
1664 ObDereferenceObject(FileObject
);
1669 Status
= GetFilterNodeProperty(FileObject
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
1670 if (!NT_SUCCESS(Status
))
1672 ObDereferenceObject(FileObject
);
1674 ExFreePool(NodeTypes
);
1678 /* get num of pins */
1679 PinCount
= GetPinCount(FileObject
);
1680 /* get the first available dac node index */
1681 NodeIndex
= GetNodeTypeIndex(NodeTypes
, (LPGUID
)&KSNODETYPE_DAC
);
1682 if (NodeIndex
!= (ULONG
)-1)
1684 Status
= InitializeMixer(DeviceObject
, Index
, &DeviceExtension
->MixerInfo
[Count
], hDevice
, FileObject
, PinCount
, NodeTypes
, NodeConnections
, NodeIndex
, FALSE
);
1685 if (NT_SUCCESS(Status
))
1687 /* increment mixer offset */
1692 /* get the first available adc node index */
1693 NodeIndex
= GetNodeTypeIndex(NodeTypes
, (LPGUID
)&KSNODETYPE_ADC
);
1694 if (NodeIndex
!= (ULONG
)-1)
1696 Status
= InitializeMixer(DeviceObject
, Index
, &DeviceExtension
->MixerInfo
[Count
], hDevice
, FileObject
, PinCount
, NodeTypes
, NodeConnections
, NodeIndex
, TRUE
);
1697 if (NT_SUCCESS(Status
))
1699 /* increment mixer offset */
1704 /* free node connections array */
1705 ExFreePool(NodeTypes
);
1706 ExFreePool(NodeConnections
);
1708 /* close virtual audio device */
1709 ObDereferenceObject(FileObject
);
1713 /* increment virtual audio device index */
1715 }while(Index
< DeviceCount
);
1717 /* store mixer count */
1718 DeviceExtension
->MixerInfoCount
= Count
;
1726 WdmAudMixerCapabilities(
1727 IN PDEVICE_OBJECT DeviceObject
,
1728 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1729 IN PWDMAUD_CLIENT ClientInfo
,
1730 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension
)
1732 if ((ULONG
)DeviceInfo
->DeviceIndex
>= DeviceExtension
->MixerInfoCount
)
1734 /* invalid parameter */
1735 return STATUS_INVALID_PARAMETER
;
1738 /* copy cached mixer caps */
1739 RtlMoveMemory(&DeviceInfo
->u
.MixCaps
, &DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->DeviceIndex
].MixCaps
, sizeof(MIXERCAPSW
));
1741 return STATUS_SUCCESS
;
1746 WdmAudControlOpenMixer(
1747 IN PDEVICE_OBJECT DeviceObject
,
1749 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1750 IN PWDMAUD_CLIENT ClientInfo
)
1753 PWDMAUD_HANDLE Handels
;
1754 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1756 PKEVENT EventObject
= NULL
;
1758 DPRINT("WdmAudControlOpenMixer\n");
1760 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1762 if (DeviceInfo
->DeviceIndex
>= DeviceExtension
->MixerInfoCount
)
1764 /* mixer index doesnt exist */
1765 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
1768 if (DeviceInfo
->u
.hNotifyEvent
)
1770 Status
= ObReferenceObjectByHandle(DeviceInfo
->u
.hNotifyEvent
, EVENT_MODIFY_STATE
, ExEventObjectType
, UserMode
, (LPVOID
*)&EventObject
, NULL
);
1772 if (!NT_SUCCESS(Status
))
1774 DPRINT1("Invalid notify event passed %p from client %p\n", DeviceInfo
->u
.hNotifyEvent
, ClientInfo
);
1776 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
1781 for(Index
= 0; Index
< ClientInfo
->NumPins
; Index
++)
1783 if (ClientInfo
->hPins
[Index
].Handle
== (HANDLE
)DeviceInfo
->DeviceIndex
&& ClientInfo
->hPins
[Index
].Type
== MIXER_DEVICE_TYPE
)
1785 /* re-use pseudo handle */
1786 DeviceInfo
->hDevice
= (HANDLE
)DeviceInfo
->DeviceIndex
;
1787 ClientInfo
->hPins
[Index
].NotifyEvent
= EventObject
;
1788 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1792 Handels
= ExAllocatePool(NonPagedPool
, sizeof(WDMAUD_HANDLE
) * (ClientInfo
->NumPins
+1));
1796 if (ClientInfo
->NumPins
)
1798 RtlMoveMemory(Handels
, ClientInfo
->hPins
, sizeof(WDMAUD_HANDLE
) * ClientInfo
->NumPins
);
1799 ExFreePool(ClientInfo
->hPins
);
1802 ClientInfo
->hPins
= Handels
;
1803 ClientInfo
->hPins
[ClientInfo
->NumPins
].Handle
= (HANDLE
)DeviceInfo
->DeviceIndex
;
1804 ClientInfo
->hPins
[ClientInfo
->NumPins
].Type
= MIXER_DEVICE_TYPE
;
1805 ClientInfo
->hPins
[ClientInfo
->NumPins
].NotifyEvent
= EventObject
;
1806 ClientInfo
->NumPins
++;
1810 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(WDMAUD_DEVICE_INFO
));
1812 DeviceInfo
->hDevice
= (HANDLE
)DeviceInfo
->DeviceIndex
;
1814 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1820 IN PDEVICE_OBJECT DeviceObject
,
1822 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1823 IN PWDMAUD_CLIENT ClientInfo
)
1825 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1826 LPMIXERLINE_EXT MixerLineSrc
;
1828 /* get device extension */
1829 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1831 DeviceInfo
->Flags
&= ~MIXER_OBJECTF_HMIXER
;
1833 if (DeviceInfo
->Flags
== MIXER_GETLINEINFOF_DESTINATION
)
1835 if ((ULONG_PTR
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1837 /* invalid parameter */
1838 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1841 if (DeviceInfo
->u
.MixLine
.dwDestination
!= 0)
1843 /* invalid parameter */
1844 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1846 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG_PTR
)DeviceInfo
->hDevice
], DESTINATION_LINE
);
1847 ASSERT(MixerLineSrc
);
1849 /* copy cached data */
1850 RtlCopyMemory(&DeviceInfo
->u
.MixLine
, &MixerLineSrc
->Line
, sizeof(MIXERLINEW
));
1851 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1853 else if (DeviceInfo
->Flags
== MIXER_GETLINEINFOF_SOURCE
)
1855 if ((ULONG_PTR
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1857 /* invalid parameter */
1858 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1861 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG_PTR
)DeviceInfo
->hDevice
], DESTINATION_LINE
);
1862 ASSERT(MixerLineSrc
);
1864 if (DeviceInfo
->u
.MixLine
.dwSource
>= MixerLineSrc
->Line
.cConnections
)
1866 DPRINT1("dwSource %u > Destinations %u\n", DeviceInfo
->u
.MixLine
.dwSource
, MixerLineSrc
->Line
.cConnections
);
1867 /* invalid parameter */
1868 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1871 MixerLineSrc
= GetSourceMixerLine(&DeviceExtension
->MixerInfo
[(ULONG_PTR
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixLine
.dwSource
);
1874 DPRINT("Line %u Name %S\n", MixerLineSrc
->Line
.dwSource
, MixerLineSrc
->Line
.szName
);
1875 RtlCopyMemory(&DeviceInfo
->u
.MixLine
, &MixerLineSrc
->Line
, sizeof(MIXERLINEW
));
1877 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1879 else if (DeviceInfo
->Flags
== MIXER_GETLINEINFOF_LINEID
)
1881 if ((ULONG_PTR
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1883 /* invalid parameter */
1884 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1887 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG_PTR
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixLine
.dwLineID
);
1890 DPRINT1("Failed to find Line with id %u\n", DeviceInfo
->u
.MixLine
.dwLineID
);
1891 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1894 /* copy cached data */
1895 RtlCopyMemory(&DeviceInfo
->u
.MixLine
, &MixerLineSrc
->Line
, sizeof(MIXERLINEW
));
1896 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1898 else if (DeviceInfo
->Flags
== MIXER_GETLINEINFOF_COMPONENTTYPE
)
1900 if ((ULONG_PTR
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1902 /* invalid parameter */
1903 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1906 MixerLineSrc
= GetSourceMixerLineByComponentType(&DeviceExtension
->MixerInfo
[(ULONG_PTR
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixLine
.dwComponentType
);
1909 DPRINT1("Failed to find component type %x\n", DeviceInfo
->u
.MixLine
.dwComponentType
);
1910 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
1913 ASSERT(MixerLineSrc
);
1915 /* copy cached data */
1916 RtlCopyMemory(&DeviceInfo
->u
.MixLine
, &MixerLineSrc
->Line
, sizeof(MIXERLINEW
));
1917 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1920 DPRINT("Flags %x\n", DeviceInfo
->Flags
);
1924 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
1930 WdmAudGetLineControls(
1931 IN PDEVICE_OBJECT DeviceObject
,
1933 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1934 IN PWDMAUD_CLIENT ClientInfo
)
1936 LPMIXERLINE_EXT MixerLineSrc
;
1937 LPMIXERCONTROLW MixerControl
;
1938 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1942 /* get device extension */
1943 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1945 DeviceInfo
->Flags
&= ~MIXER_OBJECTF_HMIXER
;
1947 if (DeviceInfo
->Flags
== MIXER_GETLINECONTROLSF_ALL
)
1949 if ((ULONG_PTR
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1951 /* invalid parameter */
1952 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1955 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG_PTR
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixControls
.dwLineID
);
1956 ASSERT(MixerLineSrc
);
1959 RtlMoveMemory(DeviceInfo
->u
.MixControls
.pamxctrl
, MixerLineSrc
->LineControls
, min(MixerLineSrc
->Line
.cControls
, DeviceInfo
->u
.MixControls
.cControls
) * sizeof(MIXERCONTROLW
));
1961 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1963 else if (DeviceInfo
->Flags
== MIXER_GETLINECONTROLSF_ONEBYTYPE
)
1965 if ((ULONG_PTR
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1967 /* invalid parameter */
1968 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1971 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG_PTR
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixControls
.dwLineID
);
1972 ASSERT(MixerLineSrc
);
1975 for(Index
= 0; Index
< MixerLineSrc
->Line
.cControls
; Index
++)
1977 DPRINT("dwControlType %x\n", MixerLineSrc
->LineControls
[Index
].dwControlType
);
1978 if (DeviceInfo
->u
.MixControls
.dwControlType
== MixerLineSrc
->LineControls
[Index
].dwControlType
)
1980 RtlMoveMemory(DeviceInfo
->u
.MixControls
.pamxctrl
, &MixerLineSrc
->LineControls
[Index
], sizeof(MIXERCONTROLW
));
1981 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1984 DPRINT("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x cControls %u \n", DeviceInfo
->u
.MixControls
.dwControlType
, DeviceInfo
->u
.MixControls
.dwLineID
, MixerLineSrc
->Line
.cControls
);
1985 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(WDMAUD_DEVICE_INFO
));
1987 else if (DeviceInfo
->Flags
== MIXER_GETLINECONTROLSF_ONEBYID
)
1989 if ((ULONG_PTR
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1991 /* invalid parameter */
1992 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1994 DPRINT("MixerId %u ControlId %u\n",(ULONG_PTR
)DeviceInfo
->hDevice
, DeviceInfo
->u
.MixControls
.dwControlID
);
1995 Status
= GetMixerControlById(&DeviceExtension
->MixerInfo
[(ULONG_PTR
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixControls
.dwControlID
, NULL
, &MixerControl
, NULL
);
1996 if (NT_SUCCESS(Status
))
1998 RtlMoveMemory(DeviceInfo
->u
.MixControls
.pamxctrl
, MixerControl
, sizeof(MIXERCONTROLW
));
2000 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
2005 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
2010 SetGetControlDetails(
2011 IN PDEVICE_OBJECT DeviceObject
,
2014 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
2016 IN ULONG PropertyId
,
2018 IN PLONG InputValue
)
2020 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
2023 PFILE_OBJECT FileObject
;
2025 ULONG BytesReturned
;
2028 Value
= *InputValue
;
2030 /* open virtual audio device */
2031 Status
= OpenSysAudioDeviceByIndex(DeviceObject
, DeviceId
, &hDevice
, &FileObject
);
2033 if (!NT_SUCCESS(Status
))
2039 /* setup the request */
2040 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
2042 Property
.NodeProperty
.NodeId
= NodeId
;
2043 Property
.NodeProperty
.Property
.Id
= PropertyId
;
2044 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_TOPOLOGY
;
2045 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
2046 Property
.Channel
= Channel
;
2049 Property
.NodeProperty
.Property
.Flags
|= KSPROPERTY_TYPE_SET
;
2051 Property
.NodeProperty
.Property
.Flags
|= KSPROPERTY_TYPE_GET
;
2053 /* send the request */
2054 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), (PVOID
)&Value
, sizeof(LONG
), &BytesReturned
);
2056 ObDereferenceObject(FileObject
);
2061 *InputValue
= Value
;
2064 DPRINT("Status %x bSet %u NodeId %u Value %d PropertyId %u\n", Status
, bSet
, NodeId
, Value
, PropertyId
);
2069 NotifyWdmAudClients(
2070 IN PDEVICE_OBJECT DeviceObject
,
2071 IN ULONG NotificationType
,
2075 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
2077 PWDMAUD_CLIENT CurClient
;
2082 /* get device extension */
2083 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
2085 /* acquire client context lock */
2086 KeAcquireSpinLock(&DeviceExtension
->Lock
, &OldIrql
);
2088 /* point to first entry */
2089 Entry
= DeviceExtension
->WdmAudClientList
.Flink
;
2091 /* iterate through all clients */
2092 while(Entry
!= &DeviceExtension
->WdmAudClientList
)
2094 /* get client context */
2095 CurClient
= (PWDMAUD_CLIENT
)CONTAINING_RECORD(Entry
, WDMAUD_CLIENT
, Entry
);
2097 /* now iterate through all pins and try to find an matching handle */
2098 for(Index
= 0; Index
< CurClient
->NumPins
; Index
++)
2100 if (CurClient
->hPins
[Index
].Handle
== hMixer
&& CurClient
->hPins
[Index
].Type
== MIXER_DEVICE_TYPE
&& CurClient
->hPins
[Index
].NotifyEvent
)
2102 /* allocate event entry */
2103 Event
= (PMIXER_EVENT
)ExAllocatePool(NonPagedPool
, sizeof(MIXER_EVENT
));
2107 return STATUS_INSUFFICIENT_RESOURCES
;
2110 /* initialize event entry */
2111 Event
->hMixer
= hMixer
;
2112 Event
->NotificationType
= NotificationType
;
2113 Event
->Value
= Value
;
2115 /* insert event entry */
2116 InsertTailList(&CurClient
->MixerEventList
, &Event
->Entry
);
2118 DPRINT("Notifying %p hMixer %p Value %x NotificationType %u\n", CurClient
->hPins
[Index
].NotifyEvent
, hMixer
, Value
, NotificationType
);
2120 /* now signal the event */
2121 KeSetEvent(CurClient
->hPins
[Index
].NotifyEvent
, 0, FALSE
);
2125 /* search next client */
2130 /* move to next client */
2131 Entry
= Entry
->Flink
;
2134 /* release client context lock */
2135 KeReleaseSpinLock(&DeviceExtension
->Lock
, OldIrql
);
2138 return STATUS_SUCCESS
;
2142 SetGetMuteControlDetails(
2143 IN PDEVICE_OBJECT DeviceObject
,
2147 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
2150 LPMIXERCONTROLDETAILS_BOOLEAN Input
;
2154 if (DeviceInfo
->u
.MixDetails
.cbDetails
!= sizeof(MIXERCONTROLDETAILS_BOOLEAN
))
2155 return STATUS_INVALID_PARAMETER
;
2158 Input
= (LPMIXERCONTROLDETAILS_BOOLEAN
)DeviceInfo
->u
.MixDetails
.paDetails
;
2162 Value
= Input
->fValue
;
2164 /* set control details */
2165 Status
= SetGetControlDetails(DeviceObject
, DeviceId
, NodeId
, DeviceInfo
, bSet
, KSPROPERTY_AUDIO_MUTE
, 0, &Value
);
2167 if (!NT_SUCCESS(Status
))
2173 Input
->fValue
= Value
;
2178 /* notify clients of a line change */
2179 NotifyWdmAudClients(DeviceObject
, MM_MIXM_LINE_CHANGE
, DeviceInfo
->hDevice
, dwLineID
);
2187 GetVolumeControlIndex(
2188 LPMIXERVOLUME_DATA VolumeData
,
2193 for(Index
= 0; Index
< VolumeData
->ValuesCount
; Index
++)
2195 if (VolumeData
->Values
[Index
] > Value
)
2197 return VolumeData
->InputSteppingDelta
* Index
;
2200 return VolumeData
->InputSteppingDelta
* (VolumeData
->ValuesCount
-1);
2205 SetGetVolumeControlDetails(
2206 IN PDEVICE_OBJECT DeviceObject
,
2209 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
2211 LPMIXERCONTROLW MixerControl
,
2212 LPMIXERLINE_EXT MixerLine
)
2214 LPMIXERCONTROLDETAILS_UNSIGNED Input
;
2215 LONG Value
, Index
, Channel
= 0;
2218 LPMIXERVOLUME_DATA VolumeData
;
2220 if (DeviceInfo
->u
.MixDetails
.cbDetails
!= sizeof(MIXERCONTROLDETAILS_SIGNED
))
2221 return STATUS_INVALID_PARAMETER
;
2223 VolumeData
= (LPMIXERVOLUME_DATA
)GetMixerControlDataById(&MixerLine
->LineControlsExtraData
, MixerControl
->dwControlID
);
2225 return STATUS_INSUFFICIENT_RESOURCES
;
2229 Input
= (LPMIXERCONTROLDETAILS_UNSIGNED
)DeviceInfo
->u
.MixDetails
.paDetails
;
2234 Value
= Input
->dwValue
;
2235 Index
= Value
/ VolumeData
->InputSteppingDelta
;
2237 if (Index
>= VolumeData
->ValuesCount
)
2239 DPRINT1("Index %u out of bounds %u \n", Index
, VolumeData
->ValuesCount
);
2241 return STATUS_INVALID_PARAMETER
;
2244 Value
= VolumeData
->Values
[Index
];
2247 /* set control details */
2250 Status
= SetGetControlDetails(DeviceObject
, DeviceId
, NodeId
, DeviceInfo
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 0, &Value
);
2251 Status
= SetGetControlDetails(DeviceObject
, DeviceId
, NodeId
, DeviceInfo
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 1, &Value
);
2255 Status
= SetGetControlDetails(DeviceObject
, DeviceId
, NodeId
, DeviceInfo
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, Channel
, &Value
);
2260 dwValue
= GetVolumeControlIndex(VolumeData
, (LONG
)Value
);
2262 Input
->dwValue
= dwValue
;
2266 /* notify clients of a line change */
2267 NotifyWdmAudClients(DeviceObject
, MM_MIXM_CONTROL_CHANGE
, DeviceInfo
->hDevice
, MixerControl
->dwControlID
);
2274 WdmAudGetMixerEvent(
2275 IN PDEVICE_OBJECT DeviceObject
,
2277 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
2278 IN PWDMAUD_CLIENT ClientInfo
)
2280 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
2281 PMIXER_EVENT Event
= NULL
;
2285 /* get device extension */
2286 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
2288 /* acquire client context lock */
2289 KeAcquireSpinLock(&DeviceExtension
->Lock
, &OldIrql
);
2291 /* point to first entry */
2292 Entry
= ClientInfo
->MixerEventList
.Flink
;
2294 while(Entry
!= &ClientInfo
->MixerEventList
)
2296 /* get mixer event */
2297 Event
= (PMIXER_EVENT
)CONTAINING_RECORD(Entry
, MIXER_EVENT
, Entry
);
2299 if (Event
->hMixer
== DeviceInfo
->hDevice
)
2301 /* found an event for that particular device */
2302 RemoveEntryList(&Event
->Entry
);
2306 /* no match found */
2309 /* move to next entry */
2310 Entry
= Entry
->Flink
;
2313 /* release client context lock */
2314 KeReleaseSpinLock(&DeviceExtension
->Lock
, OldIrql
);
2318 /* no events available */
2319 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
2322 /* store event result */
2323 DeviceInfo
->u
.MixerEvent
.hMixer
= Event
->hMixer
;
2324 DeviceInfo
->u
.MixerEvent
.NotificationType
= Event
->NotificationType
;
2325 DeviceInfo
->u
.MixerEvent
.Value
= Event
->Value
;
2327 /* free event info */
2331 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
2336 WdmAudSetControlDetails(
2337 IN PDEVICE_OBJECT DeviceObject
,
2339 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
2340 IN PWDMAUD_CLIENT ClientInfo
)
2342 LPMIXERLINE_EXT MixerLine
;
2343 LPMIXERCONTROLW MixerControl
;
2345 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
2348 DeviceInfo
->Flags
&= ~MIXER_OBJECTF_HMIXER
;
2350 DPRINT("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n",
2351 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
);
2353 if (DeviceInfo
->Flags
& MIXER_GETCONTROLDETAILSF_LISTTEXT
)
2356 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
2359 /* get device extension */
2360 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
2362 /* get mixer control */
2363 Status
= GetMixerControlById(&DeviceExtension
->MixerInfo
[(ULONG_PTR
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixDetails
.dwControlID
, &MixerLine
, &MixerControl
, &NodeId
);
2365 if (!NT_SUCCESS(Status
))
2367 DPRINT1("MixerControl %x not found\n", DeviceInfo
->u
.MixDetails
.dwControlID
);
2368 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
2371 Status
= STATUS_NOT_IMPLEMENTED
;
2372 DPRINT("dwLineId %x dwControlID %x dwControlType %x\n", MixerLine
->Line
.dwLineID
, MixerControl
->dwControlID
, MixerControl
->dwControlType
);
2373 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
2375 /* send the request */
2376 Status
= SetGetMuteControlDetails(DeviceObject
, MixerLine
->DeviceIndex
, NodeId
, MixerLine
->Line
.dwLineID
, DeviceInfo
, TRUE
);
2378 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
2380 Status
= SetGetVolumeControlDetails(DeviceObject
, MixerLine
->DeviceIndex
, NodeId
, DeviceInfo
, TRUE
, MixerControl
, MixerLine
);
2382 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
2388 WdmAudGetControlDetails(
2389 IN PDEVICE_OBJECT DeviceObject
,
2391 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
2392 IN PWDMAUD_CLIENT ClientInfo
)
2394 LPMIXERLINE_EXT MixerLine
;
2395 LPMIXERCONTROLW MixerControl
;
2397 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
2400 DeviceInfo
->Flags
&= ~MIXER_OBJECTF_HMIXER
;
2402 DPRINT("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n",
2403 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
);
2405 if (DeviceInfo
->Flags
& MIXER_GETCONTROLDETAILSF_LISTTEXT
)
2408 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
2411 /* get device extension */
2412 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
2414 /* get mixer control */
2415 Status
= GetMixerControlById(&DeviceExtension
->MixerInfo
[(ULONG_PTR
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixDetails
.dwControlID
, &MixerLine
, &MixerControl
, &NodeId
);
2417 if (!NT_SUCCESS(Status
))
2419 DPRINT1("MixerControl %x not found\n", DeviceInfo
->u
.MixDetails
.dwControlID
);
2420 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
2423 Status
= STATUS_NOT_IMPLEMENTED
;
2424 DPRINT("dwLineId %x dwControlID %x dwControlType %x\n", MixerLine
->Line
.dwLineID
, MixerControl
->dwControlID
, MixerControl
->dwControlType
);
2425 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
2427 /* send the request */
2428 Status
= SetGetMuteControlDetails(DeviceObject
, MixerLine
->DeviceIndex
, NodeId
, MixerLine
->Line
.dwLineID
, DeviceInfo
, FALSE
);
2430 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
2432 Status
= SetGetVolumeControlDetails(DeviceObject
, MixerLine
->DeviceIndex
, NodeId
, DeviceInfo
, FALSE
, MixerControl
, MixerLine
);
2435 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));