2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/sysaudio/control.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Johannes Anderwald
14 const GUID KSPROPSETID_Sysaudio
= {0xCBE3FAA0L
, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
15 const GUID KSPROPSETID_Sysaudio_Pin
= {0xA3A53220L
, 0xC6E4, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
16 const GUID KSPROPSETID_General
= {0x1464EDA5L
, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
17 const GUID KSPROPSETID_Pin
= {0x8C134960L
, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
18 const GUID KSPROPSETID_Connection
= {0x1D58C920L
, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
19 const GUID KSPROPSETID_Topology
= {0x720D4AC0L
, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
20 const GUID KSDATAFORMAT_TYPE_AUDIO
= {0x73647561L
, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
21 const GUID KSDATAFORMAT_SUBTYPE_PCM
= {0x00000001L
, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
22 const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
= {0x05589f81L
, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
30 Irp
->IoStatus
.Information
= Length
;
31 Irp
->IoStatus
.Status
= Status
;
32 if (Status
!= STATUS_PENDING
)
34 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
38 IoMarkIrpPending(Irp
);
49 PLIST_ENTRY Entry
= Head
->Flink
;
51 while(Index
-- && Entry
!= Head
)
57 return (PKSAUDIO_DEVICE_ENTRY
)CONTAINING_RECORD(Entry
, KSAUDIO_DEVICE_ENTRY
, Entry
);
61 SysAudioOpenVirtualDevice(
63 IN ULONG DeviceNumber
,
64 PSYSAUDIODEVEXT DeviceExtension
)
66 PKSAUDIO_DEVICE_ENTRY Entry
;
67 PIO_STACK_LOCATION IoStack
;
69 /* get current irp stack */
70 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
73 ASSERT(IoStack
->FileObject
);
75 if (DeviceNumber
>= DeviceExtension
->NumberOfKsAudioDevices
)
77 /* invalid device index */
78 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
81 /* get device context */
82 Entry
= GetListEntry(&DeviceExtension
->KsAudioDeviceList
, DeviceNumber
);
83 ASSERT(Entry
!= NULL
);
85 /* store device entry in FsContext
86 * see pin.c DispatchCreateSysAudioPin for details
88 IoStack
->FileObject
->FsContext
= (PVOID
)Entry
;
90 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, 0);
94 HandleSysAudioFilterPinProperties(
97 PSYSAUDIODEVEXT DeviceExtension
)
99 PIO_STACK_LOCATION IoStack
;
101 PKSAUDIO_DEVICE_ENTRY Entry
;
104 // in order to access pin properties of a sysaudio device
105 // the caller must provide a KSP_PIN struct, where
106 // Reserved member points to virtual device index
108 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
109 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSP_PIN
))
111 /* too small buffer */
112 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(KSPROPERTY
) + sizeof(ULONG
));
115 Entry
= GetListEntry(&DeviceExtension
->KsAudioDeviceList
, ((KSP_PIN
*)Property
)->Reserved
);
118 /* invalid device index */
119 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
122 /* forward request to the filter implementing the property */
123 Status
= KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
,
124 (PVOID
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
125 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
,
127 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
,
130 return SetIrpIoStatus(Irp
, Status
, BytesReturned
);
135 ComputeCompatibleFormat(
136 IN PKSAUDIO_DEVICE_ENTRY Entry
,
138 IN PKSDATAFORMAT_WAVEFORMATEX ClientFormat
,
139 OUT PKSDATAFORMAT_WAVEFORMATEX MixerFormat
)
145 PKSMULTIPLE_ITEM MultipleItem
;
147 PKSDATARANGE_AUDIO AudioRange
;
150 Length
= sizeof(KSP_PIN
) + sizeof(KSMULTIPLE_ITEM
) + ClientFormat
->DataFormat
.FormatSize
;
151 PinRequest
= AllocateItem(NonPagedPool
, Length
);
153 return STATUS_UNSUCCESSFUL
;
155 PinRequest
->PinId
= PinId
;
156 PinRequest
->Property
.Set
= KSPROPSETID_Pin
;
157 PinRequest
->Property
.Flags
= KSPROPERTY_TYPE_GET
;
158 PinRequest
->Property
.Id
= KSPROPERTY_PIN_DATAINTERSECTION
;
160 MultipleItem
= (PKSMULTIPLE_ITEM
)(PinRequest
+ 1);
161 MultipleItem
->Count
= 1;
162 MultipleItem
->Size
= ClientFormat
->DataFormat
.FormatSize
;
164 RtlMoveMemory(MultipleItem
+ 1, ClientFormat
, ClientFormat
->DataFormat
.FormatSize
);
165 /* Query the miniport data intersection handler */
166 Status
= KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)PinRequest
, Length
, (PVOID
)MixerFormat
, sizeof(KSDATAFORMAT_WAVEFORMATEX
), &BytesReturned
);
168 DPRINT("Status %x\n", Status
);
170 if (NT_SUCCESS(Status
))
172 FreeItem(PinRequest
);
176 /* Setup request block */
177 PinRequest
->Property
.Id
= KSPROPERTY_PIN_DATARANGES
;
178 /* Query pin data ranges */
179 Status
= KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)PinRequest
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
181 if (Status
!= STATUS_MORE_ENTRIES
)
183 /* Failed to get data ranges */
187 MultipleItem
= AllocateItem(NonPagedPool
, BytesReturned
);
190 FreeItem(PinRequest
);
191 return STATUS_NO_MEMORY
;
194 Status
= KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)PinRequest
, sizeof(KSP_PIN
), (PVOID
)MultipleItem
, BytesReturned
, &BytesReturned
);
195 if (!NT_SUCCESS(Status
))
197 DPRINT("Property Request KSPROPERTY_PIN_DATARANGES failed with %x\n", Status
);
198 FreeItem(MultipleItem
);
199 FreeItem(PinRequest
);
200 return STATUS_UNSUCCESSFUL
;
203 AudioRange
= (PKSDATARANGE_AUDIO
)(MultipleItem
+ 1);
205 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
207 if (AudioRange
->DataRange
.FormatSize
!= sizeof(KSDATARANGE_AUDIO
))
210 AudioRange
= (PKSDATARANGE_AUDIO
)((PUCHAR
)AudioRange
+ AudioRange
->DataRange
.FormatSize
);
213 /* Select best quality available */
215 MixerFormat
->DataFormat
.FormatSize
= sizeof(KSDATAFORMAT
) + sizeof(WAVEFORMATEX
);
216 MixerFormat
->DataFormat
.Flags
= 0;
217 MixerFormat
->DataFormat
.Reserved
= 0;
218 MixerFormat
->DataFormat
.MajorFormat
= KSDATAFORMAT_TYPE_AUDIO
;
219 MixerFormat
->DataFormat
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
220 MixerFormat
->DataFormat
.Specifier
= KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
;
221 MixerFormat
->DataFormat
.SampleSize
= 4;
222 MixerFormat
->WaveFormatEx
.wFormatTag
= ClientFormat
->WaveFormatEx
.wFormatTag
;
224 /* HACK: AC97 does not support mono render / record */
225 MixerFormat
->WaveFormatEx
.nChannels
= 2;
226 /*HACK: AC97 only supports 16-Bit Bits */
227 MixerFormat
->WaveFormatEx
.wBitsPerSample
= 16;
230 MixerFormat
->WaveFormatEx
.nChannels
= min(ClientFormat
->WaveFormatEx
.nChannels
, AudioRange
->MaximumChannels
);
231 MixerFormat
->WaveFormatEx
.wBitsPerSample
= AudioRange
->MaximumBitsPerSample
;
234 #ifdef KMIXER_RESAMPLING_IMPLEMENTED
235 MixerFormat
->WaveFormatEx
.nSamplesPerSec
= AudioRange
->MaximumSampleFrequency
;
237 MixerFormat
->WaveFormatEx
.nSamplesPerSec
= max(AudioRange
->MinimumSampleFrequency
, min(ClientFormat
->WaveFormatEx
.nSamplesPerSec
, AudioRange
->MaximumSampleFrequency
));
240 MixerFormat
->WaveFormatEx
.cbSize
= 0;
241 MixerFormat
->WaveFormatEx
.nBlockAlign
= (MixerFormat
->WaveFormatEx
.nChannels
* MixerFormat
->WaveFormatEx
.wBitsPerSample
) / 8;
242 MixerFormat
->WaveFormatEx
.nAvgBytesPerSec
= MixerFormat
->WaveFormatEx
.nChannels
* MixerFormat
->WaveFormatEx
.nSamplesPerSec
* (MixerFormat
->WaveFormatEx
.wBitsPerSample
/ 8);
247 AudioRange
= (PKSDATARANGE_AUDIO
)((PUCHAR
)AudioRange
+ AudioRange
->DataRange
.FormatSize
);
251 DPRINT1("\nNum Max Channels %u Channels %u Old Channels %u\n Max SampleRate %u SampleRate %u Old SampleRate %u\n Max BitsPerSample %u BitsPerSample %u Old BitsPerSample %u\n",
252 AudioRange
->MaximumChannels
, MixerFormat
->WaveFormatEx
.nChannels
, ClientFormat
->WaveFormatEx
.nChannels
,
253 AudioRange
->MaximumSampleFrequency
, MixerFormat
->WaveFormatEx
.nSamplesPerSec
, ClientFormat
->WaveFormatEx
.nSamplesPerSec
,
254 AudioRange
->MaximumBitsPerSample
, MixerFormat
->WaveFormatEx
.wBitsPerSample
, ClientFormat
->WaveFormatEx
.wBitsPerSample
);
259 FreeItem(MultipleItem
);
260 FreeItem(PinRequest
);
263 return STATUS_SUCCESS
;
265 return STATUS_NOT_IMPLEMENTED
;
270 PKSAUDIO_DEVICE_ENTRY Entry
,
271 PKSPIN_CINSTANCES PinInstances
,
272 PKSPIN_CONNECT PinConnect
)
277 /* query the instance count */
278 PinRequest
.PinId
= PinConnect
->PinId
;
279 PinRequest
.Property
.Set
= KSPROPSETID_Pin
;
280 PinRequest
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
281 PinRequest
.Property
.Id
= KSPROPERTY_PIN_CINSTANCES
;
282 ASSERT(Entry
->FileObject
);
283 return KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&PinRequest
, sizeof(KSP_PIN
), (PVOID
)PinInstances
, sizeof(KSPIN_CINSTANCES
), &BytesReturned
);
288 SysAudioHandleProperty(
289 PDEVICE_OBJECT DeviceObject
,
292 PIO_STACK_LOCATION IoStack
;
293 NTSTATUS Status
= STATUS_NOT_IMPLEMENTED
;
294 KSPROPERTY PropertyRequest
;
295 KSCOMPONENTID ComponentId
;
297 PKSPROPERTY Property
;
298 PSYSAUDIODEVEXT DeviceExtension
;
299 PKSAUDIO_DEVICE_ENTRY Entry
;
300 PSYSAUDIO_INSTANCE_INFO InstanceInfo
;
302 UNICODE_STRING GuidString
;
306 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
308 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSPROPERTY
))
310 /* buffer must be at least of sizeof KSPROPERTY */
311 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(KSPROPERTY
));
314 Property
= (PKSPROPERTY
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
315 DeviceExtension
= (PSYSAUDIODEVEXT
)DeviceObject
->DeviceExtension
;
317 if (IsEqualGUIDAligned(&Property
->Set
, &KSPROPSETID_Pin
))
319 return HandleSysAudioFilterPinProperties(Irp
, Property
, DeviceExtension
);
321 else if(IsEqualGUIDAligned(&Property
->Set
, &KSPROPSETID_Topology
))
323 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSP_PIN
))
325 /* too small buffer */
326 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(KSP_PIN
));
328 Pin
= (PKSP_PIN
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
329 Entry
= GetListEntry(&DeviceExtension
->KsAudioDeviceList
, Pin
->Reserved
);
330 ASSERT(Entry
!= NULL
);
332 /* forward request to the filter implementing the property */
333 Status
= KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
,
334 (PVOID
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
335 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
,
337 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
,
340 return SetIrpIoStatus(Irp
, Status
, BytesReturned
);
342 else if (IsEqualGUIDAligned(&Property
->Set
, &KSPROPSETID_Sysaudio
))
344 if (Property
->Id
== KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME
)
346 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSPROPERTY
) + sizeof(ULONG
))
348 /* invalid request */
349 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(KSPROPERTY
) + sizeof(ULONG
));
351 Index
= (PULONG
)(Property
+ 1);
353 if (DeviceExtension
->NumberOfKsAudioDevices
<= *Index
)
356 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
359 Entry
= GetListEntry(&DeviceExtension
->KsAudioDeviceList
, *Index
);
360 ASSERT(Entry
!= NULL
);
362 BytesReturned
= Entry
->DeviceName
.Length
+ sizeof(WCHAR
);
363 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< BytesReturned
)
365 /* too small buffer */
366 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, BytesReturned
);
369 /* copy device name */
370 DeviceName
= (LPWSTR
)Irp
->UserBuffer
;
372 RtlMoveMemory(DeviceName
, Entry
->DeviceName
.Buffer
, Entry
->DeviceName
.Length
);
373 DeviceName
[Entry
->DeviceName
.Length
/ sizeof(WCHAR
)] = L
'\0';
374 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, BytesReturned
);
377 if (Property
->Id
== KSPROPERTY_SYSAUDIO_COMPONENT_ID
)
379 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSPROPERTY
) + sizeof(ULONG
))
381 /* too small buffer */
382 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(KSPROPERTY
) + sizeof(ULONG
));
385 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KSCOMPONENTID
))
387 /* too small buffer */
388 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(KSCOMPONENTID
));
391 Index
= (PULONG
)(Property
+ 1);
393 if (DeviceExtension
->NumberOfKsAudioDevices
<= *Index
)
396 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
398 Entry
= GetListEntry(&DeviceExtension
->KsAudioDeviceList
, *Index
);
399 ASSERT(Entry
!= NULL
);
401 PropertyRequest
.Set
= KSPROPSETID_General
;
402 PropertyRequest
.Id
= KSPROPERTY_GENERAL_COMPONENTID
;
403 PropertyRequest
.Flags
= KSPROPERTY_TYPE_GET
;
405 /* call the filter */
406 Status
= KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&PropertyRequest
, sizeof(KSPROPERTY
), (PVOID
)&ComponentId
, sizeof(KSCOMPONENTID
), &BytesReturned
);
407 if (!NT_SUCCESS(Status
))
409 DPRINT("KsSynchronousIoControlDevice failed with %x for KSPROPERTY_GENERAL_COMPONENTID\n", Status
);
410 return SetIrpIoStatus(Irp
, Status
, 0);
412 RtlMoveMemory(Irp
->UserBuffer
, &ComponentId
, sizeof(KSCOMPONENTID
));
413 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(KSCOMPONENTID
));
415 else if (Property
->Id
== KSPROPERTY_SYSAUDIO_DEVICE_COUNT
)
417 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
419 /* too small buffer */
420 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(ULONG
));
423 *((PULONG
)Irp
->UserBuffer
) = DeviceExtension
->NumberOfKsAudioDevices
;
424 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(ULONG
));
426 else if (Property
->Id
== KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE
)
428 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
430 /* too small buffer */
431 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(ULONG
));
434 if (Property
->Flags
& KSPROPERTY_TYPE_SET
)
436 Index
= (PULONG
)Irp
->UserBuffer
;
437 return SysAudioOpenVirtualDevice(Irp
, *Index
, DeviceExtension
);
440 else if (Property
->Id
== KSPROPERTY_SYSAUDIO_INSTANCE_INFO
)
442 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SYSAUDIO_INSTANCE_INFO
))
444 /* too small buffer */
445 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(SYSAUDIO_INSTANCE_INFO
));
448 /* get input parameter */
449 InstanceInfo
= (PSYSAUDIO_INSTANCE_INFO
)Property
;
451 if (Property
->Flags
& KSPROPERTY_TYPE_SET
)
453 return SysAudioOpenVirtualDevice(Irp
, InstanceInfo
->DeviceNumber
, DeviceExtension
);
458 RtlStringFromGUID(&Property
->Set
, &GuidString
);
459 DPRINT1("Unhandled property Set |%S| Id %u Flags %x\n", GuidString
.Buffer
, Property
->Id
, Property
->Flags
);
460 RtlFreeUnicodeString(&GuidString
);
461 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);