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
.cConnections
; Index
++)
97 if (MixerLineSrc
->LineControls
[Index
].dwControlID
== dwControlID
)
99 *MixerLine
= MixerLineSrc
;
100 *MixerControl
= &MixerLineSrc
->LineControls
[Index
];
101 *NodeId
= MixerLineSrc
->NodeIds
[Index
];
102 return STATUS_SUCCESS
;
105 Entry
= Entry
->Flink
;
108 return STATUS_NOT_FOUND
;
114 GetSourceMixerLineByLineId(
115 LPMIXER_INFO MixerInfo
,
119 LPMIXERLINE_EXT MixerLineSrc
;
121 /* get first entry */
122 Entry
= MixerInfo
->LineList
.Flink
;
124 while(Entry
!= &MixerInfo
->LineList
)
126 MixerLineSrc
= (LPMIXERLINE_EXT
)CONTAINING_RECORD(Entry
, MIXERLINE_EXT
, Entry
);
127 DPRINT("dwLineID %x dwLineID %x\n", MixerLineSrc
->Line
.dwLineID
, dwLineID
);
128 if (MixerLineSrc
->Line
.dwLineID
== dwLineID
)
131 Entry
= Entry
->Flink
;
141 IN PFILE_OBJECT FileObject
)
145 ULONG NumPins
, BytesReturned
;
147 Pin
.Flags
= KSPROPERTY_TYPE_GET
;
148 Pin
.Set
= KSPROPSETID_Pin
;
149 Pin
.Id
= KSPROPERTY_PIN_CTYPES
;
151 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSPROPERTY
), (PVOID
)&NumPins
, sizeof(ULONG
), &BytesReturned
);
152 if (!NT_SUCCESS(Status
))
160 GetSysAudioDeviceCount(
161 IN PDEVICE_OBJECT DeviceObject
)
163 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
165 ULONG Count
, BytesReturned
;
168 /* setup the query request */
169 Pin
.Set
= KSPROPSETID_Sysaudio
;
170 Pin
.Id
= KSPROPERTY_SYSAUDIO_DEVICE_COUNT
;
171 Pin
.Flags
= KSPROPERTY_TYPE_GET
;
173 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
175 /* query sysaudio for the device count */
176 Status
= KsSynchronousIoControlDevice(DeviceExtension
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSPROPERTY
), (PVOID
)&Count
, sizeof(ULONG
), &BytesReturned
);
177 if (!NT_SUCCESS(Status
))
184 GetSysAudioDevicePnpName(
185 IN PDEVICE_OBJECT DeviceObject
,
186 IN ULONG DeviceIndex
,
192 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
194 /* first check if the device index is within bounds */
195 if (DeviceIndex
>= GetSysAudioDeviceCount(DeviceObject
))
196 return STATUS_INVALID_PARAMETER
;
198 /* setup the query request */
199 Pin
.Property
.Set
= KSPROPSETID_Sysaudio
;
200 Pin
.Property
.Id
= KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME
;
201 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
202 Pin
.PinId
= DeviceIndex
;
204 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
206 /* query sysaudio for the device path */
207 Status
= KsSynchronousIoControlDevice(DeviceExtension
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSPROPERTY
) + sizeof(ULONG
), NULL
, 0, &BytesReturned
);
209 /* check if the request failed */
210 if (Status
!= STATUS_BUFFER_TOO_SMALL
|| BytesReturned
== 0)
211 return STATUS_UNSUCCESSFUL
;
213 /* allocate buffer for the device */
214 *Device
= ExAllocatePool(NonPagedPool
, BytesReturned
);
216 return STATUS_INSUFFICIENT_RESOURCES
;
218 /* query sysaudio again for the device path */
219 Status
= KsSynchronousIoControlDevice(DeviceExtension
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSPROPERTY
) + sizeof(ULONG
), (PVOID
)*Device
, BytesReturned
, &BytesReturned
);
221 if (!NT_SUCCESS(Status
))
232 GetDeviceIndexFromPnpName(
233 IN PDEVICE_OBJECT DeviceObject
,
240 /* get device count */
241 Count
= GetSysAudioDeviceCount(DeviceObject
);
246 for(Index
= 0; Index
< Count
; Index
++)
248 /* get device name */
249 Status
= GetSysAudioDevicePnpName(DeviceObject
, Index
, &DeviceName
);
250 if (NT_SUCCESS(Status
))
252 if (!wcsicmp(Device
, DeviceName
))
254 /* found device index */
255 ExFreePool(DeviceName
);
258 ExFreePool(DeviceName
);
269 OUT PHANDLE DeviceHandle
,
270 OUT PFILE_OBJECT
* FileObject
)
275 /* now open the device */
276 Status
= WdmAudOpenSysAudioDevice(Device
, &hDevice
);
278 if (!NT_SUCCESS(Status
))
283 *DeviceHandle
= hDevice
;
287 Status
= ObReferenceObjectByHandle(hDevice
, FILE_READ_DATA
| FILE_WRITE_DATA
, IoFileObjectType
, KernelMode
, (PVOID
*)FileObject
, NULL
);
289 if (!NT_SUCCESS(Status
))
301 OpenSysAudioDeviceByIndex(
302 IN PDEVICE_OBJECT DeviceObject
,
303 IN ULONG DeviceIndex
,
304 IN PHANDLE DeviceHandle
,
305 IN PFILE_OBJECT
* FileObject
)
307 LPWSTR Device
= NULL
;
310 Status
= GetSysAudioDevicePnpName(DeviceObject
, DeviceIndex
, &Device
);
311 if (!NT_SUCCESS(Status
))
314 Status
= OpenDevice(Device
, DeviceHandle
, FileObject
);
316 /* free device buffer */
323 GetFilterNodeProperty(
324 IN PFILE_OBJECT FileObject
,
326 PKSMULTIPLE_ITEM
* Item
)
330 PKSMULTIPLE_ITEM MultipleItem
;
333 /* setup query request */
334 Property
.Id
= PropertyId
;
335 Property
.Flags
= KSPROPERTY_TYPE_GET
;
336 Property
.Set
= KSPROPSETID_Topology
;
338 /* query for required size */
339 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), NULL
, 0, &BytesReturned
);
341 /* check for success */
342 if (Status
!= STATUS_MORE_ENTRIES
)
345 /* allocate buffer */
346 MultipleItem
= (PKSMULTIPLE_ITEM
)ExAllocatePool(NonPagedPool
, BytesReturned
);
348 return STATUS_INSUFFICIENT_RESOURCES
;
350 /* query for required size */
351 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), (PVOID
)MultipleItem
, BytesReturned
, &BytesReturned
);
353 if (!NT_SUCCESS(Status
))
356 ExFreePool(MultipleItem
);
360 *Item
= MultipleItem
;
366 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 */
391 PKSMULTIPLE_ITEM MultipleItem
,
397 Guid
= (LPGUID
)(MultipleItem
+1);
399 /* iterate through node type array */
400 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
402 if (IsEqualGUIDAligned(NodeType
, Guid
))
404 /* found matching guid */
413 GetControlTypeFromTopologyNode(
416 if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_AGC
))
418 // automatic gain control
419 return MIXERCONTROL_CONTROLTYPE_ONOFF
;
421 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_LOUDNESS
))
424 return MIXERCONTROL_CONTROLTYPE_LOUDNESS
;
426 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_MUTE
))
429 return MIXERCONTROL_CONTROLTYPE_MUTE
;
431 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_TONE
))
435 // MIXERCONTROL_CONTROLTYPE_ONOFF if KSPROPERTY_AUDIO_BASS_BOOST is supported
436 // MIXERCONTROL_CONTROLTYPE_BASS if KSPROPERTY_AUDIO_BASS is supported
437 // MIXERCONTROL_CONTROLTYPE_TREBLE if KSPROPERTY_AUDIO_TREBLE is supported
439 return MIXERCONTROL_CONTROLTYPE_ONOFF
;
441 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_VOLUME
))
444 return MIXERCONTROL_CONTROLTYPE_VOLUME
;
446 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_PEAKMETER
))
449 return MIXERCONTROL_CONTROLTYPE_PEAKMETER
;
451 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_MUX
))
454 return MIXERCONTROL_CONTROLTYPE_MUX
;
456 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_MUX
))
459 return MIXERCONTROL_CONTROLTYPE_MUX
;
461 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_STEREO_WIDE
))
463 // stero wide control
464 return MIXERCONTROL_CONTROLTYPE_FADER
;
466 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_CHORUS
))
469 return MIXERCONTROL_CONTROLTYPE_FADER
;
471 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_REVERB
))
474 return MIXERCONTROL_CONTROLTYPE_FADER
;
476 else if (IsEqualGUIDAligned(NodeType
, (LPGUID
)&KSNODETYPE_SUPERMIX
))
479 // MIXERCONTROL_CONTROLTYPE_MUTE if KSPROPERTY_AUDIO_MUTE is supported
481 return MIXERCONTROL_CONTROLTYPE_VOLUME
;
488 GetPhysicalConnection(
489 IN PFILE_OBJECT FileObject
,
491 OUT PKSPIN_PHYSICALCONNECTION
*OutConnection
)
496 PKSPIN_PHYSICALCONNECTION Connection
;
498 /* setup the request */
499 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
500 Pin
.Property
.Id
= KSPROPERTY_PIN_PHYSICALCONNECTION
;
501 Pin
.Property
.Set
= KSPROPSETID_Pin
;
504 /* query the pin for the physical connection */
505 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
507 if (Status
== STATUS_NOT_FOUND
)
509 /* pin does not have a physical connection */
513 Connection
= ExAllocatePool(NonPagedPool
, BytesReturned
);
516 /* not enough memory */
517 return STATUS_INSUFFICIENT_RESOURCES
;
520 /* query the pin for the physical connection */
521 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Connection
, BytesReturned
, &BytesReturned
);
522 if (!NT_SUCCESS(Status
))
524 /* failed to query the physical connection */
525 ExFreePool(Connection
);
529 /* store connection */
530 *OutConnection
= Connection
;
536 IN PKSMULTIPLE_ITEM MultipleItem
,
540 OUT PULONG NodeReferenceCount
,
541 OUT PULONG
*NodeReference
)
543 ULONG Index
, Count
= 0;
544 PKSTOPOLOGY_CONNECTION Connection
;
547 /* KSMULTIPLE_ITEM is followed by several KSTOPOLOGY_CONNECTION */
548 Connection
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
550 /* first count all referenced nodes */
551 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
553 //DbgPrint("FromPin %u FromNode %u ToPin %u ToNode %u\n", Connection->FromNodePin, Connection->FromNode, Connection->ToNodePin, Connection->ToNode);
558 if (Connection
->FromNode
== NodeIndex
)
560 /* node id has a connection */
566 if (Connection
->ToNode
== NodeIndex
)
568 /* node id has a connection */
577 if (Connection
->FromNodePin
== NodeIndex
&& Connection
->FromNode
== KSFILTER_NODE
)
579 /* node id has a connection */
585 if (Connection
->ToNodePin
== NodeIndex
&& Connection
->ToNode
== KSFILTER_NODE
)
587 /* node id has a connection */
594 /* move to next connection */
600 /* now allocate node index array */
601 Refs
= ExAllocatePool(NonPagedPool
, sizeof(ULONG
) * Count
);
604 /* not enough memory */
605 return STATUS_INSUFFICIENT_RESOURCES
;
608 /* clear node index array */
609 RtlZeroMemory(Refs
, Count
* sizeof(ULONG
));
612 Connection
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
613 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
619 if (Connection
->FromNode
== NodeIndex
)
621 /* node id has a connection */
628 if (Connection
->ToNode
== NodeIndex
)
630 /* node id has a connection */
640 if (Connection
->FromNodePin
== NodeIndex
&& Connection
->FromNode
== KSFILTER_NODE
)
642 /* node id has a connection */
649 if (Connection
->ToNodePin
== NodeIndex
&& Connection
->ToNode
== KSFILTER_NODE
)
651 /* node id has a connection */
658 /* move to next connection */
663 *NodeReference
= Refs
;
664 *NodeReferenceCount
= Count
;
666 return STATUS_SUCCESS
;
671 GetTargetPinsByNodeConnectionIndex(
672 IN PKSMULTIPLE_ITEM NodeConnections
,
673 IN PKSMULTIPLE_ITEM NodeTypes
,
674 IN ULONG bUpDirection
,
675 IN ULONG NodeConnectionIndex
,
678 PKSTOPOLOGY_CONNECTION Connection
;
679 ULONG PinId
, NodeConnectionCount
, Index
;
680 PULONG NodeConnection
;
685 ASSERT(NodeConnectionIndex
< NodeConnections
->Count
);
687 Connection
= (PKSTOPOLOGY_CONNECTION
)(NodeConnections
+ 1);
689 DPRINT("FromNode %u FromNodePin %u -> ToNode %u ToNodePin %u\n", Connection
[NodeConnectionIndex
].FromNode
, Connection
[NodeConnectionIndex
].FromNodePin
, Connection
[NodeConnectionIndex
].ToNode
, Connection
[NodeConnectionIndex
].ToNodePin
);
691 if ((Connection
[NodeConnectionIndex
].ToNode
== KSFILTER_NODE
&& bUpDirection
== FALSE
) ||
692 (Connection
[NodeConnectionIndex
].FromNode
== KSFILTER_NODE
&& bUpDirection
== TRUE
))
694 /* iteration stops here */
696 PinId
= Connection
[NodeConnectionIndex
].FromNodePin
;
698 PinId
= Connection
[NodeConnectionIndex
].ToNodePin
;
700 DPRINT("GetTargetPinsByNodeIndex FOUND Target Pin %u Parsed %u\n", PinId
, Pins
[PinId
]);
702 /* mark pin index as a target pin */
704 return STATUS_SUCCESS
;
707 /* get all node indexes referenced by that node */
710 Status
= GetNodeIndexes(NodeConnections
, Connection
[NodeConnectionIndex
].FromNode
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
714 Status
= GetNodeIndexes(NodeConnections
, Connection
[NodeConnectionIndex
].ToNode
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
717 if (NT_SUCCESS(Status
))
719 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
721 /* iterate recursively into the nodes */
722 Status
= GetTargetPinsByNodeConnectionIndex(NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Pins
);
723 ASSERT(Status
== STATUS_SUCCESS
);
725 /* free node connection indexes */
726 ExFreePool(NodeConnection
);
736 PKSMULTIPLE_ITEM NodeTypes
,
737 PKSMULTIPLE_ITEM NodeConnections
,
739 IN ULONG bUpDirection
,
743 ULONG NodeConnectionCount
, Index
;
745 PULONG NodeConnection
;
748 ASSERT(NodeIndex
!= (ULONG
)-1);
750 /* get all node indexes referenced by that pin */
752 Status
= GetNodeIndexes(NodeConnections
, NodeIndex
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
754 Status
= GetNodeIndexes(NodeConnections
, NodeIndex
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
756 DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex
, Status
, NodeConnectionCount
);
758 if (NT_SUCCESS(Status
))
760 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
762 Status
= GetTargetPinsByNodeConnectionIndex(NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Pins
);
763 ASSERT(Status
== STATUS_SUCCESS
);
765 ExFreePool(NodeConnection
);
775 PULONG Pins
= ExAllocatePool(NonPagedPool
, PinCount
* sizeof(ULONG
));
779 RtlZeroMemory(Pins
, sizeof(ULONG
) * PinCount
);
784 PKSTOPOLOGY_CONNECTION
785 GetConnectionByIndex(
786 IN PKSMULTIPLE_ITEM MultipleItem
,
789 PKSTOPOLOGY_CONNECTION Descriptor
;
791 ASSERT(Index
< MultipleItem
->Count
);
793 Descriptor
= (PKSTOPOLOGY_CONNECTION
)(MultipleItem
+ 1);
794 return &Descriptor
[Index
];
799 IN PKSMULTIPLE_ITEM MultipleItem
,
804 ASSERT(Index
< MultipleItem
->Count
);
806 NodeType
= (LPGUID
)(MultipleItem
+ 1);
807 return &NodeType
[Index
];
811 GetControlsFromPinByConnectionIndex(
812 IN PKSMULTIPLE_ITEM NodeConnections
,
813 IN PKSMULTIPLE_ITEM NodeTypes
,
814 IN ULONG bUpDirection
,
815 IN ULONG NodeConnectionIndex
,
818 PKSTOPOLOGY_CONNECTION CurConnection
;
822 ULONG NodeConnectionCount
, Index
;
823 PULONG NodeConnection
;
826 /* get current connection */
827 CurConnection
= GetConnectionByIndex(NodeConnections
, NodeConnectionIndex
);
830 NodeIndex
= CurConnection
->FromNode
;
832 NodeIndex
= CurConnection
->ToNode
;
834 /* get target node type of current connection */
835 NodeType
= GetNodeType(NodeTypes
, NodeIndex
);
837 if (IsEqualGUIDAligned(NodeType
, &KSNODETYPE_SUM
) || IsEqualGUIDAligned(NodeType
, &KSNODETYPE_MUX
))
841 /* add the sum / mux node to destination line */
842 //Nodes[NodeIndex] = TRUE;
845 return STATUS_SUCCESS
;
848 /* now add the node */
849 Nodes
[NodeIndex
] = TRUE
;
852 /* get all node indexes referenced by that node */
855 Status
= GetNodeIndexes(NodeConnections
, NodeIndex
, TRUE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
859 Status
= GetNodeIndexes(NodeConnections
, NodeIndex
, TRUE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
862 if (NT_SUCCESS(Status
))
864 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
866 /* iterate recursively into the nodes */
867 Status
= GetControlsFromPinByConnectionIndex(NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Nodes
);
868 ASSERT(Status
== STATUS_SUCCESS
);
870 /* free node connection indexes */
871 ExFreePool(NodeConnection
);
879 IN PKSMULTIPLE_ITEM NodeConnections
,
880 IN PKSMULTIPLE_ITEM NodeTypes
,
882 IN ULONG bUpDirection
,
885 ULONG NodeConnectionCount
, Index
;
887 PULONG NodeConnection
;
890 ASSERT(PinId
!= (ULONG
)-1);
892 /* get all node indexes referenced by that pin */
894 Status
= GetNodeIndexes(NodeConnections
, PinId
, FALSE
, FALSE
, &NodeConnectionCount
, &NodeConnection
);
896 Status
= GetNodeIndexes(NodeConnections
, PinId
, FALSE
, TRUE
, &NodeConnectionCount
, &NodeConnection
);
898 for(Index
= 0; Index
< NodeConnectionCount
; Index
++)
900 /* get all associated controls */
901 Status
= GetControlsFromPinByConnectionIndex(NodeConnections
, NodeTypes
, bUpDirection
, NodeConnection
[Index
], Nodes
);
904 ExFreePool(NodeConnection
);
911 IN LPMIXER_INFO MixerInfo
,
912 IN PFILE_OBJECT FileObject
,
913 IN PKSMULTIPLE_ITEM NodeTypes
,
915 IN LPMIXERLINE_EXT MixerLine
,
916 OUT LPMIXERCONTROLW MixerControl
)
924 /* initialize mixer control */
925 MixerControl
->cbStruct
= sizeof(MIXERCONTROLW
);
926 MixerControl
->dwControlID
= MixerInfo
->ControlId
;
929 NodeType
= GetNodeType(NodeTypes
, NodeIndex
);
930 /* store control type */
931 MixerControl
->dwControlType
= GetControlTypeFromTopologyNode(NodeType
);
933 MixerControl
->fdwControl
= MIXERCONTROL_CONTROLF_UNIFORM
; //FIXME
934 MixerControl
->cMultipleItems
= 0; //FIXME
936 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
938 MixerControl
->Bounds
.dwMinimum
= 0;
939 MixerControl
->Bounds
.dwMaximum
= 1;
941 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
943 MixerControl
->Bounds
.dwMinimum
= 0;
944 MixerControl
->Bounds
.dwMaximum
= 0xFFFF;
945 MixerControl
->Metrics
.cSteps
= 0xC0; //FIXME
948 /* setup request to retrieve name */
949 Node
.NodeId
= NodeIndex
;
950 Node
.Property
.Id
= KSPROPERTY_TOPOLOGY_NAME
;
951 Node
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
952 Node
.Property
.Set
= KSPROPSETID_Topology
;
955 /* get node name size */
956 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), NULL
, 0, &BytesReturned
);
958 if (Status
== STATUS_BUFFER_TOO_SMALL
)
960 ASSERT(BytesReturned
!= 0);
961 Name
= ExAllocatePool(NonPagedPool
, BytesReturned
);
964 /* not enough memory */
965 return STATUS_INSUFFICIENT_RESOURCES
;
969 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Node
, sizeof(KSP_NODE
), (LPVOID
)Name
, BytesReturned
, &BytesReturned
);
970 if (NT_SUCCESS(Status
))
972 RtlMoveMemory(MixerControl
->szShortName
, Name
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
973 MixerControl
->szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
975 RtlMoveMemory(MixerControl
->szName
, Name
, (min(MIXER_LONG_NAME_CHARS
, wcslen(Name
)+1)) * sizeof(WCHAR
));
976 MixerControl
->szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
979 /* free name buffer */
983 MixerInfo
->ControlId
++;
985 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
987 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
989 PKSPROPERTY_DESCRIPTION Desc
;
990 PKSPROPERTY_MEMBERSHEADER Members
;
991 PKSPROPERTY_STEPPING_LONG Range
;
993 Length
= sizeof(KSPROPERTY_DESCRIPTION
) + sizeof(KSPROPERTY_MEMBERSHEADER
) + sizeof(KSPROPERTY_STEPPING_LONG
);
994 Desc
= ExAllocatePool(NonPagedPool
, Length
);
996 RtlZeroMemory(Desc
, Length
);
998 /* setup the request */
999 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
1001 Property
.NodeProperty
.NodeId
= NodeIndex
;
1002 Property
.NodeProperty
.Property
.Id
= KSPROPERTY_AUDIO_VOLUMELEVEL
;
1003 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_BASICSUPPORT
;
1004 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
1006 /* get node volume level info */
1007 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), Desc
, Length
, &BytesReturned
);
1009 if (NT_SUCCESS(Status
))
1011 LPMIXERVOLUME_DATA VolumeData
;
1012 ULONG Steps
, MaxRange
, Index
;
1015 Members
= (PKSPROPERTY_MEMBERSHEADER
)(Desc
+ 1);
1016 Range
= (PKSPROPERTY_STEPPING_LONG
)(Members
+ 1); //98304
1018 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
);
1020 VolumeData
= ExAllocatePool(NonPagedPool
, sizeof(MIXERVOLUME_DATA
));
1022 return STATUS_INSUFFICIENT_RESOURCES
;
1024 MaxRange
= (abs(Range
->Bounds
.SignedMinimum
) + abs(Range
->Bounds
.SignedMaximum
));
1025 Steps
= MaxRange
/ Range
->SteppingDelta
+ 1;
1027 /* store mixer control info there */
1028 VolumeData
->Header
.dwControlID
= MixerControl
->dwControlID
;
1029 VolumeData
->SignedMaximum
= Range
->Bounds
.SignedMaximum
;
1030 VolumeData
->SignedMinimum
= Range
->Bounds
.SignedMinimum
;
1031 VolumeData
->SteppingDelta
= Range
->SteppingDelta
;
1032 VolumeData
->ValuesCount
= Steps
;
1033 VolumeData
->InputSteppingDelta
= 0x10000 / Steps
;
1035 VolumeData
->Values
= ExAllocatePool(NonPagedPool
, sizeof(LONG
) * Steps
);
1036 if (!VolumeData
->Values
)
1039 ExFreePool(VolumeData
);
1041 return STATUS_INSUFFICIENT_RESOURCES
;
1044 Value
= Range
->Bounds
.SignedMinimum
;
1045 for(Index
= 0; Index
< Steps
; Index
++)
1047 VolumeData
->Values
[Index
] = Value
;
1048 Value
+= Range
->SteppingDelta
;
1050 InsertTailList(&MixerLine
->LineControlsExtraData
, &VolumeData
->Header
.Entry
);
1056 DPRINT("Status %x Name %S\n", Status
, MixerControl
->szName
);
1057 return STATUS_SUCCESS
;
1062 IN OUT LPMIXER_INFO MixerInfo
,
1063 IN PFILE_OBJECT FileObject
,
1064 IN PKSMULTIPLE_ITEM NodeConnections
,
1065 IN PKSMULTIPLE_ITEM NodeTypes
,
1066 IN ULONG DeviceIndex
,
1068 IN ULONG bBridgePin
,
1069 IN ULONG bTargetPin
)
1071 LPMIXERLINE_EXT SrcLine
, DstLine
;
1076 ULONG BytesReturned
, ControlCount
, Index
;
1081 /* allocate src mixer line */
1082 SrcLine
= (LPMIXERLINE_EXT
)ExAllocatePool(NonPagedPool
, sizeof(MIXERLINE_EXT
));
1085 return STATUS_INSUFFICIENT_RESOURCES
;
1088 RtlZeroMemory(SrcLine
, sizeof(MIXERLINE_EXT
));
1093 ASSERT(!IsListEmpty(&MixerInfo
->LineList
));
1094 SrcLine
= GetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
1097 /* get destination line */
1098 DstLine
= GetSourceMixerLineByLineId(MixerInfo
, DESTINATION_LINE
);
1104 /* initialize mixer src line */
1105 SrcLine
->DeviceIndex
= DeviceIndex
;
1106 SrcLine
->PinId
= PinId
;
1107 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
1109 /* initialize mixer destination line */
1110 SrcLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
1111 SrcLine
->Line
.dwDestination
= 0;
1112 SrcLine
->Line
.dwSource
= DstLine
->Line
.cConnections
;
1113 SrcLine
->Line
.dwLineID
= (DstLine
->Line
.cConnections
* 0x10000);
1114 SrcLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
| MIXERLINE_LINEF_SOURCE
;
1115 SrcLine
->Line
.dwUser
= 0;
1116 SrcLine
->Line
.cChannels
= DstLine
->Line
.cChannels
;
1117 SrcLine
->Line
.cConnections
= 0;
1118 SrcLine
->Line
.Target
.dwType
= 1;
1119 SrcLine
->Line
.Target
.dwDeviceID
= DstLine
->Line
.Target
.dwDeviceID
;
1120 SrcLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
1121 SrcLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
1122 SrcLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
1123 InitializeListHead(&SrcLine
->LineControlsExtraData
);
1124 wcscpy(SrcLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
1128 /* allocate a node arrary */
1129 Nodes
= ExAllocatePool(NonPagedPool
, sizeof(ULONG
) * NodeTypes
->Count
);
1133 /* not enough memory */
1136 ExFreePool(SrcLine
);
1138 return STATUS_INSUFFICIENT_RESOURCES
;
1141 /* clear nodes array */
1142 RtlZeroMemory(Nodes
, sizeof(ULONG
) * NodeTypes
->Count
);
1144 Status
= GetControlsFromPin(NodeConnections
, NodeTypes
, PinId
, bTargetPin
, Nodes
);
1145 if (!NT_SUCCESS(Status
))
1147 /* something went wrong */
1150 ExFreePool(SrcLine
);
1156 /* now count all nodes controlled by that pin */
1158 for(Index
= 0; Index
< NodeTypes
->Count
; Index
++)
1164 /* now allocate the line controls */
1167 SrcLine
->LineControls
= ExAllocatePool(NonPagedPool
, sizeof(MIXERCONTROLW
) * ControlCount
);
1169 if (!SrcLine
->LineControls
)
1171 /* no memory available */
1174 ExFreePool(SrcLine
);
1177 return STATUS_INSUFFICIENT_RESOURCES
;
1180 SrcLine
->NodeIds
= ExAllocatePool(NonPagedPool
, sizeof(ULONG
) * ControlCount
);
1181 if (!SrcLine
->NodeIds
)
1183 /* no memory available */
1184 ExFreePool(SrcLine
->LineControls
);
1187 ExFreePool(SrcLine
);
1190 return STATUS_INSUFFICIENT_RESOURCES
;
1193 /* zero line controls */
1194 RtlZeroMemory(SrcLine
->LineControls
, sizeof(MIXERCONTROLW
) * ControlCount
);
1195 RtlZeroMemory(SrcLine
->NodeIds
, sizeof(ULONG
) * ControlCount
);
1198 for(Index
= 0; Index
< NodeTypes
->Count
; Index
++)
1202 /* store the node index for retrieving / setting details */
1203 SrcLine
->NodeIds
[ControlCount
] = Index
;
1205 Status
= AddMixerControl(MixerInfo
, FileObject
, NodeTypes
, Index
, SrcLine
, &SrcLine
->LineControls
[ControlCount
]);
1206 if (NT_SUCCESS(Status
))
1208 /* increment control count on success */
1213 /* store control count */
1214 SrcLine
->Line
.cControls
= ControlCount
;
1217 /* release nodes array */
1220 /* get pin category */
1223 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
1224 Pin
.Property
.Set
= KSPROPSETID_Pin
;
1225 Pin
.Property
.Id
= KSPROPERTY_PIN_CATEGORY
;
1227 /* try get pin category */
1228 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (LPVOID
)&NodeType
, sizeof(GUID
), &BytesReturned
);
1229 if (NT_SUCCESS(Status
))
1232 //map component type
1235 /* retrieve pin name */
1238 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
1239 Pin
.Property
.Set
= KSPROPSETID_Pin
;
1240 Pin
.Property
.Id
= KSPROPERTY_PIN_NAME
;
1242 /* try get pin name size */
1243 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
1245 if (Status
!= STATUS_MORE_ENTRIES
)
1247 SrcLine
->Line
.szShortName
[0] = L
'\0';
1248 SrcLine
->Line
.szName
[0] = L
'\0';
1252 PinName
= (LPWSTR
)ExAllocatePool(NonPagedPool
, BytesReturned
);
1255 /* try get pin name */
1256 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (LPVOID
)PinName
, BytesReturned
, &BytesReturned
);
1258 if (NT_SUCCESS(Status
))
1260 RtlMoveMemory(SrcLine
->Line
.szShortName
, PinName
, (min(MIXER_SHORT_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
1261 SrcLine
->Line
.szShortName
[MIXER_SHORT_NAME_CHARS
-1] = L
'\0';
1263 RtlMoveMemory(SrcLine
->Line
.szName
, PinName
, (min(MIXER_LONG_NAME_CHARS
, wcslen(PinName
)+1)) * sizeof(WCHAR
));
1264 SrcLine
->Line
.szName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
1266 ExFreePool(PinName
);
1270 /* insert src line */
1273 InsertTailList(&MixerInfo
->LineList
, &SrcLine
->Entry
);
1274 DstLine
->Line
.cConnections
++;
1277 return STATUS_SUCCESS
;
1282 AddMixerSourceLines(
1283 IN OUT LPMIXER_INFO MixerInfo
,
1284 IN PFILE_OBJECT FileObject
,
1285 IN PKSMULTIPLE_ITEM NodeConnections
,
1286 IN PKSMULTIPLE_ITEM NodeTypes
,
1287 IN ULONG DeviceIndex
,
1289 IN ULONG BridgePinIndex
,
1290 IN ULONG TargetPinIndex
,
1294 NTSTATUS Status
= STATUS_SUCCESS
;
1296 for(Index
= PinsCount
; Index
> 0; Index
--)
1300 AddMixerSourceLine(MixerInfo
, FileObject
, NodeConnections
, NodeTypes
, DeviceIndex
, Index
-1, (Index
-1 == BridgePinIndex
), (Index
-1 == TargetPinIndex
));
1309 HandlePhysicalConnection(
1310 IN OUT LPMIXER_INFO MixerInfo
,
1311 IN PDEVICE_OBJECT DeviceObject
,
1313 IN PKSPIN_PHYSICALCONNECTION OutConnection
)
1315 PULONG PinsRef
= NULL
, PinConnectionIndex
= NULL
, PinsSrcRef
;
1316 ULONG PinsRefCount
, Index
, PinConnectionIndexCount
, DeviceIndex
;
1318 HANDLE hDevice
= NULL
;
1319 PFILE_OBJECT FileObject
= NULL
;
1320 PKSMULTIPLE_ITEM NodeTypes
= NULL
;
1321 PKSMULTIPLE_ITEM NodeConnections
= NULL
;
1322 PULONG MixerControls
;
1323 ULONG MixerControlsCount
;
1326 /* open the connected filter */
1327 Status
= OpenDevice(OutConnection
->SymbolicLinkName
, &hDevice
, &FileObject
);
1328 if (!NT_SUCCESS(Status
))
1330 DPRINT1("OpenDevice failed with %x\n", Status
);
1334 /* get device index */
1335 DeviceIndex
= GetDeviceIndexFromPnpName(DeviceObject
, OutConnection
->SymbolicLinkName
);
1337 /* get connected filter pin count */
1338 PinsRefCount
= GetPinCount(FileObject
);
1339 ASSERT(PinsRefCount
);
1341 PinsRef
= AllocatePinArray(PinsRefCount
);
1345 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1349 /* get topology node types */
1350 Status
= GetFilterNodeProperty(FileObject
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
1351 if (!NT_SUCCESS(Status
))
1353 DPRINT1("GetFilterNodeProperty failed with %x\n", Status
);
1357 /* get topology connections */
1358 Status
= GetFilterNodeProperty(FileObject
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
1359 if (!NT_SUCCESS(Status
))
1361 DPRINT1("GetFilterNodeProperty failed with %x\n", Status
);
1364 /* gets connection index of the bridge pin which connects to a node */
1365 DPRINT("Pin %u\n", OutConnection
->Pin
);
1366 Status
= GetNodeIndexes(NodeConnections
, OutConnection
->Pin
, FALSE
, !bInput
, &PinConnectionIndexCount
, &PinConnectionIndex
);
1367 if (!NT_SUCCESS(Status
))
1369 DPRINT1("GetNodeIndexes failed with %x\n", Status
);
1373 /* there should be no split in the bride pin */
1374 ASSERT(PinConnectionIndexCount
== 1);
1376 /* find all target pins of this connection */
1377 Status
= GetTargetPinsByNodeConnectionIndex(NodeConnections
, NodeTypes
, FALSE
, PinConnectionIndex
[0], PinsRef
);
1378 if (!NT_SUCCESS(Status
))
1380 DPRINT1("GetTargetPinsByNodeConnectionIndex failed with %x\n", Status
);
1384 for(Index
= 0; Index
< PinsRefCount
; Index
++)
1389 /* found a target pin, now get all references */
1390 Status
= GetNodeIndexes(NodeConnections
, Index
, FALSE
, FALSE
, &MixerControlsCount
, &MixerControls
);
1391 if (!NT_SUCCESS(Status
))
1395 ASSERT(MixerControlsCount
== 1);
1398 PinsSrcRef
= AllocatePinArray(PinsRefCount
);
1402 ExFreePool(MixerControls
);
1403 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1406 /* now get all connected source pins */
1407 Status
= GetTargetPinsByNodeConnectionIndex(NodeConnections
, NodeTypes
, TRUE
, MixerControls
[0], PinsSrcRef
);
1408 if (!NT_SUCCESS(Status
))
1411 ExFreePool(MixerControls
);
1412 ExFreePool(PinsSrcRef
);
1413 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1417 /* add pins from target line */
1420 // dont add bridge pin for input mixers
1421 PinsSrcRef
[Index
] = TRUE
;
1422 PinsSrcRef
[OutConnection
->Pin
] = TRUE
;
1425 Status
= AddMixerSourceLines(MixerInfo
, FileObject
, NodeConnections
, NodeTypes
, DeviceIndex
, PinsRefCount
, OutConnection
->Pin
, Index
, PinsSrcRef
);
1427 ExFreePool(MixerControls
);
1428 ExFreePool(PinsSrcRef
);
1435 ExFreePool(PinsRef
);
1437 if (NodeConnections
)
1438 ExFreePool(NodeConnections
);
1441 ExFreePool(NodeTypes
);
1444 ObDereferenceObject(FileObject
);
1449 if (PinConnectionIndex
)
1450 ExFreePool(PinConnectionIndex
);
1460 IN PDEVICE_OBJECT DeviceObject
,
1461 IN ULONG DeviceIndex
,
1462 IN OUT LPMIXER_INFO MixerInfo
,
1464 IN PFILE_OBJECT FileObject
,
1466 IN PKSMULTIPLE_ITEM NodeTypes
,
1467 IN PKSMULTIPLE_ITEM NodeConnections
,
1476 PKSPIN_PHYSICALCONNECTION OutConnection
;
1477 LPMIXERLINE_EXT DestinationLine
;
1479 DestinationLine
= ExAllocatePool(NonPagedPool
, sizeof(MIXERLINE_EXT
));
1480 if (!DestinationLine
)
1481 return STATUS_INSUFFICIENT_RESOURCES
;
1483 /* intialize mixer caps */
1484 MixerInfo
->MixCaps
.wMid
= MM_MICROSOFT
; //FIXME
1485 MixerInfo
->MixCaps
.wPid
= MM_PID_UNMAPPED
; //FIXME
1486 MixerInfo
->MixCaps
.vDriverVersion
= 1; //FIXME
1487 MixerInfo
->MixCaps
.fdwSupport
= 0;
1488 MixerInfo
->MixCaps
.cDestinations
= 1;
1490 /* get target pnp name */
1491 Status
= GetSysAudioDevicePnpName(DeviceObject
, DeviceIndex
, &Device
);
1492 if (NT_SUCCESS(Status
))
1494 /* find product name */
1495 Status
= FindProductName(Device
, sizeof(Buffer
) / sizeof(WCHAR
), Buffer
);
1496 if (NT_SUCCESS(Status
))
1499 wcscat(Buffer
, L
" Input");
1501 wcscat(Buffer
, L
" output");
1502 RtlMoveMemory(MixerInfo
->MixCaps
.szPname
, Buffer
, min(MAXPNAMELEN
, wcslen(Buffer
)+1) * sizeof(WCHAR
));
1503 MixerInfo
->MixCaps
.szPname
[MAXPNAMELEN
-1] = L
'\0';
1508 /* initialize mixer destination line */
1509 RtlZeroMemory(DestinationLine
, sizeof(MIXERLINEW
));
1510 DestinationLine
->Line
.cbStruct
= sizeof(MIXERLINEW
);
1511 DestinationLine
->Line
.dwSource
= MAXULONG
;
1512 DestinationLine
->Line
.dwLineID
= DESTINATION_LINE
;
1513 DestinationLine
->Line
.fdwLine
= MIXERLINE_LINEF_ACTIVE
;
1514 DestinationLine
->Line
.dwUser
= 0;
1515 DestinationLine
->Line
.dwComponentType
= (bInput
== 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
);
1516 DestinationLine
->Line
.cChannels
= 2; //FIXME
1517 wcscpy(DestinationLine
->Line
.szShortName
, L
"Summe"); //FIXME
1518 wcscpy(DestinationLine
->Line
.szName
, L
"Summe"); //FIXME
1519 DestinationLine
->Line
.Target
.dwType
= (bInput
== 0 ? MIXERLINE_TARGETTYPE_WAVEOUT
: MIXERLINE_TARGETTYPE_WAVEIN
);
1520 DestinationLine
->Line
.Target
.dwDeviceID
= !bInput
;
1521 DestinationLine
->Line
.Target
.wMid
= MixerInfo
->MixCaps
.wMid
;
1522 DestinationLine
->Line
.Target
.wPid
= MixerInfo
->MixCaps
.wPid
;
1523 DestinationLine
->Line
.Target
.vDriverVersion
= MixerInfo
->MixCaps
.vDriverVersion
;
1524 wcscpy(DestinationLine
->Line
.Target
.szPname
, MixerInfo
->MixCaps
.szPname
);
1526 /* initialize source line list */
1527 InitializeListHead(&MixerInfo
->LineList
);
1528 InitializeListHead(&DestinationLine
->LineControlsExtraData
);
1530 /* insert destination line */
1531 InsertHeadList(&MixerInfo
->LineList
, &DestinationLine
->Entry
);
1533 Pins
= AllocatePinArray(PinCount
);
1535 return STATUS_INSUFFICIENT_RESOURCES
;
1539 Status
= GetTargetPins(NodeTypes
, NodeConnections
, NodeIndex
, TRUE
, Pins
, PinCount
);
1543 Status
= GetTargetPins(NodeTypes
, NodeConnections
, NodeIndex
, FALSE
, Pins
, PinCount
);
1546 for(Index
= 0; Index
< PinCount
; Index
++)
1550 Status
= GetPhysicalConnection(FileObject
, Index
, &OutConnection
);
1551 if (NT_SUCCESS(Status
))
1553 Status
= HandlePhysicalConnection(MixerInfo
, DeviceObject
, bInput
, OutConnection
);
1554 ExFreePool(OutConnection
);
1560 return STATUS_SUCCESS
;
1564 WdmAudMixerInitialize(
1565 IN PDEVICE_OBJECT DeviceObject
)
1567 ULONG DeviceCount
, Index
, Count
, NodeIndex
, PinCount
;
1570 PFILE_OBJECT FileObject
;
1571 PKSMULTIPLE_ITEM NodeTypes
, NodeConnections
;
1572 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1574 /* get device extension */
1575 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1578 /* get number of devices */
1579 DeviceCount
= GetSysAudioDeviceCount(DeviceObject
);
1583 /* no audio devices available atm */
1584 DeviceExtension
->MixerInfoCount
= 0;
1585 DeviceExtension
->MixerInfo
= NULL
;
1586 return STATUS_SUCCESS
;
1589 /* each virtual audio device can at most have an input + output mixer */
1590 DeviceExtension
->MixerInfo
= ExAllocatePool(NonPagedPool
, sizeof(MIXER_INFO
) * DeviceCount
* 2);
1591 if (!DeviceExtension
->MixerInfo
)
1593 /* not enough memory */
1594 return STATUS_INSUFFICIENT_RESOURCES
;
1597 /* clear mixer info */
1598 RtlZeroMemory(DeviceExtension
->MixerInfo
, sizeof(MIXER_INFO
) * DeviceCount
* 2);
1604 /* open the virtual audio device */
1605 Status
= OpenSysAudioDeviceByIndex(DeviceObject
, Index
, &hDevice
, &FileObject
);
1607 if (NT_SUCCESS(Status
))
1609 /* retrieve all available node types */
1610 Status
= GetFilterNodeProperty(FileObject
, KSPROPERTY_TOPOLOGY_NODES
, &NodeTypes
);
1611 if (!NT_SUCCESS(Status
))
1613 ObDereferenceObject(FileObject
);
1618 Status
= GetFilterNodeProperty(FileObject
, KSPROPERTY_TOPOLOGY_CONNECTIONS
, &NodeConnections
);
1619 if (!NT_SUCCESS(Status
))
1621 ObDereferenceObject(FileObject
);
1623 ExFreePool(NodeTypes
);
1627 /* get num of pins */
1628 PinCount
= GetPinCount(FileObject
);
1629 /* get the first available dac node index */
1630 NodeIndex
= GetNodeTypeIndex(NodeTypes
, (LPGUID
)&KSNODETYPE_DAC
);
1631 if (NodeIndex
!= (ULONG
)-1)
1633 Status
= InitializeMixer(DeviceObject
, Index
, &DeviceExtension
->MixerInfo
[Count
], hDevice
, FileObject
, PinCount
, NodeTypes
, NodeConnections
, NodeIndex
, FALSE
);
1634 if (NT_SUCCESS(Status
))
1636 /* increment mixer offset */
1641 /* get the first available adc node index */
1642 NodeIndex
= GetNodeTypeIndex(NodeTypes
, (LPGUID
)&KSNODETYPE_ADC
);
1643 if (NodeIndex
!= (ULONG
)-1)
1645 Status
= InitializeMixer(DeviceObject
, Index
, &DeviceExtension
->MixerInfo
[Count
], hDevice
, FileObject
, PinCount
, NodeTypes
, NodeConnections
, NodeIndex
, TRUE
);
1646 if (NT_SUCCESS(Status
))
1648 /* increment mixer offset */
1653 /* free node connections array */
1654 ExFreePool(NodeTypes
);
1655 ExFreePool(NodeConnections
);
1657 /* close virtual audio device */
1658 ObDereferenceObject(FileObject
);
1662 /* increment virtual audio device index */
1664 }while(Index
< DeviceCount
);
1666 /* store mixer count */
1667 DeviceExtension
->MixerInfoCount
= Count
;
1675 WdmAudMixerCapabilities(
1676 IN PDEVICE_OBJECT DeviceObject
,
1677 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1678 IN PWDMAUD_CLIENT ClientInfo
,
1679 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension
)
1681 if ((ULONG
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1683 /* invalid parameter */
1684 return STATUS_INVALID_PARAMETER
;
1687 /* copy cached mixer caps */
1688 RtlMoveMemory(&DeviceInfo
->u
.MixCaps
, &DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
].MixCaps
, sizeof(MIXERCAPSW
));
1690 return STATUS_SUCCESS
;
1695 WdmAudControlOpenMixer(
1696 IN PDEVICE_OBJECT DeviceObject
,
1698 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1699 IN PWDMAUD_CLIENT ClientInfo
)
1702 PWDMAUD_HANDLE Handels
;
1703 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1705 DPRINT("WdmAudControlOpenMixer\n");
1707 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1710 if (DeviceInfo
->DeviceIndex
>= DeviceExtension
->MixerInfoCount
)
1712 /* mixer index doesnt exist */
1713 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
1716 for(Index
= 0; Index
< ClientInfo
->NumPins
; Index
++)
1718 if (ClientInfo
->hPins
[Index
].Handle
== (HANDLE
)DeviceInfo
->DeviceIndex
&& ClientInfo
->hPins
[Index
].Type
== MIXER_DEVICE_TYPE
)
1720 /* re-use pseudo handle */
1721 DeviceInfo
->hDevice
= (HANDLE
)DeviceInfo
->DeviceIndex
;
1722 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1726 Handels
= ExAllocatePool(NonPagedPool
, sizeof(WDMAUD_HANDLE
) * (ClientInfo
->NumPins
+1));
1730 if (ClientInfo
->NumPins
)
1732 RtlMoveMemory(Handels
, ClientInfo
->hPins
, sizeof(WDMAUD_HANDLE
) * ClientInfo
->NumPins
);
1733 ExFreePool(ClientInfo
->hPins
);
1736 ClientInfo
->hPins
= Handels
;
1737 ClientInfo
->hPins
[ClientInfo
->NumPins
].Handle
= (HANDLE
)DeviceInfo
->DeviceIndex
;
1738 ClientInfo
->hPins
[ClientInfo
->NumPins
].Type
= MIXER_DEVICE_TYPE
;
1739 ClientInfo
->NumPins
++;
1743 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(WDMAUD_DEVICE_INFO
));
1745 DeviceInfo
->hDevice
= (HANDLE
)DeviceInfo
->DeviceIndex
;
1747 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1753 IN PDEVICE_OBJECT DeviceObject
,
1755 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1756 IN PWDMAUD_CLIENT ClientInfo
)
1758 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1759 LPMIXERLINE_EXT MixerLineSrc
;
1761 /* get device extension */
1762 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1764 if (DeviceInfo
->Flags
== MIXER_GETLINEINFOF_DESTINATION
)
1766 if ((ULONG
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1768 /* invalid parameter */
1769 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1772 if (DeviceInfo
->u
.MixLine
.dwDestination
!= 0)
1774 /* invalid parameter */
1775 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1777 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DESTINATION_LINE
);
1778 ASSERT(MixerLineSrc
);
1780 /* copy cached data */
1781 RtlCopyMemory(&DeviceInfo
->u
.MixLine
, &MixerLineSrc
->Line
, sizeof(MIXERLINEW
));
1782 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1784 else if (DeviceInfo
->Flags
== MIXER_GETLINEINFOF_SOURCE
)
1786 if ((ULONG
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1788 /* invalid parameter */
1789 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1792 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DESTINATION_LINE
);
1793 ASSERT(MixerLineSrc
);
1795 if (DeviceInfo
->u
.MixLine
.dwSource
>= MixerLineSrc
->Line
.cConnections
)
1797 DPRINT1("dwSource %u Destinations %u\n", DeviceInfo
->u
.MixLine
.dwSource
, MixerLineSrc
->Line
.cConnections
);
1798 /* invalid parameter */
1799 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1802 MixerLineSrc
= GetSourceMixerLine(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixLine
.dwSource
);
1805 DPRINT("Line %u Name %S\n", MixerLineSrc
->Line
.dwSource
, MixerLineSrc
->Line
.szName
);
1806 RtlCopyMemory(&DeviceInfo
->u
.MixLine
, &MixerLineSrc
->Line
, sizeof(MIXERLINEW
));
1808 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1810 else if (DeviceInfo
->Flags
== MIXER_GETLINEINFOF_LINEID
)
1812 if ((ULONG
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1814 /* invalid parameter */
1815 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1818 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixLine
.dwLineID
);
1819 ASSERT(MixerLineSrc
);
1821 /* copy cached data */
1822 RtlCopyMemory(&DeviceInfo
->u
.MixLine
, &MixerLineSrc
->Line
, sizeof(MIXERLINEW
));
1823 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1827 DPRINT1("Flags %x\n", DeviceInfo
->Flags
);
1831 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
1837 WdmAudGetLineControls(
1838 IN PDEVICE_OBJECT DeviceObject
,
1840 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1841 IN PWDMAUD_CLIENT ClientInfo
)
1843 LPMIXERLINE_EXT MixerLineSrc
;
1844 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
1847 /* get device extension */
1848 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1850 if (DeviceInfo
->Flags
== MIXER_GETLINECONTROLSF_ALL
)
1852 if ((ULONG
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1854 /* invalid parameter */
1855 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1858 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixControls
.dwLineID
);
1859 ASSERT(MixerLineSrc
);
1862 RtlMoveMemory(DeviceInfo
->u
.MixControls
.pamxctrl
, MixerLineSrc
->LineControls
, min(MixerLineSrc
->Line
.cControls
, DeviceInfo
->u
.MixControls
.cControls
) * sizeof(MIXERCONTROLW
));
1864 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1866 else if (DeviceInfo
->Flags
== MIXER_GETLINECONTROLSF_ONEBYTYPE
)
1868 if ((ULONG
)DeviceInfo
->hDevice
>= DeviceExtension
->MixerInfoCount
)
1870 /* invalid parameter */
1871 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
1874 MixerLineSrc
= GetSourceMixerLineByLineId(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixControls
.dwLineID
);
1875 ASSERT(MixerLineSrc
);
1878 for(Index
= 0; Index
< MixerLineSrc
->Line
.cControls
; Index
++)
1880 DPRINT1("dwControlType %x\n", MixerLineSrc
->LineControls
[Index
].dwControlType
);
1881 if (DeviceInfo
->u
.MixControls
.dwControlType
== MixerLineSrc
->LineControls
[Index
].dwControlType
)
1883 RtlMoveMemory(DeviceInfo
->u
.MixControls
.pamxctrl
, &MixerLineSrc
->LineControls
[Index
], sizeof(MIXERCONTROLW
));
1884 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
1887 DPRINT1("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x cControls %u \n", DeviceInfo
->u
.MixControls
.dwControlType
, DeviceInfo
->u
.MixControls
.dwLineID
, MixerLineSrc
->Line
.cControls
);
1888 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(WDMAUD_DEVICE_INFO
));
1893 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
1898 SetGetControlDetails(
1899 IN PDEVICE_OBJECT DeviceObject
,
1902 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1904 IN ULONG PropertyId
,
1906 IN PLONG InputValue
)
1908 KSNODEPROPERTY_AUDIO_CHANNEL Property
;
1911 PFILE_OBJECT FileObject
;
1913 ULONG BytesReturned
;
1916 Value
= *InputValue
;
1918 /* open virtual audio device */
1919 Status
= OpenSysAudioDeviceByIndex(DeviceObject
, DeviceId
, &hDevice
, &FileObject
);
1921 if (!NT_SUCCESS(Status
))
1927 /* setup the request */
1928 RtlZeroMemory(&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
));
1930 Property
.NodeProperty
.NodeId
= NodeId
;
1931 Property
.NodeProperty
.Property
.Id
= PropertyId
;
1932 Property
.NodeProperty
.Property
.Flags
= KSPROPERTY_TYPE_TOPOLOGY
;
1933 Property
.NodeProperty
.Property
.Set
= KSPROPSETID_Audio
;
1934 Property
.Channel
= Channel
;
1937 Property
.NodeProperty
.Property
.Flags
|= KSPROPERTY_TYPE_SET
;
1939 Property
.NodeProperty
.Property
.Flags
|= KSPROPERTY_TYPE_GET
;
1941 /* send the request */
1942 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL
), (PVOID
)&Value
, sizeof(LONG
), &BytesReturned
);
1944 ObDereferenceObject(FileObject
);
1949 *InputValue
= Value
;
1952 DPRINT1("Status %x bSet %u NodeId %u Value %d PropertyId %u\n", Status
, bSet
, NodeId
, Value
, PropertyId
);
1957 SetGetMuteControlDetails(
1958 IN PDEVICE_OBJECT DeviceObject
,
1961 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1964 LPMIXERCONTROLDETAILS_BOOLEAN Input
;
1968 if (DeviceInfo
->u
.MixDetails
.cbDetails
!= sizeof(MIXERCONTROLDETAILS_BOOLEAN
))
1969 return STATUS_INVALID_PARAMETER
;
1972 Input
= (LPMIXERCONTROLDETAILS_BOOLEAN
)DeviceInfo
->u
.MixDetails
.paDetails
;
1976 Value
= Input
->fValue
;
1978 /* set control details */
1979 Status
= SetGetControlDetails(DeviceObject
, DeviceId
, NodeId
, DeviceInfo
, bSet
, KSPROPERTY_AUDIO_MUTE
, MAXULONG
, &Value
);
1983 Input
->fValue
= Value
;
1989 SetGetVolumeControlDetails(
1990 IN PDEVICE_OBJECT DeviceObject
,
1993 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
1995 LPMIXERCONTROLW MixerControl
,
1996 LPMIXERLINE_EXT MixerLine
)
1998 LPMIXERCONTROLDETAILS_UNSIGNED Input
;
1999 LONG Value
, Index
, Channel
= 0;
2001 LPMIXERVOLUME_DATA VolumeData
;
2003 if (DeviceInfo
->u
.MixDetails
.cbDetails
!= sizeof(MIXERCONTROLDETAILS_SIGNED
))
2004 return STATUS_INVALID_PARAMETER
;
2006 VolumeData
= (LPMIXERVOLUME_DATA
)GetMixerControlDataById(&MixerLine
->LineControlsExtraData
, MixerControl
->dwControlID
);
2008 return STATUS_INSUFFICIENT_RESOURCES
;
2012 Input
= (LPMIXERCONTROLDETAILS_UNSIGNED
)DeviceInfo
->u
.MixDetails
.paDetails
;
2017 Value
= Input
->dwValue
;
2018 Index
= Value
/ VolumeData
->InputSteppingDelta
;
2020 if (Index
>= VolumeData
->ValuesCount
)
2022 DPRINT1("Index %u out of bounds %u \n", Index
, VolumeData
->ValuesCount
);
2024 return STATUS_INVALID_PARAMETER
;
2027 Value
= VolumeData
->Values
[Index
];
2030 /* set control details */
2033 Status
= SetGetControlDetails(DeviceObject
, DeviceId
, NodeId
, DeviceInfo
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 0, &Value
);
2034 Status
= SetGetControlDetails(DeviceObject
, DeviceId
, NodeId
, DeviceInfo
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, 1, &Value
);
2038 Status
= SetGetControlDetails(DeviceObject
, DeviceId
, NodeId
, DeviceInfo
, bSet
, KSPROPERTY_AUDIO_VOLUMELEVEL
, Channel
, &Value
);
2043 for(Index
= 0; Index
< VolumeData
->ValuesCount
; Index
++)
2045 if (VolumeData
->Values
[Index
] < Value
)
2048 Input
->dwValue
= VolumeData
->InputSteppingDelta
* Index
;
2052 Input
->dwValue
= VolumeData
->InputSteppingDelta
* (VolumeData
->ValuesCount
-1);
2060 WdmAudSetControlDetails(
2061 IN PDEVICE_OBJECT DeviceObject
,
2063 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
2064 IN PWDMAUD_CLIENT ClientInfo
)
2066 LPMIXERLINE_EXT MixerLine
;
2067 LPMIXERCONTROLW MixerControl
;
2069 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
2072 DPRINT("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n",
2073 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
);
2075 if (DeviceInfo
->Flags
& MIXER_GETCONTROLDETAILSF_LISTTEXT
)
2078 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
2081 /* get device extension */
2082 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
2084 /* get mixer control */
2085 Status
= GetMixerControlById(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixDetails
.dwControlID
, &MixerLine
, &MixerControl
, &NodeId
);
2087 if (!NT_SUCCESS(Status
))
2089 DPRINT1("MixerControl %x not found\n", DeviceInfo
->u
.MixDetails
.dwControlID
);
2090 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
2093 Status
= STATUS_NOT_IMPLEMENTED
;
2094 DPRINT("dwLineId %x dwControlID %x dwControlType %x\n", MixerLine
->Line
.dwLineID
, MixerControl
->dwControlID
, MixerControl
->dwControlType
);
2095 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
2097 /* send the request */
2098 Status
= SetGetMuteControlDetails(DeviceObject
, MixerLine
->DeviceIndex
, NodeId
, DeviceInfo
, TRUE
);
2100 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
2102 Status
= SetGetVolumeControlDetails(DeviceObject
, MixerLine
->DeviceIndex
, NodeId
, DeviceInfo
, TRUE
, MixerControl
, MixerLine
);
2104 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
2110 WdmAudGetControlDetails(
2111 IN PDEVICE_OBJECT DeviceObject
,
2113 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
2114 IN PWDMAUD_CLIENT ClientInfo
)
2116 LPMIXERLINE_EXT MixerLine
;
2117 LPMIXERCONTROLW MixerControl
;
2119 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
2122 DPRINT("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n",
2123 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
);
2125 if (DeviceInfo
->Flags
& MIXER_GETCONTROLDETAILSF_LISTTEXT
)
2128 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
2131 /* get device extension */
2132 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
2134 /* get mixer control */
2135 Status
= GetMixerControlById(&DeviceExtension
->MixerInfo
[(ULONG
)DeviceInfo
->hDevice
], DeviceInfo
->u
.MixDetails
.dwControlID
, &MixerLine
, &MixerControl
, &NodeId
);
2137 if (!NT_SUCCESS(Status
))
2139 DPRINT1("MixerControl %x not found\n", DeviceInfo
->u
.MixDetails
.dwControlID
);
2140 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
2143 Status
= STATUS_NOT_IMPLEMENTED
;
2144 if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
2146 /* send the request */
2147 Status
= SetGetMuteControlDetails(DeviceObject
, MixerLine
->DeviceIndex
, NodeId
, DeviceInfo
, FALSE
);
2149 else if (MixerControl
->dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
2151 Status
= SetGetVolumeControlDetails(DeviceObject
, MixerLine
->DeviceIndex
, NodeId
, DeviceInfo
, FALSE
, MixerControl
, MixerLine
);
2154 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));