- 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:
Johannes Anderwald 2009-10-02 10:57:24 +00:00
parent 2f541881a8
commit 347609e691
7 changed files with 1503 additions and 765 deletions

View file

@ -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 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
WdmAudControlOpen(
@ -135,174 +27,17 @@ WdmAudControlOpen(
IN PWDMAUD_DEVICE_INFO DeviceInfo,
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)
{
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 SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
return WdmAudControlOpenWave(DeviceObject, Irp, DeviceInfo, ClientInfo);
}
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);
}
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));
return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
}
NTSTATUS
@ -312,85 +47,23 @@ WdmAudControlDeviceType(
IN PWDMAUD_DEVICE_INFO DeviceInfo,
IN PWDMAUD_CLIENT ClientInfo)
{
KSP_PIN Pin;
ULONG Count, BytesReturned, Index, SubIndex, Result, NumPins;
ULONG Result = 0;
NTSTATUS Status;
KSPIN_COMMUNICATION Communication;
KSPIN_DATAFLOW DataFlow;
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
{
DeviceInfo->DeviceCount = DeviceExtension->MixerInfoCount;
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
Result = DeviceExtension->MixerInfoCount;
}
if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceInfo->DeviceType != WAVE_IN_DEVICE_TYPE)
else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
{
DPRINT("FIXME: Unsupported device type %x\n", DeviceInfo->DeviceType);
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++;
Result = DeviceExtension->WaveOutDeviceCount;
}
else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
{
if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
Result++;
}
}
}
Result = DeviceExtension->WaveInDeviceCount;
}
/* store result count */
@ -436,253 +109,6 @@ WdmAudControlDeviceState(
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
WdmAudCapabilities(
IN PDEVICE_OBJECT DeviceObject,
@ -692,19 +118,6 @@ WdmAudCapabilities(
{
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
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");
@ -713,115 +126,12 @@ WdmAudCapabilities(
if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
{
Status = WdmAudMixerCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
}
Status = GetFilterIdAndPinId(DeviceObject, DeviceInfo, ClientInfo, &FilterId, &PinId);
if (!NT_SUCCESS(Status))
else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
{
DPRINT1("Invalid device index provided %u\n", DeviceInfo->DeviceIndex);
return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
Status = WdmAudWaveCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
}
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));
}
@ -846,6 +156,7 @@ WdmAudIoctlClose(
return STATUS_SUCCESS;
}
}
SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO));
return STATUS_INVALID_PARAMETER;
}

View file

@ -78,6 +78,8 @@ WdmAudInstallDevice(
Status = WdmAudMixerInitialize(DeviceObject);
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_DEVICE_INITIALIZING;

View file

@ -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_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_SUM = {0xDA441A60L, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
#define DESTINATION_LINE 0xFFFF0000
@ -62,7 +63,7 @@ GetSourceMixerLineByLineId(
while(Entry != &MixerInfo->LineList)
{
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)
return MixerLineSrc;
@ -719,36 +720,260 @@ AllocatePinArray(
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
AddMixerSourceLine(
IN OUT LPMIXER_INFO MixerInfo,
IN PFILE_OBJECT FileObject,
IN PKSMULTIPLE_ITEM NodeConnections,
IN PKSMULTIPLE_ITEM NodeTypes,
IN ULONG DeviceIndex,
IN ULONG PinId)
IN ULONG PinId,
IN ULONG bBridgePin,
IN ULONG bTargetPin)
{
LPMIXERLINE_EXT SrcLine, DstLine;
NTSTATUS Status;
KSP_PIN Pin;
LPWSTR PinName;
GUID NodeType;
ULONG BytesReturned;
ULONG BytesReturned, ControlCount, Index;
PULONG Nodes;
if (!bTargetPin)
{
/* allocate src mixer line */
SrcLine = (LPMIXERLINE_EXT)ExAllocatePool(NonPagedPool, sizeof(MIXERLINE_EXT));
if (!SrcLine)
return STATUS_INSUFFICIENT_RESOURCES;
/* zero struct */
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 */
SrcLine->DeviceIndex = DeviceIndex;
SrcLine->PinId = PinId;
SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
/* get destination line */
DstLine = GetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
/* initialize mixer destination line */
SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
SrcLine->Line.dwDestination = 0;
@ -758,28 +983,106 @@ AddMixerSourceLine(
SrcLine->Line.dwUser = 0;
SrcLine->Line.cChannels = DstLine->Line.cChannels;
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 */
if (!bTargetPin)
{
ExFreePool(SrcLine);
}
return STATUS_INSUFFICIENT_RESOURCES;
}
/* clear line controls */
RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW));
/* clear nodes array */
RtlZeroMemory(Nodes, sizeof(ULONG) * NodeTypes->Count);
/* fill in pseudo mixer control */
SrcLine->LineControls->dwControlID = 1; //FIXME
SrcLine->LineControls->cbStruct = sizeof(MIXERCONTROLW);
SrcLine->LineControls->fdwControl = 0;
SrcLine->LineControls->cMultipleItems = 0;
wcscpy(SrcLine->LineControls->szName, L"test");
wcscpy(SrcLine->LineControls->szShortName, L"test");
Status = GetControlsFromPin(NodeConnections, NodeTypes, PinId, bTargetPin, Nodes);
if (!NT_SUCCESS(Status))
{
/* something went wrong */
if (!bTargetPin)
{
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 */
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 */
if (!bTargetPin)
{
InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
DstLine->Line.cConnections++;
}
return STATUS_SUCCESS;
}
@ -851,8 +1149,12 @@ NTSTATUS
AddMixerSourceLines(
IN OUT LPMIXER_INFO MixerInfo,
IN PFILE_OBJECT FileObject,
IN PKSMULTIPLE_ITEM NodeConnections,
IN PKSMULTIPLE_ITEM NodeTypes,
IN ULONG DeviceIndex,
IN ULONG PinsCount,
IN ULONG BridgePinIndex,
IN ULONG TargetPinIndex,
IN PULONG Pins)
{
ULONG Index;
@ -862,7 +1164,7 @@ AddMixerSourceLines(
{
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;
@ -987,7 +1289,7 @@ HandlePhysicalConnection(
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(PinsSrcRef);
@ -1045,10 +1347,6 @@ InitializeMixer(
if (!DestinationLine)
return STATUS_INSUFFICIENT_RESOURCES;
/* initialize mixer info */
MixerInfo->hMixer = hDevice;
MixerInfo->MixerFileObject = FileObject;
/* intialize mixer caps */
MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
@ -1083,7 +1381,6 @@ InitializeMixer(
DestinationLine->Line.dwUser = 0;
DestinationLine->Line.dwComponentType = (bInput == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
DestinationLine->Line.cChannels = 2; //FIXME
DestinationLine->Line.cControls = 0; //FIXME
wcscpy(DestinationLine->Line.szShortName, L"Summe"); //FIXME
wcscpy(DestinationLine->Line.szName, L"Summe"); //FIXME
DestinationLine->Line.Target.dwType = (bInput == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
@ -1411,6 +1708,7 @@ WdmAudGetLineControls(
{
LPMIXERLINE_EXT MixerLineSrc;
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
ULONG Index;
/* get device extension */
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
@ -1427,15 +1725,12 @@ WdmAudGetLineControls(
ASSERT(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));
}
else if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
{
DPRINT1("dwLineID %u\n",DeviceInfo->u.MixControls.dwLineID);
UNIMPLEMENTED
//HACK
if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
{
/* invalid parameter */
@ -1444,12 +1739,19 @@ WdmAudGetLineControls(
MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwLineID);
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));
}
}
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;
//DbgBreakPoint();

View 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;
}

View 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;
}

View file

@ -40,21 +40,33 @@ typedef struct
ULONG DeviceIndex;
MIXERLINEW Line;
LPMIXERCONTROLW LineControls;
PULONG NodeIds;
}MIXERLINE_EXT, *LPMIXERLINE_EXT;
typedef struct
{
HANDLE hMixer;
PFILE_OBJECT MixerFileObject;
MIXERCAPSW MixCaps;
LIST_ENTRY LineList;
ULONG ControlId;
}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
{
LIST_ENTRY Entry;
@ -77,6 +89,12 @@ typedef struct
ULONG MixerInfoCount;
LPMIXER_INFO MixerInfo;
ULONG WaveInDeviceCount;
LIST_ENTRY WaveInList;
ULONG WaveOutDeviceCount;
LIST_ENTRY WaveOutList;
}WDMAUD_DEVICE_EXTENSION, *PWDMAUD_DEVICE_EXTENSION;
@ -86,6 +104,16 @@ typedef struct
PIRP Irp;
}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
WdmAudRegisterDeviceInterface(
IN PDEVICE_OBJECT PhysicalDeviceObject,
@ -120,6 +148,14 @@ WdmAudControlOpenMixer(
IN PWDMAUD_DEVICE_INFO DeviceInfo,
IN PWDMAUD_CLIENT ClientInfo);
NTSTATUS
WdmAudControlOpenWave(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PWDMAUD_DEVICE_INFO DeviceInfo,
IN PWDMAUD_CLIENT ClientInfo);
ULONG
GetNumOfMixerDevices(
IN PDEVICE_OBJECT DeviceObject);
@ -148,6 +184,13 @@ WdmAudMixerCapabilities(
IN PWDMAUD_CLIENT ClientInfo,
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
NTAPI
WdmAudFrameSize(
@ -192,5 +235,26 @@ NTSTATUS
WdmAudMixerInitialize(
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

View file

@ -7,9 +7,12 @@
<library>ntoskrnl</library>
<library>ks</library>
<library>pseh</library>
<library>hal</library>
<file>control.c</file>
<file>deviface.c</file>
<file>entry.c</file>
<file>mixer.c</file>
<file>wave.c</file>
<file>sup.c</file>
<file>wdmaud.rc</file>
</module>