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
11 const GUID KSPROPSETID_Sysaudio
= {0xCBE3FAA0L
, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
12 const GUID KSPROPSETID_Sysaudio_Pin
= {0xA3A53220L
, 0xC6E4, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
13 const GUID KSPROPSETID_General
= {0x1464EDA5L
, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
14 const GUID KSPROPSETID_Pin
= {0x8C134960L
, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
15 const GUID KSPROPSETID_Connection
= {0x1D58C920L
, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
16 const GUID KSPROPSETID_Topology
= {0x720D4AC0L
, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
17 const GUID KSDATAFORMAT_TYPE_AUDIO
= {0x73647561L
, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
18 const GUID KSDATAFORMAT_SUBTYPE_PCM
= {0x00000001L
, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
19 const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
= {0x05589f81L
, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
27 Irp
->IoStatus
.Information
= Length
;
28 Irp
->IoStatus
.Status
= Status
;
29 if (Status
!= STATUS_PENDING
)
31 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
35 IoMarkIrpPending(Irp
);
46 PLIST_ENTRY Entry
= Head
->Flink
;
48 while(Index
-- && Entry
!= Head
)
54 return (PKSAUDIO_DEVICE_ENTRY
)CONTAINING_RECORD(Entry
, KSAUDIO_DEVICE_ENTRY
, Entry
);
58 SysAudioOpenVirtualDevice(
60 IN ULONG DeviceNumber
,
61 PSYSAUDIODEVEXT DeviceExtension
)
63 PKSAUDIO_DEVICE_ENTRY Entry
;
64 PIO_STACK_LOCATION IoStack
;
66 /* get current irp stack */
67 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
70 ASSERT(IoStack
->FileObject
);
72 if (DeviceNumber
>= DeviceExtension
->NumberOfKsAudioDevices
)
74 /* invalid device index */
75 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
78 /* get device context */
79 Entry
= GetListEntry(&DeviceExtension
->KsAudioDeviceList
, DeviceNumber
);
80 ASSERT(Entry
!= NULL
);
82 /* store device entry in FsContext
83 * see pin.c DispatchCreateSysAudioPin for details
85 IoStack
->FileObject
->FsContext
= (PVOID
)Entry
;
87 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, 0);
91 HandleSysAudioFilterPinProperties(
94 PSYSAUDIODEVEXT DeviceExtension
)
96 PIO_STACK_LOCATION IoStack
;
98 PKSAUDIO_DEVICE_ENTRY Entry
;
101 // in order to access pin properties of a sysaudio device
102 // the caller must provide a KSP_PIN struct, where
103 // Reserved member points to virtual device index
105 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
106 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSP_PIN
))
108 /* too small buffer */
109 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(KSPROPERTY
) + sizeof(ULONG
));
112 Entry
= GetListEntry(&DeviceExtension
->KsAudioDeviceList
, ((KSP_PIN
*)Property
)->Reserved
);
115 /* invalid device index */
116 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
119 /* forward request to the filter implementing the property */
120 Status
= KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
,
121 (PVOID
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
122 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
,
124 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
,
127 return SetIrpIoStatus(Irp
, Status
, BytesReturned
);
132 ComputeCompatibleFormat(
133 IN PKSAUDIO_DEVICE_ENTRY Entry
,
135 IN PKSDATAFORMAT_WAVEFORMATEX ClientFormat
,
136 OUT PKSDATAFORMAT_WAVEFORMATEX MixerFormat
)
142 PKSMULTIPLE_ITEM MultipleItem
;
144 PKSDATARANGE_AUDIO AudioRange
;
147 Length
= sizeof(KSP_PIN
) + sizeof(KSMULTIPLE_ITEM
) + ClientFormat
->DataFormat
.FormatSize
;
148 PinRequest
= ExAllocatePool(NonPagedPool
, Length
);
150 return STATUS_UNSUCCESSFUL
;
152 PinRequest
->PinId
= PinId
;
153 PinRequest
->Property
.Set
= KSPROPSETID_Pin
;
154 PinRequest
->Property
.Flags
= KSPROPERTY_TYPE_GET
;
155 PinRequest
->Property
.Id
= KSPROPERTY_PIN_DATAINTERSECTION
;
157 MultipleItem
= (PKSMULTIPLE_ITEM
)(PinRequest
+ 1);
158 MultipleItem
->Count
= 1;
159 MultipleItem
->Size
= ClientFormat
->DataFormat
.FormatSize
;
161 RtlMoveMemory(MultipleItem
+ 1, ClientFormat
, ClientFormat
->DataFormat
.FormatSize
);
162 /* Query the miniport data intersection handler */
163 Status
= KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)PinRequest
, Length
, (PVOID
)MixerFormat
, sizeof(KSDATAFORMAT_WAVEFORMATEX
), &BytesReturned
);
165 DPRINT("Status %x\n", Status
);
167 if (NT_SUCCESS(Status
))
169 ExFreePool(PinRequest
);
173 /* Setup request block */
174 PinRequest
->Property
.Id
= KSPROPERTY_PIN_DATARANGES
;
175 /* Query pin data ranges */
176 Status
= KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)PinRequest
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
178 if (Status
!= STATUS_MORE_ENTRIES
)
180 /* Failed to get data ranges */
184 MultipleItem
= ExAllocatePool(NonPagedPool
, BytesReturned
);
187 ExFreePool(PinRequest
);
188 return STATUS_NO_MEMORY
;
191 Status
= KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)PinRequest
, sizeof(KSP_PIN
), (PVOID
)MultipleItem
, BytesReturned
, &BytesReturned
);
192 if (!NT_SUCCESS(Status
))
194 DPRINT("Property Request KSPROPERTY_PIN_DATARANGES failed with %x\n", Status
);
195 ExFreePool(MultipleItem
);
196 ExFreePool(PinRequest
);
197 return STATUS_UNSUCCESSFUL
;
200 AudioRange
= (PKSDATARANGE_AUDIO
)(MultipleItem
+ 1);
202 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
204 if (AudioRange
->DataRange
.FormatSize
!= sizeof(KSDATARANGE_AUDIO
))
207 AudioRange
= (PKSDATARANGE_AUDIO
)((PUCHAR
)AudioRange
+ AudioRange
->DataRange
.FormatSize
);
210 /* Select best quality available */
212 MixerFormat
->DataFormat
.FormatSize
= sizeof(KSDATAFORMAT
) + sizeof(WAVEFORMATEX
);
213 MixerFormat
->DataFormat
.Flags
= 0;
214 MixerFormat
->DataFormat
.Reserved
= 0;
215 MixerFormat
->DataFormat
.MajorFormat
= KSDATAFORMAT_TYPE_AUDIO
;
216 MixerFormat
->DataFormat
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
217 MixerFormat
->DataFormat
.Specifier
= KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
;
218 MixerFormat
->DataFormat
.SampleSize
= 4;
219 MixerFormat
->WaveFormatEx
.wFormatTag
= ClientFormat
->WaveFormatEx
.wFormatTag
;
221 /* HACK: AC97 does not support mono render / record */
222 MixerFormat
->WaveFormatEx
.nChannels
= 2;
223 /*HACK: AC97 only supports 16-Bit Bits */
224 MixerFormat
->WaveFormatEx
.wBitsPerSample
= 16;
227 MixerFormat
->WaveFormatEx
.nChannels
= min(ClientFormat
->WaveFormatEx
.nChannels
, AudioRange
->MaximumChannels
);
228 MixerFormat
->WaveFormatEx
.wBitsPerSample
= AudioRange
->MaximumBitsPerSample
;
231 #ifdef KMIXER_RESAMPLING_IMPLEMENTED
232 MixerFormat
->WaveFormatEx
.nSamplesPerSec
= AudioRange
->MaximumSampleFrequency
;
234 MixerFormat
->WaveFormatEx
.nSamplesPerSec
= max(AudioRange
->MinimumSampleFrequency
, min(ClientFormat
->WaveFormatEx
.nSamplesPerSec
, AudioRange
->MaximumSampleFrequency
));
237 MixerFormat
->WaveFormatEx
.cbSize
= 0;
238 MixerFormat
->WaveFormatEx
.nBlockAlign
= (MixerFormat
->WaveFormatEx
.nChannels
* MixerFormat
->WaveFormatEx
.wBitsPerSample
) / 8;
239 MixerFormat
->WaveFormatEx
.nAvgBytesPerSec
= MixerFormat
->WaveFormatEx
.nChannels
* MixerFormat
->WaveFormatEx
.nSamplesPerSec
* (MixerFormat
->WaveFormatEx
.wBitsPerSample
/ 8);
244 AudioRange
= (PKSDATARANGE_AUDIO
)((PUCHAR
)AudioRange
+ AudioRange
->DataRange
.FormatSize
);
248 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",
249 AudioRange
->MaximumChannels
, MixerFormat
->WaveFormatEx
.nChannels
, ClientFormat
->WaveFormatEx
.nChannels
,
250 AudioRange
->MaximumSampleFrequency
, MixerFormat
->WaveFormatEx
.nSamplesPerSec
, ClientFormat
->WaveFormatEx
.nSamplesPerSec
,
251 AudioRange
->MaximumBitsPerSample
, MixerFormat
->WaveFormatEx
.wBitsPerSample
, ClientFormat
->WaveFormatEx
.wBitsPerSample
);
256 ExFreePool(MultipleItem
);
257 ExFreePool(PinRequest
);
260 return STATUS_SUCCESS
;
262 return STATUS_NOT_IMPLEMENTED
;
267 PKSAUDIO_DEVICE_ENTRY Entry
,
268 PKSPIN_CINSTANCES PinInstances
,
269 PKSPIN_CONNECT PinConnect
)
274 /* query the instance count */
275 PinRequest
.PinId
= PinConnect
->PinId
;
276 PinRequest
.Property
.Set
= KSPROPSETID_Pin
;
277 PinRequest
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
278 PinRequest
.Property
.Id
= KSPROPERTY_PIN_CINSTANCES
;
279 ASSERT(Entry
->FileObject
);
280 return KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&PinRequest
, sizeof(KSP_PIN
), (PVOID
)PinInstances
, sizeof(KSPIN_CINSTANCES
), &BytesReturned
);
285 SysAudioHandleProperty(
286 PDEVICE_OBJECT DeviceObject
,
289 PIO_STACK_LOCATION IoStack
;
290 NTSTATUS Status
= STATUS_NOT_IMPLEMENTED
;
291 KSPROPERTY PropertyRequest
;
292 KSCOMPONENTID ComponentId
;
294 PKSPROPERTY Property
;
295 PSYSAUDIODEVEXT DeviceExtension
;
296 PKSAUDIO_DEVICE_ENTRY Entry
;
297 PSYSAUDIO_INSTANCE_INFO InstanceInfo
;
299 PKSOBJECT_CREATE_ITEM CreateItem
;
300 UNICODE_STRING GuidString
;
304 /* access the create item */
305 CreateItem
= KSCREATE_ITEM_IRP_STORAGE(Irp
);
307 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
309 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSPROPERTY
))
311 /* buffer must be at least of sizeof KSPROPERTY */
312 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(KSPROPERTY
));
315 Property
= (PKSPROPERTY
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
316 DeviceExtension
= (PSYSAUDIODEVEXT
)DeviceObject
->DeviceExtension
;
318 if (IsEqualGUIDAligned(&Property
->Set
, &KSPROPSETID_Pin
))
320 return HandleSysAudioFilterPinProperties(Irp
, Property
, DeviceExtension
);
322 else if(IsEqualGUIDAligned(&Property
->Set
, &KSPROPSETID_Topology
))
324 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSP_PIN
))
326 /* too small buffer */
327 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(KSP_PIN
));
329 Pin
= (PKSP_PIN
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
330 Entry
= GetListEntry(&DeviceExtension
->KsAudioDeviceList
, Pin
->Reserved
);
331 ASSERT(Entry
!= NULL
);
333 /* forward request to the filter implementing the property */
334 Status
= KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
,
335 (PVOID
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
336 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
,
338 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
,
341 return SetIrpIoStatus(Irp
, Status
, BytesReturned
);
343 else if (IsEqualGUIDAligned(&Property
->Set
, &KSPROPSETID_Sysaudio
))
345 if (Property
->Id
== KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME
)
347 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSPROPERTY
) + sizeof(ULONG
))
349 /* invalid request */
350 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, sizeof(KSPROPERTY
) + sizeof(ULONG
));
352 Index
= (PULONG
)(Property
+ 1);
354 if (DeviceExtension
->NumberOfKsAudioDevices
<= *Index
)
357 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
360 Entry
= GetListEntry(&DeviceExtension
->KsAudioDeviceList
, *Index
);
361 ASSERT(Entry
!= NULL
);
363 BytesReturned
= Entry
->DeviceName
.Length
+ sizeof(WCHAR
);
364 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< BytesReturned
)
366 /* too small buffer */
367 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, BytesReturned
);
370 /* copy device name */
371 DeviceName
= (LPWSTR
)Irp
->UserBuffer
;
373 RtlMoveMemory(DeviceName
, Entry
->DeviceName
.Buffer
, Entry
->DeviceName
.Length
);
374 DeviceName
[Entry
->DeviceName
.Length
/ sizeof(WCHAR
)] = L
'\0';
375 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, BytesReturned
);
378 if (Property
->Id
== KSPROPERTY_SYSAUDIO_COMPONENT_ID
)
380 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSPROPERTY
) + sizeof(ULONG
))
382 /* too small buffer */
383 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(KSPROPERTY
) + sizeof(ULONG
));
386 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KSCOMPONENTID
))
388 /* too small buffer */
389 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(KSCOMPONENTID
));
392 Index
= (PULONG
)(Property
+ 1);
394 if (DeviceExtension
->NumberOfKsAudioDevices
<= *Index
)
397 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
399 Entry
= GetListEntry(&DeviceExtension
->KsAudioDeviceList
, *Index
);
400 ASSERT(Entry
!= NULL
);
402 PropertyRequest
.Set
= KSPROPSETID_General
;
403 PropertyRequest
.Id
= KSPROPERTY_GENERAL_COMPONENTID
;
404 PropertyRequest
.Flags
= KSPROPERTY_TYPE_GET
;
406 /* call the filter */
407 Status
= KsSynchronousIoControlDevice(Entry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&PropertyRequest
, sizeof(KSPROPERTY
), (PVOID
)&ComponentId
, sizeof(KSCOMPONENTID
), &BytesReturned
);
408 if (!NT_SUCCESS(Status
))
410 DPRINT("KsSynchronousIoControlDevice failed with %x for KSPROPERTY_GENERAL_COMPONENTID\n", Status
);
411 return SetIrpIoStatus(Irp
, Status
, 0);
413 RtlMoveMemory(Irp
->UserBuffer
, &ComponentId
, sizeof(KSCOMPONENTID
));
414 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(KSCOMPONENTID
));
416 else if (Property
->Id
== KSPROPERTY_SYSAUDIO_DEVICE_COUNT
)
418 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
420 /* too small buffer */
421 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(ULONG
));
424 *((PULONG
)Irp
->UserBuffer
) = DeviceExtension
->NumberOfKsAudioDevices
;
425 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(ULONG
));
427 else if (Property
->Id
== KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE
)
429 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
431 /* too small buffer */
432 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(ULONG
));
435 if (Property
->Flags
& KSPROPERTY_TYPE_SET
)
437 Index
= (PULONG
)Irp
->UserBuffer
;
438 return SysAudioOpenVirtualDevice(Irp
, *Index
, DeviceExtension
);
441 else if (Property
->Id
== KSPROPERTY_SYSAUDIO_INSTANCE_INFO
)
443 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SYSAUDIO_INSTANCE_INFO
))
445 /* too small buffer */
446 return SetIrpIoStatus(Irp
, STATUS_BUFFER_TOO_SMALL
, sizeof(SYSAUDIO_INSTANCE_INFO
));
449 /* get input parameter */
450 InstanceInfo
= (PSYSAUDIO_INSTANCE_INFO
)Property
;
452 if (Property
->Flags
& KSPROPERTY_TYPE_SET
)
454 return SysAudioOpenVirtualDevice(Irp
, InstanceInfo
->DeviceNumber
, DeviceExtension
);
459 RtlStringFromGUID(&Property
->Set
, &GuidString
);
460 DPRINT1("Unhandeled property Set |%S| Id %u Flags %x\n", GuidString
.Buffer
, Property
->Id
, Property
->Flags
);
461 RtlFreeUnicodeString(&GuidString
);
462 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);