mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 20:25:39 +00:00
- Rewrite Wave API to enumerate wave out / in devices at startup
- Improves speedup of application minus short delay in system boot - Enumerate controls for source and destination lines svn path=/trunk/; revision=43254
This commit is contained in:
parent
2f541881a8
commit
347609e691
7 changed files with 1503 additions and 765 deletions
|
@ -19,114 +19,6 @@ const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001L, 0x0000, 0x0010,
|
||||||
const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
|
const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
|
||||||
const GUID KSPROPSETID_Topology = {0x720D4AC0L, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
|
const GUID KSPROPSETID_Topology = {0x720D4AC0L, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
SetIrpIoStatus(
|
|
||||||
IN PIRP Irp,
|
|
||||||
IN NTSTATUS Status,
|
|
||||||
IN ULONG Length)
|
|
||||||
{
|
|
||||||
Irp->IoStatus.Information = Length;
|
|
||||||
Irp->IoStatus.Status = Status;
|
|
||||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
||||||
return Status;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
GetFilterIdAndPinId(
|
|
||||||
IN PDEVICE_OBJECT DeviceObject,
|
|
||||||
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
|
||||||
IN PWDMAUD_CLIENT ClientInfo,
|
|
||||||
IN PULONG FilterId,
|
|
||||||
IN PULONG PinId)
|
|
||||||
{
|
|
||||||
KSP_PIN Pin;
|
|
||||||
ULONG Count, BytesReturned, Index, SubIndex, Result, NumPins;
|
|
||||||
NTSTATUS Status;
|
|
||||||
KSPIN_COMMUNICATION Communication;
|
|
||||||
KSPIN_DATAFLOW DataFlow;
|
|
||||||
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
|
||||||
|
|
||||||
if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceInfo->DeviceType != WAVE_IN_DEVICE_TYPE)
|
|
||||||
{
|
|
||||||
DPRINT1("FIXME: Unsupported device type %x\n", DeviceInfo->DeviceType);
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pin.Property.Set = KSPROPSETID_Sysaudio;
|
|
||||||
Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
|
|
||||||
Pin.Property.Flags = KSPROPERTY_TYPE_GET;
|
|
||||||
|
|
||||||
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
||||||
|
|
||||||
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
|
|
||||||
Result = 0;
|
|
||||||
for(Index = 0; Index < Count; Index++)
|
|
||||||
{
|
|
||||||
/* query number of pins */
|
|
||||||
Pin.Reserved = Index; // see sysaudio
|
|
||||||
Pin.Property.Flags = KSPROPERTY_TYPE_GET;
|
|
||||||
Pin.Property.Set = KSPROPSETID_Pin;
|
|
||||||
Pin.Property.Id = KSPROPERTY_PIN_CTYPES;
|
|
||||||
Pin.PinId = 0;
|
|
||||||
|
|
||||||
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
/* enumerate now all pins */
|
|
||||||
for(SubIndex = 0; SubIndex < NumPins; SubIndex++)
|
|
||||||
{
|
|
||||||
Pin.PinId = SubIndex;
|
|
||||||
Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
|
|
||||||
Communication = KSPIN_COMMUNICATION_NONE;
|
|
||||||
|
|
||||||
/* get pin communication type */
|
|
||||||
KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
|
|
||||||
|
|
||||||
Pin.Property.Id = KSPROPERTY_PIN_DATAFLOW;
|
|
||||||
DataFlow = 0;
|
|
||||||
|
|
||||||
/* get pin dataflow type */
|
|
||||||
KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
|
|
||||||
|
|
||||||
if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
|
|
||||||
{
|
|
||||||
if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
|
|
||||||
{
|
|
||||||
if(DeviceInfo->DeviceIndex == Result)
|
|
||||||
{
|
|
||||||
/* found the index */
|
|
||||||
*FilterId = Index;
|
|
||||||
*PinId = SubIndex;
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
|
|
||||||
{
|
|
||||||
if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
|
|
||||||
{
|
|
||||||
if(DeviceInfo->DeviceIndex == Result)
|
|
||||||
{
|
|
||||||
/* found the index */
|
|
||||||
*FilterId = Index;
|
|
||||||
*PinId = SubIndex;
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
Result++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
WdmAudControlOpen(
|
WdmAudControlOpen(
|
||||||
|
@ -135,174 +27,17 @@ WdmAudControlOpen(
|
||||||
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
||||||
IN PWDMAUD_CLIENT ClientInfo)
|
IN PWDMAUD_CLIENT ClientInfo)
|
||||||
{
|
{
|
||||||
SYSAUDIO_INSTANCE_INFO InstanceInfo;
|
|
||||||
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
|
||||||
ULONG BytesReturned;
|
|
||||||
NTSTATUS Status;
|
|
||||||
ACCESS_MASK DesiredAccess = 0;
|
|
||||||
HANDLE PinHandle;
|
|
||||||
KSPIN_CONNECT * PinConnect;
|
|
||||||
ULONG Length, Index;
|
|
||||||
KSDATAFORMAT_WAVEFORMATEX * DataFormat;
|
|
||||||
ULONG FilterId;
|
|
||||||
ULONG PinId;
|
|
||||||
ULONG FreeIndex;
|
|
||||||
|
|
||||||
if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
|
if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
|
||||||
{
|
{
|
||||||
return WdmAudControlOpenMixer(DeviceObject, Irp, DeviceInfo, ClientInfo);
|
return WdmAudControlOpenMixer(DeviceObject, Irp, DeviceInfo, ClientInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceInfo->DeviceType != WAVE_IN_DEVICE_TYPE)
|
if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
|
||||||
{
|
{
|
||||||
DPRINT1("FIXME: only waveout / wavein devices are supported\n");
|
return WdmAudControlOpenWave(DeviceObject, Irp, DeviceInfo, ClientInfo);
|
||||||
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DeviceInfo->u.WaveFormatEx.wFormatTag != WAVE_FORMAT_PCM)
|
return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
|
||||||
{
|
|
||||||
DPRINT("FIXME: Only WAVE_FORMAT_PCM is supported RequestFormat %x\n", DeviceInfo->u.WaveFormatEx.wFormatTag);
|
|
||||||
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = GetFilterIdAndPinId(DeviceObject, DeviceInfo, ClientInfo, &FilterId, &PinId);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT1("Invalid device index %u\n", DeviceInfo->DeviceIndex);
|
|
||||||
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* close pin handle which uses same virtual audio device id and pin id */
|
|
||||||
FreeIndex = MAXULONG;
|
|
||||||
for(Index = 0; Index < ClientInfo->NumPins; Index++)
|
|
||||||
{
|
|
||||||
if (ClientInfo->hPins[Index].FilterId == FilterId && ClientInfo->hPins[Index].PinId == PinId && ClientInfo->hPins[Index].Handle && ClientInfo->hPins[Index].Type == DeviceInfo->DeviceType)
|
|
||||||
{
|
|
||||||
ZwClose(ClientInfo->hPins[Index].Handle);
|
|
||||||
ClientInfo->hPins[Index].Handle = NULL;
|
|
||||||
FreeIndex = Index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Length = sizeof(KSDATAFORMAT_WAVEFORMATEX) + sizeof(KSPIN_CONNECT);
|
|
||||||
PinConnect = ExAllocatePool(NonPagedPool, Length);
|
|
||||||
if (!PinConnect)
|
|
||||||
{
|
|
||||||
/* no memory */
|
|
||||||
return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
||||||
|
|
||||||
if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE ||
|
|
||||||
DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE ||
|
|
||||||
DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
|
|
||||||
{
|
|
||||||
DesiredAccess |= GENERIC_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE ||
|
|
||||||
DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE ||
|
|
||||||
DeviceInfo->DeviceType == AUX_DEVICE_TYPE ||
|
|
||||||
DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
|
|
||||||
{
|
|
||||||
DesiredAccess |= GENERIC_WRITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PinConnect->Interface.Set = KSINTERFACESETID_Standard;
|
|
||||||
PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
|
|
||||||
PinConnect->Interface.Flags = 0;
|
|
||||||
PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
|
|
||||||
PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
|
|
||||||
PinConnect->Medium.Flags = 0;
|
|
||||||
PinConnect->PinToHandle = NULL;
|
|
||||||
PinConnect->PinId = PinId;
|
|
||||||
PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
|
|
||||||
PinConnect->Priority.PrioritySubClass = 1;
|
|
||||||
|
|
||||||
|
|
||||||
DataFormat = (KSDATAFORMAT_WAVEFORMATEX*) (PinConnect + 1);
|
|
||||||
DataFormat->WaveFormatEx.wFormatTag = DeviceInfo->u.WaveFormatEx.wFormatTag;
|
|
||||||
DataFormat->WaveFormatEx.nChannels = DeviceInfo->u.WaveFormatEx.nChannels;
|
|
||||||
DataFormat->WaveFormatEx.nSamplesPerSec = DeviceInfo->u.WaveFormatEx.nSamplesPerSec;
|
|
||||||
DataFormat->WaveFormatEx.nBlockAlign = DeviceInfo->u.WaveFormatEx.nBlockAlign;
|
|
||||||
DataFormat->WaveFormatEx.nAvgBytesPerSec = DeviceInfo->u.WaveFormatEx.nAvgBytesPerSec;
|
|
||||||
DataFormat->WaveFormatEx.wBitsPerSample = DeviceInfo->u.WaveFormatEx.wBitsPerSample;
|
|
||||||
DataFormat->WaveFormatEx.cbSize = 0;
|
|
||||||
DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
|
|
||||||
DataFormat->DataFormat.Flags = 0;
|
|
||||||
DataFormat->DataFormat.Reserved = 0;
|
|
||||||
DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
|
|
||||||
|
|
||||||
DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
|
||||||
DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
|
|
||||||
DataFormat->DataFormat.SampleSize = 4;
|
|
||||||
|
|
||||||
/* setup property request */
|
|
||||||
InstanceInfo.Property.Set = KSPROPSETID_Sysaudio;
|
|
||||||
InstanceInfo.Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
|
|
||||||
InstanceInfo.Property.Flags = KSPROPERTY_TYPE_SET;
|
|
||||||
InstanceInfo.Flags = 0;
|
|
||||||
InstanceInfo.DeviceNumber = FilterId;
|
|
||||||
|
|
||||||
/* first open the virtual device */
|
|
||||||
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
/* failed */
|
|
||||||
ExFreePool(PinConnect);
|
|
||||||
return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now create the pin */
|
|
||||||
Status = KsCreatePin(DeviceExtension->hSysAudio, PinConnect, DesiredAccess, &PinHandle);
|
|
||||||
|
|
||||||
/* free create info */
|
|
||||||
ExFreePool(PinConnect);
|
|
||||||
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
PWDMAUD_HANDLE Handels;
|
|
||||||
|
|
||||||
if (FreeIndex != MAXULONG)
|
|
||||||
{
|
|
||||||
/* re-use a free index */
|
|
||||||
ClientInfo->hPins[Index].Handle = PinHandle;
|
|
||||||
ClientInfo->hPins[Index].FilterId = FilterId;
|
|
||||||
ClientInfo->hPins[Index].PinId = PinId;
|
|
||||||
ClientInfo->hPins[Index].Type = DeviceInfo->DeviceType;
|
|
||||||
|
|
||||||
DeviceInfo->hDevice = PinHandle;
|
|
||||||
return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
|
|
||||||
}
|
|
||||||
|
|
||||||
Handels = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
|
|
||||||
|
|
||||||
if (Handels)
|
|
||||||
{
|
|
||||||
if (ClientInfo->NumPins)
|
|
||||||
{
|
|
||||||
RtlMoveMemory(Handels, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
|
|
||||||
ExFreePool(ClientInfo->hPins);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClientInfo->hPins = Handels;
|
|
||||||
ClientInfo->hPins[ClientInfo->NumPins].Handle = PinHandle;
|
|
||||||
ClientInfo->hPins[ClientInfo->NumPins].Type = DeviceInfo->DeviceType;
|
|
||||||
ClientInfo->hPins[ClientInfo->NumPins].FilterId = FilterId;
|
|
||||||
ClientInfo->hPins[ClientInfo->NumPins].PinId = PinId;
|
|
||||||
ClientInfo->NumPins++;
|
|
||||||
}
|
|
||||||
DeviceInfo->hDevice = PinHandle;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DeviceInfo->hDevice = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
|
@ -312,85 +47,23 @@ WdmAudControlDeviceType(
|
||||||
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
||||||
IN PWDMAUD_CLIENT ClientInfo)
|
IN PWDMAUD_CLIENT ClientInfo)
|
||||||
{
|
{
|
||||||
KSP_PIN Pin;
|
ULONG Result = 0;
|
||||||
ULONG Count, BytesReturned, Index, SubIndex, Result, NumPins;
|
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
KSPIN_COMMUNICATION Communication;
|
|
||||||
KSPIN_DATAFLOW DataFlow;
|
|
||||||
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
||||||
|
|
||||||
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||||
|
|
||||||
if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
|
if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
|
||||||
{
|
{
|
||||||
DeviceInfo->DeviceCount = DeviceExtension->MixerInfoCount;
|
Result = DeviceExtension->MixerInfoCount;
|
||||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
|
||||||
}
|
}
|
||||||
|
else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
|
||||||
if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceInfo->DeviceType != WAVE_IN_DEVICE_TYPE)
|
|
||||||
{
|
{
|
||||||
DPRINT("FIXME: Unsupported device type %x\n", DeviceInfo->DeviceType);
|
Result = DeviceExtension->WaveOutDeviceCount;
|
||||||
DeviceInfo->DeviceCount = 0;
|
|
||||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
|
||||||
}
|
|
||||||
|
|
||||||
Pin.Property.Set = KSPROPSETID_Sysaudio;
|
|
||||||
Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
|
|
||||||
Pin.Property.Flags = KSPROPERTY_TYPE_GET;
|
|
||||||
|
|
||||||
|
|
||||||
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT1("KSPROPERTY_SYSAUDIO_DEVICE_COUNT failed with %x\n", Status);
|
|
||||||
return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
|
|
||||||
}
|
|
||||||
Result = 0;
|
|
||||||
/* now enumerate all available filters */
|
|
||||||
for(Index = 0; Index < Count; Index++)
|
|
||||||
{
|
|
||||||
/* query number of pins */
|
|
||||||
Pin.Reserved = Index; // see sysaudio
|
|
||||||
Pin.Property.Flags = KSPROPERTY_TYPE_GET;
|
|
||||||
Pin.Property.Set = KSPROPSETID_Pin;
|
|
||||||
Pin.Property.Id = KSPROPERTY_PIN_CTYPES;
|
|
||||||
Pin.PinId = 0;
|
|
||||||
|
|
||||||
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
/* enumerate now all pins */
|
|
||||||
for(SubIndex = 0; SubIndex < NumPins; SubIndex++)
|
|
||||||
{
|
|
||||||
Pin.PinId = SubIndex;
|
|
||||||
Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
|
|
||||||
Communication = KSPIN_COMMUNICATION_NONE;
|
|
||||||
|
|
||||||
/* get pin communication type */
|
|
||||||
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Pin.Property.Id = KSPROPERTY_PIN_DATAFLOW;
|
|
||||||
DataFlow = 0;
|
|
||||||
|
|
||||||
/* get pin dataflow type */
|
|
||||||
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
|
|
||||||
{
|
|
||||||
if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
|
|
||||||
Result++;
|
|
||||||
}
|
}
|
||||||
else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
|
else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
|
||||||
{
|
{
|
||||||
if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
|
Result = DeviceExtension->WaveInDeviceCount;
|
||||||
Result++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* store result count */
|
/* store result count */
|
||||||
|
@ -436,253 +109,6 @@ WdmAudControlDeviceState(
|
||||||
return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
|
return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG
|
|
||||||
CheckFormatSupport(
|
|
||||||
IN PKSDATARANGE_AUDIO DataRangeAudio,
|
|
||||||
ULONG SampleFrequency,
|
|
||||||
ULONG Mono8Bit,
|
|
||||||
ULONG Stereo8Bit,
|
|
||||||
ULONG Mono16Bit,
|
|
||||||
ULONG Stereo16Bit)
|
|
||||||
{
|
|
||||||
ULONG Result = 0;
|
|
||||||
|
|
||||||
if (DataRangeAudio->MinimumSampleFrequency <= SampleFrequency && DataRangeAudio->MaximumSampleFrequency >= SampleFrequency)
|
|
||||||
{
|
|
||||||
if (DataRangeAudio->MinimumBitsPerSample <= 8 && DataRangeAudio->MaximumBitsPerSample >= 8)
|
|
||||||
{
|
|
||||||
Result |= Mono8Bit;
|
|
||||||
if (DataRangeAudio->MaximumChannels >= 2)
|
|
||||||
{
|
|
||||||
Result |= Stereo8Bit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DataRangeAudio->MinimumBitsPerSample <= 16 && DataRangeAudio->MaximumBitsPerSample >= 16)
|
|
||||||
{
|
|
||||||
Result |= Mono16Bit;
|
|
||||||
if (DataRangeAudio->MaximumChannels >= 2)
|
|
||||||
{
|
|
||||||
Result |= Stereo8Bit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Result;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
PKEY_VALUE_PARTIAL_INFORMATION
|
|
||||||
ReadKeyValue(
|
|
||||||
IN HANDLE hSubKey,
|
|
||||||
IN PUNICODE_STRING KeyName)
|
|
||||||
{
|
|
||||||
NTSTATUS Status;
|
|
||||||
ULONG Length;
|
|
||||||
PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
|
|
||||||
|
|
||||||
/* now query MatchingDeviceId key */
|
|
||||||
Status = ZwQueryValueKey(hSubKey, KeyName, KeyValuePartialInformation, NULL, 0, &Length);
|
|
||||||
|
|
||||||
/* check for success */
|
|
||||||
if (Status != STATUS_BUFFER_TOO_SMALL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* allocate a buffer for key data */
|
|
||||||
PartialInformation = ExAllocatePool(NonPagedPool, Length);
|
|
||||||
|
|
||||||
if (!PartialInformation)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
|
|
||||||
/* now query MatchingDeviceId key */
|
|
||||||
Status = ZwQueryValueKey(hSubKey, KeyName, KeyValuePartialInformation, PartialInformation, Length, &Length);
|
|
||||||
|
|
||||||
/* check for success */
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
ExFreePool(PartialInformation);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PartialInformation->Type != REG_SZ)
|
|
||||||
{
|
|
||||||
/* invalid key type */
|
|
||||||
ExFreePool(PartialInformation);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PartialInformation;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
CompareProductName(
|
|
||||||
IN HANDLE hSubKey,
|
|
||||||
IN LPWSTR PnpName,
|
|
||||||
IN ULONG ProductNameSize,
|
|
||||||
OUT LPWSTR ProductName)
|
|
||||||
{
|
|
||||||
PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
|
|
||||||
UNICODE_STRING DriverDescName = RTL_CONSTANT_STRING(L"DriverDesc");
|
|
||||||
UNICODE_STRING MatchingDeviceIdName = RTL_CONSTANT_STRING(L"MatchingDeviceId");
|
|
||||||
ULONG Length;
|
|
||||||
LPWSTR DeviceName;
|
|
||||||
|
|
||||||
/* read MatchingDeviceId value */
|
|
||||||
PartialInformation = ReadKeyValue(hSubKey, &MatchingDeviceIdName);
|
|
||||||
|
|
||||||
if (!PartialInformation)
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
|
|
||||||
|
|
||||||
/* extract last '&' */
|
|
||||||
DeviceName = wcsrchr((LPWSTR)PartialInformation->Data, L'&');
|
|
||||||
ASSERT(DeviceName);
|
|
||||||
/* terminate it */
|
|
||||||
DeviceName[0] = L'\0';
|
|
||||||
|
|
||||||
Length = wcslen((LPWSTR)PartialInformation->Data);
|
|
||||||
|
|
||||||
DPRINT("DeviceName %S PnpName %S Length %u\n", (LPWSTR)PartialInformation->Data, PnpName, Length);
|
|
||||||
|
|
||||||
if (_wcsnicmp((LPWSTR)PartialInformation->Data, &PnpName[4], Length))
|
|
||||||
{
|
|
||||||
ExFreePool(PartialInformation);
|
|
||||||
return STATUS_NO_MATCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* free buffer */
|
|
||||||
ExFreePool(PartialInformation);
|
|
||||||
|
|
||||||
/* read DriverDescName value */
|
|
||||||
PartialInformation = ReadKeyValue(hSubKey, &DriverDescName);
|
|
||||||
|
|
||||||
if (!PartialInformation)
|
|
||||||
{
|
|
||||||
/* failed to read driver desc key */
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy key name */
|
|
||||||
Length = min(ProductNameSize * sizeof(WCHAR), PartialInformation->DataLength);
|
|
||||||
RtlMoveMemory(ProductName, (PVOID)PartialInformation->Data, Length);
|
|
||||||
|
|
||||||
/* zero terminate it */
|
|
||||||
ProductName[ProductNameSize-1] = L'\0';
|
|
||||||
|
|
||||||
/* free buffer */
|
|
||||||
ExFreePool(PartialInformation);
|
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
FindProductName(
|
|
||||||
IN LPWSTR PnpName,
|
|
||||||
IN ULONG ProductNameSize,
|
|
||||||
OUT LPWSTR ProductName)
|
|
||||||
{
|
|
||||||
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E96C-E325-11CE-BFC1-08002BE10318}");
|
|
||||||
|
|
||||||
UNICODE_STRING SubKeyName;
|
|
||||||
WCHAR SubKey[20];
|
|
||||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
||||||
HANDLE hKey, hSubKey;
|
|
||||||
NTSTATUS Status;
|
|
||||||
ULONG Length, Index;
|
|
||||||
PKEY_FULL_INFORMATION KeyInformation;
|
|
||||||
|
|
||||||
for(Index = 0; Index < wcslen(PnpName); Index++)
|
|
||||||
{
|
|
||||||
if (PnpName[Index] == '#')
|
|
||||||
PnpName[Index] = L'\\';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* initialize key attributes */
|
|
||||||
InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, NULL, NULL);
|
|
||||||
|
|
||||||
/* open the key */
|
|
||||||
Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjectAttributes);
|
|
||||||
|
|
||||||
/* check for success */
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
return Status;
|
|
||||||
|
|
||||||
/* query num of subkeys */
|
|
||||||
Status = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &Length);
|
|
||||||
|
|
||||||
if (Status != STATUS_BUFFER_TOO_SMALL)
|
|
||||||
{
|
|
||||||
DPRINT1("ZwQueryKey failed with %x\n", Status);
|
|
||||||
/* failed */
|
|
||||||
ZwClose(hKey);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate key information struct */
|
|
||||||
KeyInformation = ExAllocatePool(NonPagedPool, Length);
|
|
||||||
if (!KeyInformation)
|
|
||||||
{
|
|
||||||
/* no memory */
|
|
||||||
ZwClose(hKey);
|
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* query num of subkeys */
|
|
||||||
Status = ZwQueryKey(hKey, KeyFullInformation, (PVOID)KeyInformation, Length, &Length);
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT1("ZwQueryKey failed with %x\n", Status);
|
|
||||||
ExFreePool(KeyInformation);
|
|
||||||
ZwClose(hKey);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now iterate through all subkeys */
|
|
||||||
for(Index = 0; Index < KeyInformation->SubKeys; Index++)
|
|
||||||
{
|
|
||||||
/* subkeys are always in the format 0000-XXXX */
|
|
||||||
swprintf(SubKey, L"%04u", Index);
|
|
||||||
|
|
||||||
/* initialize subkey name */
|
|
||||||
RtlInitUnicodeString(&SubKeyName, SubKey);
|
|
||||||
|
|
||||||
/* initialize key attributes */
|
|
||||||
InitializeObjectAttributes(&ObjectAttributes, &SubKeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, hKey, NULL);
|
|
||||||
|
|
||||||
/* open the sub key */
|
|
||||||
Status = ZwOpenKey(&hSubKey, GENERIC_READ, &ObjectAttributes);
|
|
||||||
|
|
||||||
/* check for success */
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
/* compare product name */
|
|
||||||
Status = CompareProductName(hSubKey, PnpName, ProductNameSize, ProductName);
|
|
||||||
|
|
||||||
/* close subkey */
|
|
||||||
ZwClose(hSubKey);
|
|
||||||
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* free buffer */
|
|
||||||
ExFreePool(KeyInformation);
|
|
||||||
|
|
||||||
/* close key */
|
|
||||||
ZwClose(hKey);
|
|
||||||
|
|
||||||
/* no matching key found */
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
WdmAudCapabilities(
|
WdmAudCapabilities(
|
||||||
IN PDEVICE_OBJECT DeviceObject,
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
@ -692,19 +118,6 @@ WdmAudCapabilities(
|
||||||
{
|
{
|
||||||
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
||||||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||||||
KSP_PIN PinProperty;
|
|
||||||
KSCOMPONENTID ComponentId;
|
|
||||||
KSMULTIPLE_ITEM * MultipleItem;
|
|
||||||
ULONG BytesReturned;
|
|
||||||
PKSDATARANGE_AUDIO DataRangeAudio;
|
|
||||||
PKSDATARANGE DataRange;
|
|
||||||
ULONG Index;
|
|
||||||
ULONG wChannels = 0;
|
|
||||||
ULONG dwFormats = 0;
|
|
||||||
ULONG dwSupport = 0;
|
|
||||||
ULONG FilterId;
|
|
||||||
ULONG PinId;
|
|
||||||
WCHAR DeviceName[MAX_PATH];
|
|
||||||
|
|
||||||
DPRINT("WdmAudCapabilities entered\n");
|
DPRINT("WdmAudCapabilities entered\n");
|
||||||
|
|
||||||
|
@ -713,115 +126,12 @@ WdmAudCapabilities(
|
||||||
if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
|
if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
|
||||||
{
|
{
|
||||||
Status = WdmAudMixerCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
|
Status = WdmAudMixerCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
|
||||||
return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
|
|
||||||
}
|
}
|
||||||
|
else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
|
||||||
|
|
||||||
Status = GetFilterIdAndPinId(DeviceObject, DeviceInfo, ClientInfo, &FilterId, &PinId);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
{
|
||||||
DPRINT1("Invalid device index provided %u\n", DeviceInfo->DeviceIndex);
|
Status = WdmAudWaveCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
|
||||||
return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PinProperty.PinId = FilterId;
|
|
||||||
PinProperty.Property.Set = KSPROPSETID_Sysaudio;
|
|
||||||
PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_COMPONENT_ID;
|
|
||||||
PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
|
|
||||||
|
|
||||||
RtlZeroMemory(&ComponentId, sizeof(KSCOMPONENTID));
|
|
||||||
|
|
||||||
|
|
||||||
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)&ComponentId, sizeof(KSCOMPONENTID), &BytesReturned);
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DeviceInfo->u.WaveOutCaps.wMid = ComponentId.Manufacturer.Data1 - 0xd5a47fa7;
|
|
||||||
DeviceInfo->u.WaveOutCaps.vDriverVersion = MAKELONG(ComponentId.Version, ComponentId.Revision);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* retrieve pnp base name */
|
|
||||||
PinProperty.PinId = FilterId;
|
|
||||||
PinProperty.Property.Set = KSPROPSETID_Sysaudio;
|
|
||||||
PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
|
|
||||||
PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
|
|
||||||
|
|
||||||
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)DeviceName, sizeof(DeviceName), &BytesReturned);
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
/* find product name */
|
|
||||||
Status = FindProductName(DeviceName, MAXPNAMELEN, DeviceInfo->u.WaveOutCaps.szPname);
|
|
||||||
|
|
||||||
/* check for success */
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DeviceInfo->u.WaveOutCaps.szPname[0] = L'\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PinProperty.Reserved = DeviceInfo->DeviceIndex;
|
|
||||||
PinProperty.PinId = PinId;
|
|
||||||
PinProperty.Property.Set = KSPROPSETID_Pin;
|
|
||||||
PinProperty.Property.Id = KSPROPERTY_PIN_DATARANGES;
|
|
||||||
PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
|
|
||||||
|
|
||||||
BytesReturned = 0;
|
|
||||||
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)NULL, 0, &BytesReturned);
|
|
||||||
if (Status != STATUS_BUFFER_TOO_SMALL)
|
|
||||||
{
|
|
||||||
return SetIrpIoStatus(Irp, Status, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
MultipleItem = ExAllocatePool(NonPagedPool, BytesReturned);
|
|
||||||
if (!MultipleItem)
|
|
||||||
{
|
|
||||||
/* no memory */
|
|
||||||
return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
ExFreePool(MultipleItem);
|
|
||||||
return SetIrpIoStatus(Irp, Status, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
DataRange = (PKSDATARANGE) (MultipleItem + 1);
|
|
||||||
for(Index = 0; Index < MultipleItem->Count; Index++)
|
|
||||||
{
|
|
||||||
if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
|
|
||||||
{
|
|
||||||
if (DataRange->FormatSize == sizeof(KSDATARANGE_AUDIO))
|
|
||||||
{
|
|
||||||
DataRangeAudio = (PKSDATARANGE_AUDIO)DataRange;
|
|
||||||
|
|
||||||
if (IsEqualGUIDAligned(&DataRangeAudio->DataRange.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
|
|
||||||
IsEqualGUIDAligned(&DataRangeAudio->DataRange.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
|
|
||||||
IsEqualGUIDAligned(&DataRangeAudio->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
|
|
||||||
{
|
|
||||||
DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio->MinimumSampleFrequency, DataRangeAudio->MaximumSampleFrequency,
|
|
||||||
DataRangeAudio->MinimumBitsPerSample, DataRangeAudio->MaximumBitsPerSample, DataRangeAudio->MaximumChannels);
|
|
||||||
|
|
||||||
dwFormats |= CheckFormatSupport(DataRangeAudio, 11025, WAVE_FORMAT_1M08, WAVE_FORMAT_1S08, WAVE_FORMAT_1M16, WAVE_FORMAT_1S16);
|
|
||||||
dwFormats |= CheckFormatSupport(DataRangeAudio, 22050, WAVE_FORMAT_2M08, WAVE_FORMAT_2S08, WAVE_FORMAT_2M16, WAVE_FORMAT_2S16);
|
|
||||||
dwFormats |= CheckFormatSupport(DataRangeAudio, 44100, WAVE_FORMAT_4M08, WAVE_FORMAT_4S08, WAVE_FORMAT_4M16, WAVE_FORMAT_4S16);
|
|
||||||
dwFormats |= CheckFormatSupport(DataRangeAudio, 48000, WAVE_FORMAT_48M08, WAVE_FORMAT_48S08, WAVE_FORMAT_48M16, WAVE_FORMAT_48S16);
|
|
||||||
dwFormats |= CheckFormatSupport(DataRangeAudio, 96000, WAVE_FORMAT_96M08, WAVE_FORMAT_96S08, WAVE_FORMAT_96M16, WAVE_FORMAT_96S16);
|
|
||||||
|
|
||||||
|
|
||||||
wChannels = DataRangeAudio->MaximumChannels;
|
|
||||||
dwSupport = WAVECAPS_VOLUME; //FIXME get info from nodes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DataRange = (PKSDATARANGE)((PUCHAR)DataRange + DataRange->FormatSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceInfo->u.WaveOutCaps.dwFormats = dwFormats;
|
|
||||||
DeviceInfo->u.WaveOutCaps.dwSupport = dwSupport;
|
|
||||||
DeviceInfo->u.WaveOutCaps.wChannels = wChannels;
|
|
||||||
|
|
||||||
ExFreePool(MultipleItem);
|
|
||||||
|
|
||||||
return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
|
return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -846,6 +156,7 @@ WdmAudIoctlClose(
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO));
|
SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO));
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,8 @@ WdmAudInstallDevice(
|
||||||
|
|
||||||
Status = WdmAudMixerInitialize(DeviceObject);
|
Status = WdmAudMixerInitialize(DeviceObject);
|
||||||
DPRINT("WdmAudMixerInitialize Status %x\n", Status);
|
DPRINT("WdmAudMixerInitialize Status %x\n", Status);
|
||||||
|
Status = WdmAudWaveInitialize(DeviceObject);
|
||||||
|
DPRINT("WdmAudWaveInitialize Status %x\n", Status);
|
||||||
|
|
||||||
DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
|
DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
|
||||||
DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
|
DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
|
||||||
|
|
|
@ -21,6 +21,7 @@ const GUID KSNODETYPE_STEREO_WIDE = {0xA9E69800L, 0xC558, 0x11D0, {0x8A, 0x2B, 0
|
||||||
const GUID KSNODETYPE_CHORUS = {0x20173F20L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
|
const GUID KSNODETYPE_CHORUS = {0x20173F20L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
|
||||||
const GUID KSNODETYPE_REVERB = {0xEF0328E0L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
|
const GUID KSNODETYPE_REVERB = {0xEF0328E0L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
|
||||||
const GUID KSNODETYPE_SUPERMIX = {0xE573ADC0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
|
const GUID KSNODETYPE_SUPERMIX = {0xE573ADC0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
|
||||||
|
const GUID KSNODETYPE_SUM = {0xDA441A60L, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
|
||||||
|
|
||||||
#define DESTINATION_LINE 0xFFFF0000
|
#define DESTINATION_LINE 0xFFFF0000
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ GetSourceMixerLineByLineId(
|
||||||
while(Entry != &MixerInfo->LineList)
|
while(Entry != &MixerInfo->LineList)
|
||||||
{
|
{
|
||||||
MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
|
MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
|
||||||
DPRINT("dwLineID %x dwLineID %x\n", MixerLineSrc->Line.dwLineID, dwLineID);
|
DPRINT1("dwLineID %x dwLineID %x\n", MixerLineSrc->Line.dwLineID, dwLineID);
|
||||||
if (MixerLineSrc->Line.dwLineID == dwLineID)
|
if (MixerLineSrc->Line.dwLineID == dwLineID)
|
||||||
return MixerLineSrc;
|
return MixerLineSrc;
|
||||||
|
|
||||||
|
@ -719,36 +720,260 @@ AllocatePinArray(
|
||||||
return Pins;
|
return Pins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PKSTOPOLOGY_CONNECTION
|
||||||
|
GetConnectionByIndex(
|
||||||
|
IN PKSMULTIPLE_ITEM MultipleItem,
|
||||||
|
IN ULONG Index)
|
||||||
|
{
|
||||||
|
PKSTOPOLOGY_CONNECTION Descriptor;
|
||||||
|
|
||||||
|
ASSERT(Index < MultipleItem->Count);
|
||||||
|
|
||||||
|
Descriptor = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
|
||||||
|
return &Descriptor[Index];
|
||||||
|
}
|
||||||
|
|
||||||
|
LPGUID
|
||||||
|
GetNodeType(
|
||||||
|
IN PKSMULTIPLE_ITEM MultipleItem,
|
||||||
|
IN ULONG Index)
|
||||||
|
{
|
||||||
|
LPGUID NodeType;
|
||||||
|
|
||||||
|
ASSERT(Index < MultipleItem->Count);
|
||||||
|
|
||||||
|
NodeType = (LPGUID)(MultipleItem + 1);
|
||||||
|
return &NodeType[Index];
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
GetControlsFromPinByConnectionIndex(
|
||||||
|
IN PKSMULTIPLE_ITEM NodeConnections,
|
||||||
|
IN PKSMULTIPLE_ITEM NodeTypes,
|
||||||
|
IN ULONG bUpDirection,
|
||||||
|
IN ULONG NodeConnectionIndex,
|
||||||
|
OUT PULONG Nodes)
|
||||||
|
{
|
||||||
|
PKSTOPOLOGY_CONNECTION CurConnection;
|
||||||
|
LPGUID NodeType;
|
||||||
|
ULONG NodeIndex;
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG NodeConnectionCount, Index;
|
||||||
|
PULONG NodeConnection;
|
||||||
|
|
||||||
|
|
||||||
|
/* get current connection */
|
||||||
|
CurConnection = GetConnectionByIndex(NodeConnections, NodeConnectionIndex);
|
||||||
|
|
||||||
|
if (bUpDirection)
|
||||||
|
NodeIndex = CurConnection->FromNode;
|
||||||
|
else
|
||||||
|
NodeIndex = CurConnection->ToNode;
|
||||||
|
|
||||||
|
/* get target node type of current connection */
|
||||||
|
NodeType = GetNodeType(NodeTypes, NodeIndex);
|
||||||
|
|
||||||
|
if (IsEqualGUIDAligned(NodeType, &KSNODETYPE_SUM) || IsEqualGUIDAligned(NodeType, &KSNODETYPE_MUX))
|
||||||
|
{
|
||||||
|
if (bUpDirection)
|
||||||
|
{
|
||||||
|
/* add the sum / mux node to destination line */
|
||||||
|
//Nodes[NodeIndex] = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now add the node */
|
||||||
|
Nodes[NodeIndex] = TRUE;
|
||||||
|
|
||||||
|
|
||||||
|
/* get all node indexes referenced by that node */
|
||||||
|
if (bUpDirection)
|
||||||
|
{
|
||||||
|
Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
for(Index = 0; Index < NodeConnectionCount; Index++)
|
||||||
|
{
|
||||||
|
/* iterate recursively into the nodes */
|
||||||
|
Status = GetControlsFromPinByConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
|
||||||
|
ASSERT(Status == STATUS_SUCCESS);
|
||||||
|
}
|
||||||
|
/* free node connection indexes */
|
||||||
|
ExFreePool(NodeConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
GetControlsFromPin(
|
||||||
|
IN PKSMULTIPLE_ITEM NodeConnections,
|
||||||
|
IN PKSMULTIPLE_ITEM NodeTypes,
|
||||||
|
IN ULONG PinId,
|
||||||
|
IN ULONG bUpDirection,
|
||||||
|
OUT PULONG Nodes)
|
||||||
|
{
|
||||||
|
ULONG NodeConnectionCount, Index;
|
||||||
|
NTSTATUS Status;
|
||||||
|
PULONG NodeConnection;
|
||||||
|
|
||||||
|
/* sanity check */
|
||||||
|
ASSERT(PinId != (ULONG)-1);
|
||||||
|
|
||||||
|
/* get all node indexes referenced by that pin */
|
||||||
|
if (bUpDirection)
|
||||||
|
Status = GetNodeIndexes(NodeConnections, PinId, FALSE, FALSE, &NodeConnectionCount, &NodeConnection);
|
||||||
|
else
|
||||||
|
Status = GetNodeIndexes(NodeConnections, PinId, FALSE, TRUE, &NodeConnectionCount, &NodeConnection);
|
||||||
|
|
||||||
|
for(Index = 0; Index < NodeConnectionCount; Index++)
|
||||||
|
{
|
||||||
|
/* get all associated controls */
|
||||||
|
Status = GetControlsFromPinByConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExFreePool(NodeConnection);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
AddMixerControl(
|
||||||
|
IN LPMIXER_INFO MixerInfo,
|
||||||
|
IN PFILE_OBJECT FileObject,
|
||||||
|
IN PKSMULTIPLE_ITEM NodeTypes,
|
||||||
|
IN ULONG NodeIndex,
|
||||||
|
OUT LPMIXERCONTROLW MixerControl)
|
||||||
|
{
|
||||||
|
LPGUID NodeType;
|
||||||
|
KSP_NODE Node;
|
||||||
|
ULONG BytesReturned;
|
||||||
|
NTSTATUS Status;
|
||||||
|
LPWSTR Name;
|
||||||
|
|
||||||
|
|
||||||
|
/* initialize mixer control */
|
||||||
|
MixerControl->cbStruct = sizeof(MIXERCONTROLW);
|
||||||
|
MixerControl->dwControlID = MixerInfo->ControlId;
|
||||||
|
|
||||||
|
/* get node type */
|
||||||
|
NodeType = GetNodeType(NodeTypes, NodeIndex);
|
||||||
|
/* store control type */
|
||||||
|
MixerControl->dwControlType = GetControlTypeFromTopologyNode(NodeType);
|
||||||
|
|
||||||
|
MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; //FIXME
|
||||||
|
MixerControl->cMultipleItems = 0; //FIXME
|
||||||
|
|
||||||
|
if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
|
||||||
|
{
|
||||||
|
MixerControl->Bounds.dwMinimum = 0;
|
||||||
|
MixerControl->Bounds.dwMaximum = 1;
|
||||||
|
}
|
||||||
|
else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
|
||||||
|
{
|
||||||
|
MixerControl->Bounds.dwMinimum = 0;
|
||||||
|
MixerControl->Bounds.dwMaximum = 0xFFFF;
|
||||||
|
MixerControl->Metrics.cSteps = 0xC0; //FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup request to retrieve name */
|
||||||
|
Node.NodeId = NodeIndex;
|
||||||
|
Node.Property.Id = KSPROPERTY_TOPOLOGY_NAME;
|
||||||
|
Node.Property.Flags = KSPROPERTY_TYPE_GET;
|
||||||
|
Node.Property.Set = KSPROPSETID_Topology;
|
||||||
|
Node.Reserved = 0;
|
||||||
|
|
||||||
|
/* get node name size */
|
||||||
|
Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
|
||||||
|
|
||||||
|
if (Status == STATUS_BUFFER_TOO_SMALL)
|
||||||
|
{
|
||||||
|
ASSERT(BytesReturned != 0);
|
||||||
|
Name = ExAllocatePool(NonPagedPool, BytesReturned);
|
||||||
|
if (!Name)
|
||||||
|
{
|
||||||
|
/* not enough memory */
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get node name */
|
||||||
|
Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
RtlMoveMemory(MixerControl->szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
|
||||||
|
MixerControl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
|
||||||
|
|
||||||
|
RtlMoveMemory(MixerControl->szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
|
||||||
|
MixerControl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free name buffer */
|
||||||
|
ExFreePool(Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
MixerInfo->ControlId++;
|
||||||
|
|
||||||
|
DPRINT("Status %x Name %S\n", Status, MixerControl->szName);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
AddMixerSourceLine(
|
AddMixerSourceLine(
|
||||||
IN OUT LPMIXER_INFO MixerInfo,
|
IN OUT LPMIXER_INFO MixerInfo,
|
||||||
IN PFILE_OBJECT FileObject,
|
IN PFILE_OBJECT FileObject,
|
||||||
|
IN PKSMULTIPLE_ITEM NodeConnections,
|
||||||
|
IN PKSMULTIPLE_ITEM NodeTypes,
|
||||||
IN ULONG DeviceIndex,
|
IN ULONG DeviceIndex,
|
||||||
IN ULONG PinId)
|
IN ULONG PinId,
|
||||||
|
IN ULONG bBridgePin,
|
||||||
|
IN ULONG bTargetPin)
|
||||||
{
|
{
|
||||||
LPMIXERLINE_EXT SrcLine, DstLine;
|
LPMIXERLINE_EXT SrcLine, DstLine;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
KSP_PIN Pin;
|
KSP_PIN Pin;
|
||||||
LPWSTR PinName;
|
LPWSTR PinName;
|
||||||
GUID NodeType;
|
GUID NodeType;
|
||||||
ULONG BytesReturned;
|
ULONG BytesReturned, ControlCount, Index;
|
||||||
|
PULONG Nodes;
|
||||||
|
|
||||||
|
if (!bTargetPin)
|
||||||
|
{
|
||||||
/* allocate src mixer line */
|
/* allocate src mixer line */
|
||||||
SrcLine = (LPMIXERLINE_EXT)ExAllocatePool(NonPagedPool, sizeof(MIXERLINE_EXT));
|
SrcLine = (LPMIXERLINE_EXT)ExAllocatePool(NonPagedPool, sizeof(MIXERLINE_EXT));
|
||||||
|
|
||||||
if (!SrcLine)
|
if (!SrcLine)
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
/* zero struct */
|
/* zero struct */
|
||||||
RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT));
|
RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT));
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(!IsListEmpty(&MixerInfo->LineList));
|
||||||
|
SrcLine = GetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get destination line */
|
||||||
|
DstLine = GetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
|
||||||
|
ASSERT(DstLine);
|
||||||
|
|
||||||
|
|
||||||
|
if (!bTargetPin)
|
||||||
|
{
|
||||||
/* initialize mixer src line */
|
/* initialize mixer src line */
|
||||||
SrcLine->DeviceIndex = DeviceIndex;
|
SrcLine->DeviceIndex = DeviceIndex;
|
||||||
SrcLine->PinId = PinId;
|
SrcLine->PinId = PinId;
|
||||||
SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
|
SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
|
||||||
|
|
||||||
/* get destination line */
|
|
||||||
DstLine = GetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
|
|
||||||
|
|
||||||
/* initialize mixer destination line */
|
/* initialize mixer destination line */
|
||||||
SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
|
SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
|
||||||
SrcLine->Line.dwDestination = 0;
|
SrcLine->Line.dwDestination = 0;
|
||||||
|
@ -758,28 +983,106 @@ AddMixerSourceLine(
|
||||||
SrcLine->Line.dwUser = 0;
|
SrcLine->Line.dwUser = 0;
|
||||||
SrcLine->Line.cChannels = DstLine->Line.cChannels;
|
SrcLine->Line.cChannels = DstLine->Line.cChannels;
|
||||||
SrcLine->Line.cConnections = 0;
|
SrcLine->Line.cConnections = 0;
|
||||||
SrcLine->Line.cControls = 1; //FIXME
|
SrcLine->Line.Target.dwType = 1;
|
||||||
|
SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
|
||||||
|
SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
|
||||||
|
SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
|
||||||
|
SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
|
||||||
|
wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
|
||||||
|
|
||||||
//HACK
|
}
|
||||||
SrcLine->LineControls = ExAllocatePool(NonPagedPool, SrcLine->Line.cControls * sizeof(MIXERCONTROLW));
|
|
||||||
if (!SrcLine->LineControls)
|
/* allocate a node arrary */
|
||||||
|
Nodes = ExAllocatePool(NonPagedPool, sizeof(ULONG) * NodeTypes->Count);
|
||||||
|
|
||||||
|
if (!Nodes)
|
||||||
{
|
{
|
||||||
/* not enough memory */
|
/* not enough memory */
|
||||||
|
if (!bTargetPin)
|
||||||
|
{
|
||||||
ExFreePool(SrcLine);
|
ExFreePool(SrcLine);
|
||||||
|
}
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear line controls */
|
/* clear nodes array */
|
||||||
RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW));
|
RtlZeroMemory(Nodes, sizeof(ULONG) * NodeTypes->Count);
|
||||||
|
|
||||||
/* fill in pseudo mixer control */
|
Status = GetControlsFromPin(NodeConnections, NodeTypes, PinId, bTargetPin, Nodes);
|
||||||
SrcLine->LineControls->dwControlID = 1; //FIXME
|
if (!NT_SUCCESS(Status))
|
||||||
SrcLine->LineControls->cbStruct = sizeof(MIXERCONTROLW);
|
{
|
||||||
SrcLine->LineControls->fdwControl = 0;
|
/* something went wrong */
|
||||||
SrcLine->LineControls->cMultipleItems = 0;
|
if (!bTargetPin)
|
||||||
wcscpy(SrcLine->LineControls->szName, L"test");
|
{
|
||||||
wcscpy(SrcLine->LineControls->szShortName, L"test");
|
ExFreePool(SrcLine);
|
||||||
|
}
|
||||||
|
ExFreePool(Nodes);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now count all nodes controlled by that pin */
|
||||||
|
ControlCount = 0;
|
||||||
|
for(Index = 0; Index < NodeTypes->Count; Index++)
|
||||||
|
{
|
||||||
|
if (Nodes[Index])
|
||||||
|
ControlCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now allocate the line controls */
|
||||||
|
if (ControlCount)
|
||||||
|
{
|
||||||
|
SrcLine->LineControls = ExAllocatePool(NonPagedPool, sizeof(MIXERCONTROLW) * ControlCount);
|
||||||
|
|
||||||
|
if (!SrcLine->LineControls)
|
||||||
|
{
|
||||||
|
/* no memory available */
|
||||||
|
if (!bTargetPin)
|
||||||
|
{
|
||||||
|
ExFreePool(SrcLine);
|
||||||
|
}
|
||||||
|
ExFreePool(Nodes);
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrcLine->NodeIds = ExAllocatePool(NonPagedPool, sizeof(ULONG) * ControlCount);
|
||||||
|
if (!SrcLine->NodeIds)
|
||||||
|
{
|
||||||
|
/* no memory available */
|
||||||
|
ExFreePool(SrcLine->LineControls);
|
||||||
|
if (!bTargetPin)
|
||||||
|
{
|
||||||
|
ExFreePool(SrcLine);
|
||||||
|
}
|
||||||
|
ExFreePool(Nodes);
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* zero line controls */
|
||||||
|
RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW) * ControlCount);
|
||||||
|
RtlZeroMemory(SrcLine->NodeIds, sizeof(ULONG) * ControlCount);
|
||||||
|
|
||||||
|
ControlCount = 0;
|
||||||
|
for(Index = 0; Index < NodeTypes->Count; Index++)
|
||||||
|
{
|
||||||
|
if (Nodes[Index])
|
||||||
|
{
|
||||||
|
/* store the node index for retrieving / setting details */
|
||||||
|
SrcLine->NodeIds[ControlCount] = Index;
|
||||||
|
|
||||||
|
Status = AddMixerControl(MixerInfo, FileObject, NodeTypes, Index, &SrcLine->LineControls[ControlCount]);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* increment control count on success */
|
||||||
|
ControlCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* store control count */
|
||||||
|
SrcLine->Line.cControls = ControlCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* release nodes array */
|
||||||
|
ExFreePool(Nodes);
|
||||||
|
|
||||||
/* get pin category */
|
/* get pin category */
|
||||||
Pin.PinId = PinId;
|
Pin.PinId = PinId;
|
||||||
|
@ -831,17 +1134,12 @@ AddMixerSourceLine(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SrcLine->Line.Target.dwType = 1;
|
|
||||||
SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
|
|
||||||
SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
|
|
||||||
SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
|
|
||||||
SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
|
|
||||||
wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
|
|
||||||
|
|
||||||
|
|
||||||
/* insert src line */
|
/* insert src line */
|
||||||
|
if (!bTargetPin)
|
||||||
|
{
|
||||||
InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
|
InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
|
||||||
DstLine->Line.cConnections++;
|
DstLine->Line.cConnections++;
|
||||||
|
}
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -851,8 +1149,12 @@ NTSTATUS
|
||||||
AddMixerSourceLines(
|
AddMixerSourceLines(
|
||||||
IN OUT LPMIXER_INFO MixerInfo,
|
IN OUT LPMIXER_INFO MixerInfo,
|
||||||
IN PFILE_OBJECT FileObject,
|
IN PFILE_OBJECT FileObject,
|
||||||
|
IN PKSMULTIPLE_ITEM NodeConnections,
|
||||||
|
IN PKSMULTIPLE_ITEM NodeTypes,
|
||||||
IN ULONG DeviceIndex,
|
IN ULONG DeviceIndex,
|
||||||
IN ULONG PinsCount,
|
IN ULONG PinsCount,
|
||||||
|
IN ULONG BridgePinIndex,
|
||||||
|
IN ULONG TargetPinIndex,
|
||||||
IN PULONG Pins)
|
IN PULONG Pins)
|
||||||
{
|
{
|
||||||
ULONG Index;
|
ULONG Index;
|
||||||
|
@ -862,7 +1164,7 @@ AddMixerSourceLines(
|
||||||
{
|
{
|
||||||
if (Pins[Index-1])
|
if (Pins[Index-1])
|
||||||
{
|
{
|
||||||
AddMixerSourceLine(MixerInfo, FileObject, DeviceIndex, Index-1);
|
AddMixerSourceLine(MixerInfo, FileObject, NodeConnections, NodeTypes, DeviceIndex, Index-1, (Index -1 == BridgePinIndex), (Index -1 == TargetPinIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Status;
|
return Status;
|
||||||
|
@ -987,7 +1289,7 @@ HandlePhysicalConnection(
|
||||||
PinsSrcRef[OutConnection->Pin] = TRUE;
|
PinsSrcRef[OutConnection->Pin] = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = AddMixerSourceLines(MixerInfo, FileObject, DeviceIndex, PinsRefCount, PinsSrcRef);
|
Status = AddMixerSourceLines(MixerInfo, FileObject, NodeConnections, NodeTypes, DeviceIndex, PinsRefCount, OutConnection->Pin, Index, PinsSrcRef);
|
||||||
|
|
||||||
ExFreePool(MixerControls);
|
ExFreePool(MixerControls);
|
||||||
ExFreePool(PinsSrcRef);
|
ExFreePool(PinsSrcRef);
|
||||||
|
@ -1045,10 +1347,6 @@ InitializeMixer(
|
||||||
if (!DestinationLine)
|
if (!DestinationLine)
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
/* initialize mixer info */
|
|
||||||
MixerInfo->hMixer = hDevice;
|
|
||||||
MixerInfo->MixerFileObject = FileObject;
|
|
||||||
|
|
||||||
/* intialize mixer caps */
|
/* intialize mixer caps */
|
||||||
MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
|
MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
|
||||||
MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
|
MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
|
||||||
|
@ -1083,7 +1381,6 @@ InitializeMixer(
|
||||||
DestinationLine->Line.dwUser = 0;
|
DestinationLine->Line.dwUser = 0;
|
||||||
DestinationLine->Line.dwComponentType = (bInput == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
|
DestinationLine->Line.dwComponentType = (bInput == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
|
||||||
DestinationLine->Line.cChannels = 2; //FIXME
|
DestinationLine->Line.cChannels = 2; //FIXME
|
||||||
DestinationLine->Line.cControls = 0; //FIXME
|
|
||||||
wcscpy(DestinationLine->Line.szShortName, L"Summe"); //FIXME
|
wcscpy(DestinationLine->Line.szShortName, L"Summe"); //FIXME
|
||||||
wcscpy(DestinationLine->Line.szName, L"Summe"); //FIXME
|
wcscpy(DestinationLine->Line.szName, L"Summe"); //FIXME
|
||||||
DestinationLine->Line.Target.dwType = (bInput == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
|
DestinationLine->Line.Target.dwType = (bInput == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
|
||||||
|
@ -1411,6 +1708,7 @@ WdmAudGetLineControls(
|
||||||
{
|
{
|
||||||
LPMIXERLINE_EXT MixerLineSrc;
|
LPMIXERLINE_EXT MixerLineSrc;
|
||||||
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
||||||
|
ULONG Index;
|
||||||
|
|
||||||
/* get device extension */
|
/* get device extension */
|
||||||
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||||
|
@ -1427,15 +1725,12 @@ WdmAudGetLineControls(
|
||||||
ASSERT(MixerLineSrc);
|
ASSERT(MixerLineSrc);
|
||||||
if (MixerLineSrc)
|
if (MixerLineSrc)
|
||||||
{
|
{
|
||||||
RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, DeviceInfo->u.MixControls.cControls) * sizeof(MIXERLINECONTROLSW));
|
RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, DeviceInfo->u.MixControls.cControls) * sizeof(MIXERCONTROLW));
|
||||||
}
|
}
|
||||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
||||||
}
|
}
|
||||||
else if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
|
else if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
|
||||||
{
|
{
|
||||||
DPRINT1("dwLineID %u\n",DeviceInfo->u.MixControls.dwLineID);
|
|
||||||
UNIMPLEMENTED
|
|
||||||
//HACK
|
|
||||||
if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
|
if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
|
||||||
{
|
{
|
||||||
/* invalid parameter */
|
/* invalid parameter */
|
||||||
|
@ -1444,12 +1739,19 @@ WdmAudGetLineControls(
|
||||||
|
|
||||||
MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwLineID);
|
MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwLineID);
|
||||||
ASSERT(MixerLineSrc);
|
ASSERT(MixerLineSrc);
|
||||||
if (MixerLineSrc)
|
|
||||||
|
Index = 0;
|
||||||
|
for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
|
||||||
{
|
{
|
||||||
RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, DeviceInfo->u.MixControls.cControls) * sizeof(MIXERLINECONTROLSW));
|
if (DeviceInfo->u.MixControls.dwControlType == MixerLineSrc->LineControls[Index].dwControlType)
|
||||||
}
|
{
|
||||||
|
RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, &MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW));
|
||||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
DPRINT1("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x\n", DeviceInfo->u.MixControls.dwControlType, DeviceInfo->u.MixControls.dwLineID);
|
||||||
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
|
||||||
|
}
|
||||||
|
|
||||||
UNIMPLEMENTED;
|
UNIMPLEMENTED;
|
||||||
//DbgBreakPoint();
|
//DbgBreakPoint();
|
||||||
|
|
300
reactos/drivers/wdm/audio/legacy/wdmaud/sup.c
Normal file
300
reactos/drivers/wdm/audio/legacy/wdmaud/sup.c
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS Kernel Streaming
|
||||||
|
* FILE: drivers/wdm/audio/legacy/wdmaud/sup.c
|
||||||
|
* PURPOSE: System Audio graph builder
|
||||||
|
* PROGRAMMER: Andrew Greenwood
|
||||||
|
* Johannes Anderwald
|
||||||
|
*/
|
||||||
|
#include "wdmaud.h"
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
SetIrpIoStatus(
|
||||||
|
IN PIRP Irp,
|
||||||
|
IN NTSTATUS Status,
|
||||||
|
IN ULONG Length)
|
||||||
|
{
|
||||||
|
Irp->IoStatus.Information = Length;
|
||||||
|
Irp->IoStatus.Status = Status;
|
||||||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
ClosePin(
|
||||||
|
IN PWDMAUD_CLIENT ClientInfo,
|
||||||
|
IN ULONG FilterId,
|
||||||
|
IN ULONG PinId,
|
||||||
|
IN SOUND_DEVICE_TYPE DeviceType)
|
||||||
|
{
|
||||||
|
ULONG Index;
|
||||||
|
|
||||||
|
for(Index = 0; Index < ClientInfo->NumPins; Index++)
|
||||||
|
{
|
||||||
|
if (ClientInfo->hPins[Index].FilterId == FilterId && ClientInfo->hPins[Index].PinId == PinId && ClientInfo->hPins[Index].Handle && ClientInfo->hPins[Index].Type == DeviceType)
|
||||||
|
{
|
||||||
|
if (ClientInfo->hPins[Index].Type != MIXER_DEVICE_TYPE)
|
||||||
|
{
|
||||||
|
ZwClose(ClientInfo->hPins[Index].Handle);
|
||||||
|
}
|
||||||
|
ClientInfo->hPins[Index].Handle = NULL;
|
||||||
|
return Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MAXULONG;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
InsertPinHandle(
|
||||||
|
IN PWDMAUD_CLIENT ClientInfo,
|
||||||
|
IN ULONG FilterId,
|
||||||
|
IN ULONG PinId,
|
||||||
|
IN SOUND_DEVICE_TYPE DeviceType,
|
||||||
|
IN HANDLE PinHandle,
|
||||||
|
IN ULONG FreeIndex)
|
||||||
|
{
|
||||||
|
PWDMAUD_HANDLE Handles;
|
||||||
|
|
||||||
|
if (FreeIndex != MAXULONG)
|
||||||
|
{
|
||||||
|
/* re-use a free index */
|
||||||
|
ClientInfo->hPins[FreeIndex].Handle = PinHandle;
|
||||||
|
ClientInfo->hPins[FreeIndex].FilterId = FilterId;
|
||||||
|
ClientInfo->hPins[FreeIndex].PinId = PinId;
|
||||||
|
ClientInfo->hPins[FreeIndex].Type = DeviceType;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handles = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
|
||||||
|
|
||||||
|
if (!Handles)
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
|
if (ClientInfo->NumPins)
|
||||||
|
{
|
||||||
|
RtlMoveMemory(Handles, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
|
||||||
|
ExFreePool(ClientInfo->hPins);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientInfo->hPins = Handles;
|
||||||
|
ClientInfo->hPins[ClientInfo->NumPins].Handle = PinHandle;
|
||||||
|
ClientInfo->hPins[ClientInfo->NumPins].Type = DeviceType;
|
||||||
|
ClientInfo->hPins[ClientInfo->NumPins].FilterId = FilterId;
|
||||||
|
ClientInfo->hPins[ClientInfo->NumPins].PinId = PinId;
|
||||||
|
ClientInfo->NumPins++;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
PKEY_VALUE_PARTIAL_INFORMATION
|
||||||
|
ReadKeyValue(
|
||||||
|
IN HANDLE hSubKey,
|
||||||
|
IN PUNICODE_STRING KeyName)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG Length;
|
||||||
|
PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
|
||||||
|
|
||||||
|
/* now query MatchingDeviceId key */
|
||||||
|
Status = ZwQueryValueKey(hSubKey, KeyName, KeyValuePartialInformation, NULL, 0, &Length);
|
||||||
|
|
||||||
|
/* check for success */
|
||||||
|
if (Status != STATUS_BUFFER_TOO_SMALL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* allocate a buffer for key data */
|
||||||
|
PartialInformation = ExAllocatePool(NonPagedPool, Length);
|
||||||
|
|
||||||
|
if (!PartialInformation)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/* now query MatchingDeviceId key */
|
||||||
|
Status = ZwQueryValueKey(hSubKey, KeyName, KeyValuePartialInformation, PartialInformation, Length, &Length);
|
||||||
|
|
||||||
|
/* check for success */
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ExFreePool(PartialInformation);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PartialInformation->Type != REG_SZ)
|
||||||
|
{
|
||||||
|
/* invalid key type */
|
||||||
|
ExFreePool(PartialInformation);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PartialInformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CompareProductName(
|
||||||
|
IN HANDLE hSubKey,
|
||||||
|
IN LPWSTR PnpName,
|
||||||
|
IN ULONG ProductNameSize,
|
||||||
|
OUT LPWSTR ProductName)
|
||||||
|
{
|
||||||
|
PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
|
||||||
|
UNICODE_STRING DriverDescName = RTL_CONSTANT_STRING(L"DriverDesc");
|
||||||
|
UNICODE_STRING MatchingDeviceIdName = RTL_CONSTANT_STRING(L"MatchingDeviceId");
|
||||||
|
ULONG Length;
|
||||||
|
LPWSTR DeviceName;
|
||||||
|
|
||||||
|
/* read MatchingDeviceId value */
|
||||||
|
PartialInformation = ReadKeyValue(hSubKey, &MatchingDeviceIdName);
|
||||||
|
|
||||||
|
if (!PartialInformation)
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
|
|
||||||
|
/* extract last '&' */
|
||||||
|
DeviceName = wcsrchr((LPWSTR)PartialInformation->Data, L'&');
|
||||||
|
ASSERT(DeviceName);
|
||||||
|
/* terminate it */
|
||||||
|
DeviceName[0] = L'\0';
|
||||||
|
|
||||||
|
Length = wcslen((LPWSTR)PartialInformation->Data);
|
||||||
|
|
||||||
|
DPRINT("DeviceName %S PnpName %S Length %u\n", (LPWSTR)PartialInformation->Data, PnpName, Length);
|
||||||
|
|
||||||
|
if (_wcsnicmp((LPWSTR)PartialInformation->Data, &PnpName[4], Length))
|
||||||
|
{
|
||||||
|
ExFreePool(PartialInformation);
|
||||||
|
return STATUS_NO_MATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free buffer */
|
||||||
|
ExFreePool(PartialInformation);
|
||||||
|
|
||||||
|
/* read DriverDescName value */
|
||||||
|
PartialInformation = ReadKeyValue(hSubKey, &DriverDescName);
|
||||||
|
|
||||||
|
if (!PartialInformation)
|
||||||
|
{
|
||||||
|
/* failed to read driver desc key */
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy key name */
|
||||||
|
Length = min(ProductNameSize * sizeof(WCHAR), PartialInformation->DataLength);
|
||||||
|
RtlMoveMemory(ProductName, (PVOID)PartialInformation->Data, Length);
|
||||||
|
|
||||||
|
/* zero terminate it */
|
||||||
|
ProductName[ProductNameSize-1] = L'\0';
|
||||||
|
|
||||||
|
/* free buffer */
|
||||||
|
ExFreePool(PartialInformation);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
FindProductName(
|
||||||
|
IN LPWSTR PnpName,
|
||||||
|
IN ULONG ProductNameSize,
|
||||||
|
OUT LPWSTR ProductName)
|
||||||
|
{
|
||||||
|
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E96C-E325-11CE-BFC1-08002BE10318}");
|
||||||
|
|
||||||
|
UNICODE_STRING SubKeyName;
|
||||||
|
WCHAR SubKey[20];
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
HANDLE hKey, hSubKey;
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG Length, Index;
|
||||||
|
PKEY_FULL_INFORMATION KeyInformation;
|
||||||
|
|
||||||
|
for(Index = 0; Index < wcslen(PnpName); Index++)
|
||||||
|
{
|
||||||
|
if (PnpName[Index] == '#')
|
||||||
|
PnpName[Index] = L'\\';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* initialize key attributes */
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, NULL, NULL);
|
||||||
|
|
||||||
|
/* open the key */
|
||||||
|
Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjectAttributes);
|
||||||
|
|
||||||
|
/* check for success */
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
/* query num of subkeys */
|
||||||
|
Status = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &Length);
|
||||||
|
|
||||||
|
if (Status != STATUS_BUFFER_TOO_SMALL)
|
||||||
|
{
|
||||||
|
DPRINT1("ZwQueryKey failed with %x\n", Status);
|
||||||
|
/* failed */
|
||||||
|
ZwClose(hKey);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate key information struct */
|
||||||
|
KeyInformation = ExAllocatePool(NonPagedPool, Length);
|
||||||
|
if (!KeyInformation)
|
||||||
|
{
|
||||||
|
/* no memory */
|
||||||
|
ZwClose(hKey);
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* query num of subkeys */
|
||||||
|
Status = ZwQueryKey(hKey, KeyFullInformation, (PVOID)KeyInformation, Length, &Length);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("ZwQueryKey failed with %x\n", Status);
|
||||||
|
ExFreePool(KeyInformation);
|
||||||
|
ZwClose(hKey);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now iterate through all subkeys */
|
||||||
|
for(Index = 0; Index < KeyInformation->SubKeys; Index++)
|
||||||
|
{
|
||||||
|
/* subkeys are always in the format 0000-XXXX */
|
||||||
|
swprintf(SubKey, L"%04u", Index);
|
||||||
|
|
||||||
|
/* initialize subkey name */
|
||||||
|
RtlInitUnicodeString(&SubKeyName, SubKey);
|
||||||
|
|
||||||
|
/* initialize key attributes */
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes, &SubKeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, hKey, NULL);
|
||||||
|
|
||||||
|
/* open the sub key */
|
||||||
|
Status = ZwOpenKey(&hSubKey, GENERIC_READ, &ObjectAttributes);
|
||||||
|
|
||||||
|
/* check for success */
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* compare product name */
|
||||||
|
Status = CompareProductName(hSubKey, PnpName, ProductNameSize, ProductName);
|
||||||
|
|
||||||
|
/* close subkey */
|
||||||
|
ZwClose(hSubKey);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free buffer */
|
||||||
|
ExFreePool(KeyInformation);
|
||||||
|
|
||||||
|
/* close key */
|
||||||
|
ZwClose(hKey);
|
||||||
|
|
||||||
|
/* no matching key found */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
756
reactos/drivers/wdm/audio/legacy/wdmaud/wave.c
Normal file
756
reactos/drivers/wdm/audio/legacy/wdmaud/wave.c
Normal file
|
@ -0,0 +1,756 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS Kernel Streaming
|
||||||
|
* FILE: drivers/wdm/audio/legacy/wdmaud/wave.c
|
||||||
|
* PURPOSE: Wave Out enumeration
|
||||||
|
* PROGRAMMER: Andrew Greenwood
|
||||||
|
* Johannes Anderwald
|
||||||
|
*/
|
||||||
|
#include "wdmaud.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ULONG SampleRate;
|
||||||
|
ULONG Bit8Mono;
|
||||||
|
ULONG Bit8Stereo;
|
||||||
|
ULONG Bit16Mono;
|
||||||
|
ULONG Bit16Stereo;
|
||||||
|
}AUDIO_RANGE;
|
||||||
|
|
||||||
|
#define AUDIO_TEST_RANGE (5)
|
||||||
|
|
||||||
|
static AUDIO_RANGE TestRange[AUDIO_TEST_RANGE] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
11025,
|
||||||
|
WAVE_FORMAT_1M08,
|
||||||
|
WAVE_FORMAT_1S08,
|
||||||
|
WAVE_FORMAT_1M16,
|
||||||
|
WAVE_FORMAT_1S16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
22050,
|
||||||
|
WAVE_FORMAT_2M08,
|
||||||
|
WAVE_FORMAT_2S08,
|
||||||
|
WAVE_FORMAT_2M16,
|
||||||
|
WAVE_FORMAT_2S16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
44100,
|
||||||
|
WAVE_FORMAT_4M08,
|
||||||
|
WAVE_FORMAT_4S08,
|
||||||
|
WAVE_FORMAT_4M16,
|
||||||
|
WAVE_FORMAT_4S16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
48000,
|
||||||
|
WAVE_FORMAT_48M08,
|
||||||
|
WAVE_FORMAT_48S08,
|
||||||
|
WAVE_FORMAT_48M16,
|
||||||
|
WAVE_FORMAT_48S16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
96000,
|
||||||
|
WAVE_FORMAT_96M08,
|
||||||
|
WAVE_FORMAT_96S08,
|
||||||
|
WAVE_FORMAT_96M16,
|
||||||
|
WAVE_FORMAT_96S16
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LPWAVE_INFO
|
||||||
|
AllocateWaveInfo()
|
||||||
|
{
|
||||||
|
/* allocate wav info */
|
||||||
|
LPWAVE_INFO WaveOutInfo = ExAllocatePool(NonPagedPool, sizeof(WAVE_INFO));
|
||||||
|
if (!WaveOutInfo)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* zero wave info struct */
|
||||||
|
RtlZeroMemory(WaveOutInfo, sizeof(WAVE_INFO));
|
||||||
|
|
||||||
|
return WaveOutInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
PKSPIN_CONNECT
|
||||||
|
AllocatePinConnect(
|
||||||
|
ULONG DataFormatSize)
|
||||||
|
{
|
||||||
|
PKSPIN_CONNECT Connect = ExAllocatePool(NonPagedPool, sizeof(KSPIN_CONNECT) + DataFormatSize);
|
||||||
|
if (!Connect)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* zero pin connect struct */
|
||||||
|
RtlZeroMemory(Connect, sizeof(KSPIN_CONNECT) + DataFormatSize);
|
||||||
|
|
||||||
|
return Connect;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
GetWaveInfoByIndexAndType(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN ULONG DeviceIndex,
|
||||||
|
IN SOUND_DEVICE_TYPE DeviceType,
|
||||||
|
OUT LPWAVE_INFO *OutWaveInfo)
|
||||||
|
{
|
||||||
|
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
||||||
|
ULONG Index = 0;
|
||||||
|
PLIST_ENTRY Entry, ListHead;
|
||||||
|
LPWAVE_INFO WaveInfo;
|
||||||
|
|
||||||
|
/* get device extension */
|
||||||
|
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||||
|
|
||||||
|
if (DeviceType == WAVE_IN_DEVICE_TYPE)
|
||||||
|
ListHead = &DeviceExtension->WaveInList;
|
||||||
|
else
|
||||||
|
ListHead = &DeviceExtension->WaveOutList;
|
||||||
|
|
||||||
|
/* get first entry */
|
||||||
|
Entry = ListHead->Flink;
|
||||||
|
|
||||||
|
while(Entry != ListHead)
|
||||||
|
{
|
||||||
|
WaveInfo = (LPWAVE_INFO)CONTAINING_RECORD(Entry, WAVE_INFO, Entry);
|
||||||
|
|
||||||
|
if (Index == DeviceIndex)
|
||||||
|
{
|
||||||
|
*OutWaveInfo = WaveInfo;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
Index++;
|
||||||
|
Entry = Entry->Flink;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
InitializePinConnect(
|
||||||
|
IN OUT PKSPIN_CONNECT PinConnect,
|
||||||
|
IN ULONG PinId)
|
||||||
|
{
|
||||||
|
PinConnect->Interface.Set = KSINTERFACESETID_Standard;
|
||||||
|
PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
|
||||||
|
PinConnect->Interface.Flags = 0;
|
||||||
|
PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
|
||||||
|
PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
|
||||||
|
PinConnect->Medium.Flags = 0;
|
||||||
|
PinConnect->PinToHandle = NULL;
|
||||||
|
PinConnect->PinId = PinId;
|
||||||
|
PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
|
||||||
|
PinConnect->Priority.PrioritySubClass = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
InitializeDataFormat(
|
||||||
|
IN PKSDATAFORMAT_WAVEFORMATEX DataFormat,
|
||||||
|
LPWAVEFORMATEX WaveFormatEx)
|
||||||
|
{
|
||||||
|
|
||||||
|
DataFormat->WaveFormatEx.wFormatTag = WaveFormatEx->wFormatTag;
|
||||||
|
DataFormat->WaveFormatEx.nChannels = WaveFormatEx->nChannels;
|
||||||
|
DataFormat->WaveFormatEx.nSamplesPerSec = WaveFormatEx->nSamplesPerSec;
|
||||||
|
DataFormat->WaveFormatEx.nBlockAlign = WaveFormatEx->nBlockAlign;
|
||||||
|
DataFormat->WaveFormatEx.nAvgBytesPerSec = WaveFormatEx->nAvgBytesPerSec;
|
||||||
|
DataFormat->WaveFormatEx.wBitsPerSample = WaveFormatEx->wBitsPerSample;
|
||||||
|
DataFormat->WaveFormatEx.cbSize = 0;
|
||||||
|
DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
|
||||||
|
DataFormat->DataFormat.Flags = 0;
|
||||||
|
DataFormat->DataFormat.Reserved = 0;
|
||||||
|
DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
|
||||||
|
|
||||||
|
DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||||
|
DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
|
||||||
|
DataFormat->DataFormat.SampleSize = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
AttachToVirtualAudioDevice(
|
||||||
|
IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,
|
||||||
|
IN ULONG VirtualDeviceId)
|
||||||
|
{
|
||||||
|
ULONG BytesReturned;
|
||||||
|
SYSAUDIO_INSTANCE_INFO InstanceInfo;
|
||||||
|
|
||||||
|
/* setup property request */
|
||||||
|
InstanceInfo.Property.Set = KSPROPSETID_Sysaudio;
|
||||||
|
InstanceInfo.Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
|
||||||
|
InstanceInfo.Property.Flags = KSPROPERTY_TYPE_SET;
|
||||||
|
InstanceInfo.Flags = 0;
|
||||||
|
InstanceInfo.DeviceNumber = VirtualDeviceId;
|
||||||
|
|
||||||
|
/* attach to virtual device */
|
||||||
|
return KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
GetAudioPinDataRanges(
|
||||||
|
IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,
|
||||||
|
IN ULONG FilterId,
|
||||||
|
IN ULONG PinId,
|
||||||
|
IN OUT PKSMULTIPLE_ITEM * OutMultipleItem)
|
||||||
|
{
|
||||||
|
KSP_PIN PinProperty;
|
||||||
|
ULONG BytesReturned = 0;
|
||||||
|
NTSTATUS Status;
|
||||||
|
PKSMULTIPLE_ITEM MultipleItem;
|
||||||
|
|
||||||
|
/* retrieve size of data ranges buffer */
|
||||||
|
PinProperty.Reserved = FilterId;
|
||||||
|
PinProperty.PinId = PinId;
|
||||||
|
PinProperty.Property.Set = KSPROPSETID_Pin;
|
||||||
|
PinProperty.Property.Id = KSPROPERTY_PIN_DATARANGES;
|
||||||
|
PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
|
||||||
|
|
||||||
|
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)NULL, 0, &BytesReturned);
|
||||||
|
if (Status != STATUS_MORE_ENTRIES)
|
||||||
|
{
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultipleItem = ExAllocatePool(NonPagedPool, BytesReturned);
|
||||||
|
if (!MultipleItem)
|
||||||
|
{
|
||||||
|
/* not enough memory */
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* failed */
|
||||||
|
ExFreePool(MultipleItem);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save result */
|
||||||
|
*OutMultipleItem = MultipleItem;
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
FindAudioDataRange(
|
||||||
|
PKSMULTIPLE_ITEM MultipleItem,
|
||||||
|
PKSDATARANGE_AUDIO * OutDataRangeAudio)
|
||||||
|
{
|
||||||
|
ULONG Index;
|
||||||
|
PKSDATARANGE_AUDIO DataRangeAudio;
|
||||||
|
PKSDATARANGE DataRange;
|
||||||
|
|
||||||
|
DataRange = (PKSDATARANGE) (MultipleItem + 1);
|
||||||
|
for(Index = 0; Index < MultipleItem->Count; Index++)
|
||||||
|
{
|
||||||
|
if (DataRange->FormatSize == sizeof(KSDATARANGE_AUDIO))
|
||||||
|
{
|
||||||
|
DataRangeAudio = (PKSDATARANGE_AUDIO)DataRange;
|
||||||
|
if (IsEqualGUIDAligned(&DataRangeAudio->DataRange.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
|
||||||
|
IsEqualGUIDAligned(&DataRangeAudio->DataRange.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
|
||||||
|
IsEqualGUIDAligned(&DataRangeAudio->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
|
||||||
|
{
|
||||||
|
DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio->MinimumSampleFrequency, DataRangeAudio->MaximumSampleFrequency,
|
||||||
|
DataRangeAudio->MinimumBitsPerSample, DataRangeAudio->MaximumBitsPerSample, DataRangeAudio->MaximumChannels);
|
||||||
|
*OutDataRangeAudio = DataRangeAudio;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
OpenWavePin(
|
||||||
|
IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,
|
||||||
|
IN ULONG FilterId,
|
||||||
|
IN ULONG PinId,
|
||||||
|
IN LPWAVEFORMATEX WaveFormatEx,
|
||||||
|
IN ACCESS_MASK DesiredAccess,
|
||||||
|
OUT PHANDLE PinHandle)
|
||||||
|
{
|
||||||
|
PKSPIN_CONNECT PinConnect;
|
||||||
|
PKSDATAFORMAT_WAVEFORMATEX DataFormat;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* allocate pin connect */
|
||||||
|
PinConnect = AllocatePinConnect(sizeof(KSDATAFORMAT_WAVEFORMATEX));
|
||||||
|
if (!PinConnect)
|
||||||
|
{
|
||||||
|
/* no memory */
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize pin connect struct */
|
||||||
|
InitializePinConnect(PinConnect, PinId);
|
||||||
|
|
||||||
|
/* get offset to dataformat */
|
||||||
|
DataFormat = (PKSDATAFORMAT_WAVEFORMATEX) (PinConnect + 1);
|
||||||
|
/* initialize with requested wave format */
|
||||||
|
InitializeDataFormat(DataFormat, WaveFormatEx);
|
||||||
|
|
||||||
|
/* first attach to the virtual device */
|
||||||
|
Status = AttachToVirtualAudioDevice(DeviceExtension, FilterId);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* failed */
|
||||||
|
ExFreePool(PinConnect);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now create the pin */
|
||||||
|
Status = KsCreatePin(DeviceExtension->hSysAudio, PinConnect, DesiredAccess, PinHandle);
|
||||||
|
|
||||||
|
/* free create info */
|
||||||
|
ExFreePool(PinConnect);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG
|
||||||
|
GetPinInstanceCount(
|
||||||
|
PWDMAUD_DEVICE_EXTENSION DeviceExtension,
|
||||||
|
ULONG FilterId,
|
||||||
|
ULONG PinId)
|
||||||
|
{
|
||||||
|
KSP_PIN PinRequest;
|
||||||
|
KSPIN_CINSTANCES PinInstances;
|
||||||
|
ULONG BytesReturned;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* query the instance count */
|
||||||
|
PinRequest.Reserved = FilterId;
|
||||||
|
PinRequest.PinId = PinId;
|
||||||
|
PinRequest.Property.Set = KSPROPSETID_Pin;
|
||||||
|
PinRequest.Property.Flags = KSPROPERTY_TYPE_GET;
|
||||||
|
PinRequest.Property.Id = KSPROPERTY_PIN_CINSTANCES;
|
||||||
|
|
||||||
|
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinRequest, sizeof(KSP_PIN), (PVOID)&PinInstances, sizeof(KSPIN_CINSTANCES), &BytesReturned);
|
||||||
|
ASSERT(Status == STATUS_SUCCESS);
|
||||||
|
return PinInstances.CurrentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CheckSampleFormat(
|
||||||
|
PWDMAUD_DEVICE_EXTENSION DeviceExtension,
|
||||||
|
LPWAVE_INFO WaveInfo,
|
||||||
|
ULONG SampleRate,
|
||||||
|
ULONG NumChannels,
|
||||||
|
ULONG BitsPerSample)
|
||||||
|
{
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
WAVEFORMATEX WaveFormat;
|
||||||
|
HANDLE PinHandle;
|
||||||
|
|
||||||
|
/* clear wave format */
|
||||||
|
RtlZeroMemory(&WaveFormat, sizeof(WAVEFORMATEX));
|
||||||
|
|
||||||
|
WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
WaveFormat.nChannels = NumChannels;
|
||||||
|
WaveFormat.nSamplesPerSec = SampleRate;
|
||||||
|
WaveFormat.nAvgBytesPerSec = SampleRate * NumChannels * (BitsPerSample/8);
|
||||||
|
WaveFormat.nBlockAlign = (NumChannels * BitsPerSample) / 8;
|
||||||
|
WaveFormat.wBitsPerSample = BitsPerSample;
|
||||||
|
WaveFormat.cbSize = sizeof(WAVEFORMATEX);
|
||||||
|
|
||||||
|
Status = OpenWavePin(DeviceExtension, WaveInfo->FilterId, WaveInfo->PinId, &WaveFormat, GENERIC_READ | GENERIC_WRITE, &PinHandle);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* success */
|
||||||
|
ZwClose(PinHandle);
|
||||||
|
|
||||||
|
while(GetPinInstanceCount(DeviceExtension, WaveInfo->FilterId, WaveInfo->PinId))
|
||||||
|
KeStallExecutionProcessor(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT("SampleRate %u BitsPerSample %u NumChannels %u Status %x bInput %u\n", SampleRate, BitsPerSample, NumChannels, Status, WaveInfo->bInput);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CheckFormat(
|
||||||
|
PWDMAUD_DEVICE_EXTENSION DeviceExtension,
|
||||||
|
PKSDATARANGE_AUDIO DataRangeAudio,
|
||||||
|
LPWAVE_INFO WaveInfo)
|
||||||
|
{
|
||||||
|
ULONG Index, SampleFrequency;
|
||||||
|
ULONG Result = 0;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
for(Index = 0; Index < AUDIO_TEST_RANGE; Index++)
|
||||||
|
{
|
||||||
|
SampleFrequency = TestRange[Index].SampleRate;
|
||||||
|
|
||||||
|
if (DataRangeAudio->MinimumSampleFrequency <= SampleFrequency && DataRangeAudio->MaximumSampleFrequency >= SampleFrequency)
|
||||||
|
{
|
||||||
|
/* the audio adapter supports the sample frequency */
|
||||||
|
if (DataRangeAudio->MinimumBitsPerSample <= 8 && DataRangeAudio->MaximumBitsPerSample >= 8)
|
||||||
|
{
|
||||||
|
/* check if pin supports the sample rate in 8-Bit Mono */
|
||||||
|
Status = CheckSampleFormat(DeviceExtension, WaveInfo, SampleFrequency, 1, 8);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
Result |= TestRange[Index].Bit8Mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DataRangeAudio->MaximumChannels > 1)
|
||||||
|
{
|
||||||
|
/* check if pin supports the sample rate in 8-Bit Stereo */
|
||||||
|
Status = CheckSampleFormat(DeviceExtension, WaveInfo, SampleFrequency, 2, 8);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
Result |= TestRange[Index].Bit8Stereo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DataRangeAudio->MinimumBitsPerSample <= 16 && DataRangeAudio->MaximumBitsPerSample >= 16)
|
||||||
|
{
|
||||||
|
/* check if pin supports the sample rate in 16-Bit Mono */
|
||||||
|
Status = CheckSampleFormat(DeviceExtension, WaveInfo, SampleFrequency, 1, 16);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
Result |= TestRange[Index].Bit16Mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DataRangeAudio->MaximumChannels > 1)
|
||||||
|
{
|
||||||
|
/* check if pin supports the sample rate in 16-Bit Stereo */
|
||||||
|
Status = CheckSampleFormat(DeviceExtension, WaveInfo, SampleFrequency, 2, 16);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
Result |= TestRange[Index].Bit16Stereo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (WaveInfo->bInput)
|
||||||
|
WaveInfo->u.InCaps.dwFormats = Result;
|
||||||
|
else
|
||||||
|
WaveInfo->u.OutCaps.dwFormats = Result;
|
||||||
|
|
||||||
|
DPRINT("Format %x bInput %u\n", Result, WaveInfo->bInput);
|
||||||
|
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
InitializeWaveInfo(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN ULONG FilterId,
|
||||||
|
IN ULONG PinId,
|
||||||
|
IN ULONG bInput)
|
||||||
|
{
|
||||||
|
KSP_PIN PinProperty;
|
||||||
|
KSCOMPONENTID ComponentId;
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG BytesReturned;
|
||||||
|
WCHAR DeviceName[MAX_PATH];
|
||||||
|
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
||||||
|
PKSMULTIPLE_ITEM MultipleItem;
|
||||||
|
PKSDATARANGE_AUDIO DataRangeAudio;
|
||||||
|
LPWAVE_INFO WaveInfo = AllocateWaveInfo();
|
||||||
|
|
||||||
|
|
||||||
|
if (!WaveInfo)
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
|
/* initialize wave info */
|
||||||
|
WaveInfo->bInput = bInput;
|
||||||
|
WaveInfo->FilterId = FilterId;
|
||||||
|
WaveInfo->PinId = PinId;
|
||||||
|
|
||||||
|
/* setup request to return component id */
|
||||||
|
PinProperty.PinId = FilterId;
|
||||||
|
PinProperty.Property.Set = KSPROPSETID_Sysaudio;
|
||||||
|
PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_COMPONENT_ID;
|
||||||
|
PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
|
||||||
|
|
||||||
|
/* get device extension */
|
||||||
|
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||||
|
|
||||||
|
/* query sysaudio for component id */
|
||||||
|
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)&ComponentId, sizeof(KSCOMPONENTID), &BytesReturned);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
if (bInput)
|
||||||
|
{
|
||||||
|
WaveInfo->u.InCaps.wMid = ComponentId.Manufacturer.Data1 - 0xd5a47fa7;
|
||||||
|
WaveInfo->u.InCaps.vDriverVersion = MAKELONG(ComponentId.Version, ComponentId.Revision);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WaveInfo->u.OutCaps.wMid = ComponentId.Manufacturer.Data1 - 0xd5a47fa7;
|
||||||
|
WaveInfo->u.OutCaps.vDriverVersion = MAKELONG(ComponentId.Version, ComponentId.Revision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* set up something useful */
|
||||||
|
if (bInput)
|
||||||
|
{
|
||||||
|
WaveInfo->u.InCaps.wMid = MM_MICROSOFT;
|
||||||
|
WaveInfo->u.InCaps.wPid = MM_PID_UNMAPPED;
|
||||||
|
WaveInfo->u.InCaps.vDriverVersion = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WaveInfo->u.OutCaps.wMid = MM_MICROSOFT;
|
||||||
|
WaveInfo->u.OutCaps.wPid = MM_PID_UNMAPPED;
|
||||||
|
WaveInfo->u.OutCaps.vDriverVersion = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* retrieve pnp base name */
|
||||||
|
PinProperty.PinId = FilterId;
|
||||||
|
PinProperty.Property.Set = KSPROPSETID_Sysaudio;
|
||||||
|
PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
|
||||||
|
PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
|
||||||
|
|
||||||
|
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)DeviceName, sizeof(DeviceName), &BytesReturned);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* find product name */
|
||||||
|
if (bInput)
|
||||||
|
Status = FindProductName(DeviceName, MAXPNAMELEN, WaveInfo->u.OutCaps.szPname);
|
||||||
|
else
|
||||||
|
Status = FindProductName(DeviceName, MAXPNAMELEN, WaveInfo->u.InCaps.szPname);
|
||||||
|
|
||||||
|
/* check for success */
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
if (bInput)
|
||||||
|
WaveInfo->u.OutCaps.szPname[0] = L'\0';
|
||||||
|
else
|
||||||
|
WaveInfo->u.InCaps.szPname[0] = L'\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = GetAudioPinDataRanges(DeviceExtension, FilterId, PinId, &MultipleItem);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* find a audio data range */
|
||||||
|
Status = FindAudioDataRange(MultipleItem, &DataRangeAudio);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
if (bInput)
|
||||||
|
{
|
||||||
|
WaveInfo->u.InCaps.wChannels = DataRangeAudio->MaximumChannels;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WaveInfo->u.OutCaps.wChannels = DataRangeAudio->MaximumChannels;
|
||||||
|
}
|
||||||
|
CheckFormat(DeviceExtension, DataRangeAudio, WaveInfo);
|
||||||
|
}
|
||||||
|
ExFreePool(MultipleItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bInput)
|
||||||
|
{
|
||||||
|
InsertTailList(&DeviceExtension->WaveInList, &WaveInfo->Entry);
|
||||||
|
DeviceExtension->WaveInDeviceCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InsertTailList(&DeviceExtension->WaveOutList, &WaveInfo->Entry);
|
||||||
|
DeviceExtension->WaveOutDeviceCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
WdmAudWaveInitialize(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject)
|
||||||
|
{
|
||||||
|
KSP_PIN Pin;
|
||||||
|
ULONG Count, BytesReturned, Index, SubIndex, Result, NumPins;
|
||||||
|
NTSTATUS Status;
|
||||||
|
KSPIN_COMMUNICATION Communication;
|
||||||
|
KSPIN_DATAFLOW DataFlow;
|
||||||
|
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
||||||
|
|
||||||
|
Pin.Property.Set = KSPROPSETID_Sysaudio;
|
||||||
|
Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
|
||||||
|
Pin.Property.Flags = KSPROPERTY_TYPE_GET;
|
||||||
|
|
||||||
|
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||||
|
|
||||||
|
/* set wave count to zero */
|
||||||
|
DeviceExtension->WaveInDeviceCount = 0;
|
||||||
|
DeviceExtension->WaveOutDeviceCount = 0;
|
||||||
|
|
||||||
|
/* intialize list head */
|
||||||
|
InitializeListHead(&DeviceExtension->WaveInList);
|
||||||
|
InitializeListHead(&DeviceExtension->WaveOutList);
|
||||||
|
|
||||||
|
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
|
Result = 0;
|
||||||
|
for(Index = 0; Index < Count; Index++)
|
||||||
|
{
|
||||||
|
/* query number of pins */
|
||||||
|
Pin.Reserved = Index; // see sysaudio
|
||||||
|
Pin.Property.Flags = KSPROPERTY_TYPE_GET;
|
||||||
|
Pin.Property.Set = KSPROPSETID_Pin;
|
||||||
|
Pin.Property.Id = KSPROPERTY_PIN_CTYPES;
|
||||||
|
Pin.PinId = 0;
|
||||||
|
|
||||||
|
Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* enumerate now all pins */
|
||||||
|
for(SubIndex = 0; SubIndex < NumPins; SubIndex++)
|
||||||
|
{
|
||||||
|
Pin.PinId = SubIndex;
|
||||||
|
Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
|
||||||
|
Communication = KSPIN_COMMUNICATION_NONE;
|
||||||
|
|
||||||
|
/* get pin communication type */
|
||||||
|
KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
|
||||||
|
|
||||||
|
Pin.Property.Id = KSPROPERTY_PIN_DATAFLOW;
|
||||||
|
DataFlow = 0;
|
||||||
|
|
||||||
|
/* get pin dataflow type */
|
||||||
|
KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
|
||||||
|
|
||||||
|
if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
|
||||||
|
{
|
||||||
|
/* found a wave out device */
|
||||||
|
InitializeWaveInfo(DeviceObject, Index, SubIndex, FALSE);
|
||||||
|
}
|
||||||
|
else if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
|
||||||
|
{
|
||||||
|
/* found a wave in device */
|
||||||
|
InitializeWaveInfo(DeviceObject, Index, SubIndex, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
WdmAudControlOpenWave(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN PIRP Irp,
|
||||||
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
||||||
|
IN PWDMAUD_CLIENT ClientInfo)
|
||||||
|
{
|
||||||
|
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
||||||
|
LPWAVE_INFO WaveInfo;
|
||||||
|
NTSTATUS Status;
|
||||||
|
ACCESS_MASK DesiredAccess = 0;
|
||||||
|
HANDLE PinHandle;
|
||||||
|
ULONG FreeIndex;
|
||||||
|
|
||||||
|
if (DeviceInfo->u.WaveFormatEx.wFormatTag != WAVE_FORMAT_PCM)
|
||||||
|
{
|
||||||
|
DPRINT("FIXME: Only WAVE_FORMAT_PCM is supported RequestFormat %x\n", DeviceInfo->u.WaveFormatEx.wFormatTag);
|
||||||
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get device extension */
|
||||||
|
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||||
|
|
||||||
|
/* find destination wave */
|
||||||
|
Status = GetWaveInfoByIndexAndType(DeviceObject, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType, &WaveInfo);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* failed to find wave info */
|
||||||
|
DbgBreakPoint();
|
||||||
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* close pin handle which uses same virtual audio device id and pin id */
|
||||||
|
FreeIndex = ClosePin(ClientInfo, WaveInfo->FilterId, WaveInfo->PinId, DeviceInfo->DeviceType);
|
||||||
|
|
||||||
|
/* get desired access */
|
||||||
|
if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
|
||||||
|
{
|
||||||
|
DesiredAccess |= GENERIC_READ;
|
||||||
|
}
|
||||||
|
else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
|
||||||
|
{
|
||||||
|
DesiredAccess |= GENERIC_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now try open the pin */
|
||||||
|
Status = OpenWavePin(DeviceExtension, WaveInfo->FilterId, WaveInfo->PinId, &DeviceInfo->u.WaveFormatEx, DesiredAccess, &PinHandle);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* failed to open the pin */
|
||||||
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store the handle */
|
||||||
|
Status = InsertPinHandle(ClientInfo, WaveInfo->FilterId, WaveInfo->PinId, DeviceInfo->DeviceType, PinHandle, FreeIndex);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* failed to insert handle */
|
||||||
|
ZwClose(PinHandle);
|
||||||
|
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store pin handle */
|
||||||
|
DeviceInfo->hDevice = PinHandle;
|
||||||
|
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
WdmAudWaveCapabilities(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
||||||
|
IN PWDMAUD_CLIENT ClientInfo,
|
||||||
|
IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
|
||||||
|
{
|
||||||
|
LPWAVE_INFO WaveInfo;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* find destination wave */
|
||||||
|
Status = GetWaveInfoByIndexAndType(DeviceObject, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType, &WaveInfo);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* failed to find wave info */
|
||||||
|
DbgBreakPoint();
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
|
||||||
|
{
|
||||||
|
RtlMoveMemory(&DeviceInfo->u.WaveInCaps, &WaveInfo->u.InCaps, sizeof(WAVEINCAPSW));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RtlMoveMemory(&DeviceInfo->u.WaveOutCaps, &WaveInfo->u.OutCaps, sizeof(WAVEOUTCAPSW));
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
|
@ -40,21 +40,33 @@ typedef struct
|
||||||
ULONG DeviceIndex;
|
ULONG DeviceIndex;
|
||||||
MIXERLINEW Line;
|
MIXERLINEW Line;
|
||||||
LPMIXERCONTROLW LineControls;
|
LPMIXERCONTROLW LineControls;
|
||||||
|
PULONG NodeIds;
|
||||||
}MIXERLINE_EXT, *LPMIXERLINE_EXT;
|
}MIXERLINE_EXT, *LPMIXERLINE_EXT;
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
HANDLE hMixer;
|
|
||||||
PFILE_OBJECT MixerFileObject;
|
|
||||||
|
|
||||||
MIXERCAPSW MixCaps;
|
MIXERCAPSW MixCaps;
|
||||||
|
|
||||||
LIST_ENTRY LineList;
|
LIST_ENTRY LineList;
|
||||||
|
ULONG ControlId;
|
||||||
}MIXER_INFO, *LPMIXER_INFO;
|
}MIXER_INFO, *LPMIXER_INFO;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
LIST_ENTRY Entry;
|
||||||
|
ULONG FilterId;
|
||||||
|
ULONG PinId;
|
||||||
|
ULONG bInput;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
WAVEOUTCAPSW OutCaps;
|
||||||
|
WAVEINCAPSW InCaps;
|
||||||
|
}u;
|
||||||
|
}WAVE_INFO, *LPWAVE_INFO;
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
LIST_ENTRY Entry;
|
LIST_ENTRY Entry;
|
||||||
|
@ -77,6 +89,12 @@ typedef struct
|
||||||
ULONG MixerInfoCount;
|
ULONG MixerInfoCount;
|
||||||
LPMIXER_INFO MixerInfo;
|
LPMIXER_INFO MixerInfo;
|
||||||
|
|
||||||
|
ULONG WaveInDeviceCount;
|
||||||
|
LIST_ENTRY WaveInList;
|
||||||
|
|
||||||
|
ULONG WaveOutDeviceCount;
|
||||||
|
LIST_ENTRY WaveOutList;
|
||||||
|
|
||||||
|
|
||||||
}WDMAUD_DEVICE_EXTENSION, *PWDMAUD_DEVICE_EXTENSION;
|
}WDMAUD_DEVICE_EXTENSION, *PWDMAUD_DEVICE_EXTENSION;
|
||||||
|
|
||||||
|
@ -86,6 +104,16 @@ typedef struct
|
||||||
PIRP Irp;
|
PIRP Irp;
|
||||||
}CONTEXT_WRITE, *PCONTEXT_WRITE;
|
}CONTEXT_WRITE, *PCONTEXT_WRITE;
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
OpenWavePin(
|
||||||
|
IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,
|
||||||
|
IN ULONG FilterId,
|
||||||
|
IN ULONG PinId,
|
||||||
|
IN LPWAVEFORMATEX WaveFormatEx,
|
||||||
|
IN ACCESS_MASK DesiredAccess,
|
||||||
|
OUT PHANDLE PinHandle);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
WdmAudRegisterDeviceInterface(
|
WdmAudRegisterDeviceInterface(
|
||||||
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
||||||
|
@ -120,6 +148,14 @@ WdmAudControlOpenMixer(
|
||||||
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
||||||
IN PWDMAUD_CLIENT ClientInfo);
|
IN PWDMAUD_CLIENT ClientInfo);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
WdmAudControlOpenWave(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN PIRP Irp,
|
||||||
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
||||||
|
IN PWDMAUD_CLIENT ClientInfo);
|
||||||
|
|
||||||
|
|
||||||
ULONG
|
ULONG
|
||||||
GetNumOfMixerDevices(
|
GetNumOfMixerDevices(
|
||||||
IN PDEVICE_OBJECT DeviceObject);
|
IN PDEVICE_OBJECT DeviceObject);
|
||||||
|
@ -148,6 +184,13 @@ WdmAudMixerCapabilities(
|
||||||
IN PWDMAUD_CLIENT ClientInfo,
|
IN PWDMAUD_CLIENT ClientInfo,
|
||||||
IN PWDMAUD_DEVICE_EXTENSION DeviceExtension);
|
IN PWDMAUD_DEVICE_EXTENSION DeviceExtension);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
WdmAudWaveCapabilities(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
||||||
|
IN PWDMAUD_CLIENT ClientInfo,
|
||||||
|
IN PWDMAUD_DEVICE_EXTENSION DeviceExtension);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
WdmAudFrameSize(
|
WdmAudFrameSize(
|
||||||
|
@ -192,5 +235,26 @@ NTSTATUS
|
||||||
WdmAudMixerInitialize(
|
WdmAudMixerInitialize(
|
||||||
IN PDEVICE_OBJECT DeviceObject);
|
IN PDEVICE_OBJECT DeviceObject);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
WdmAudWaveInitialize(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
ClosePin(
|
||||||
|
IN PWDMAUD_CLIENT ClientInfo,
|
||||||
|
IN ULONG FilterId,
|
||||||
|
IN ULONG PinId,
|
||||||
|
IN SOUND_DEVICE_TYPE DeviceType);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
InsertPinHandle(
|
||||||
|
IN PWDMAUD_CLIENT ClientInfo,
|
||||||
|
IN ULONG FilterId,
|
||||||
|
IN ULONG PinId,
|
||||||
|
IN SOUND_DEVICE_TYPE DeviceType,
|
||||||
|
IN HANDLE PinHandle,
|
||||||
|
IN ULONG FreeIndex);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,9 +7,12 @@
|
||||||
<library>ntoskrnl</library>
|
<library>ntoskrnl</library>
|
||||||
<library>ks</library>
|
<library>ks</library>
|
||||||
<library>pseh</library>
|
<library>pseh</library>
|
||||||
|
<library>hal</library>
|
||||||
<file>control.c</file>
|
<file>control.c</file>
|
||||||
<file>deviface.c</file>
|
<file>deviface.c</file>
|
||||||
<file>entry.c</file>
|
<file>entry.c</file>
|
||||||
<file>mixer.c</file>
|
<file>mixer.c</file>
|
||||||
|
<file>wave.c</file>
|
||||||
|
<file>sup.c</file>
|
||||||
<file>wdmaud.rc</file>
|
<file>wdmaud.rc</file>
|
||||||
</module>
|
</module>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue