- Add kmixer to bootcd

- Check if device supports a specified format. When the device doesnt support a format, query its datarange and create a format which it supports and create a kmixer pin which is used to convert the format
- Load kmixer.sys when sysaudio starts
- Call kmixer when there is work to do. 
- Bitrate increasing / decreasing is not working at all. (Need to find a working algorithm, volunteers?)
- Install kmixer service when an audio adapter is installed

svn path=/trunk/; revision=39946
This commit is contained in:
Johannes Anderwald 2009-03-11 09:30:33 +00:00
parent acdae19a65
commit 0a23e307a1
11 changed files with 566 additions and 48 deletions

View file

@ -474,6 +474,7 @@ drivers\video\miniport\vga\vgamp.sys 2
drivers\video\miniport\vbe\vbemp.sys 2
drivers\video\videoprt\videoprt.sys 2
drivers\wdm\audio\filters\kmixer\kmixer.sys 2
drivers\wdm\audio\sysaudio\sysaudio.sys 2
drivers\wdm\audio\legacy\wdmaud\wdmaud.sys 2
drivers\wdm\audio\backpln\portcls\portcls.sys 2

View file

@ -66,7 +66,7 @@ DpcRoutine(
if (CurMapping->Irp)
{
CurMapping->Irp->IoStatus.Information = CurMapping->Header->DataUsed;
CurMapping->Irp->IoStatus.Information = CurMapping->Header->FrameExtent;
CurMapping->Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(CurMapping->Irp, IO_SOUND_INCREMENT);
}

View file

@ -379,7 +379,9 @@ IPortPinWaveCyclic_HandleKsProperty(
if (This->Stream)
{
This->IrpQueue->lpVtbl->CancelBuffers(This->IrpQueue);
while(!This->IrpQueue->lpVtbl->CancelBuffers(This->IrpQueue))
KeStallExecutionProcessor(10);
This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_STOP);
This->State = KSSTATE_STOP;
@ -680,7 +682,7 @@ IPortPinWaveCyclic_fnFastWrite(
//DPRINT1("Completing Irp %p\n", Packet->Irp);
Packet->Irp->IoStatus.Status = STATUS_SUCCESS;
Packet->Irp->IoStatus.Information = Packet->Header.DataUsed;
Packet->Irp->IoStatus.Information = Packet->Header.FrameExtent;
IoCompleteRequest(Packet->Irp, IO_SOUND_INCREMENT);
StatusBlock->Status = STATUS_SUCCESS;
}

View file

@ -8,19 +8,172 @@
#include "kmixer.h"
const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
NTSTATUS
PerformQualityConversion(
PUCHAR Buffer,
ULONG BufferLength,
ULONG OldWidth,
ULONG NewWidth,
PVOID * Result,
PULONG ResultLength)
{
ULONG Samples;
ULONG Index;
ASSERT(OldWidth != NewWidth);
/* FIXME
* This code does not work at all
*/
Samples = BufferLength / (OldWidth / 8);
DPRINT1("Samples %u BufferLength %u\n", Samples, BufferLength);
if (OldWidth == 8 && NewWidth == 16)
{
USHORT Sample;
PUSHORT BufferOut = ExAllocatePool(NonPagedPool, Samples * sizeof(USHORT));
if (!BufferOut)
return STATUS_INSUFFICIENT_RESOURCES;
for(Index = 0; Index < Samples; Index++)
{
Sample = Buffer[Index];
BufferOut[Index] = Sample * 256;
}
*Result = BufferOut;
*ResultLength = Samples * sizeof(USHORT);
DPRINT1("done\n");
}
else if (OldWidth == 8 && NewWidth == 32)
{
PULONG BufferOut = ExAllocatePool(NonPagedPool, Samples * sizeof(ULONG));
if (!BufferOut)
return STATUS_INSUFFICIENT_RESOURCES;
for(Index = 0; Index < Samples; Index++)
{
BufferOut[Index] = Buffer[Index] * 16777216;
}
*Result = BufferOut;
*ResultLength = Samples * sizeof(ULONG);
}
else if (OldWidth == 16 && NewWidth == 32)
{
PULONG BufferOut = ExAllocatePool(NonPagedPool, Samples * sizeof(ULONG));
if (!BufferOut)
return STATUS_INSUFFICIENT_RESOURCES;
for(Index = 0; Index < Samples; Index++)
{
BufferOut[Index] = Buffer[Index] * 65536;
}
*Result = BufferOut;
*ResultLength = Samples * sizeof(ULONG);
}
else if (OldWidth == 16 && NewWidth == 8)
{
PUCHAR BufferOut = ExAllocatePool(NonPagedPool, Samples * sizeof(UCHAR));
if (!BufferOut)
return STATUS_INSUFFICIENT_RESOURCES;
for(Index = 0; Index < Samples; Index++)
{
BufferOut[Index] = (Buffer[Index] / 256) & 0xFF;
}
*Result = BufferOut;
*ResultLength = Samples * sizeof(UCHAR);
}
else if (OldWidth == 32 && NewWidth == 8)
{
PUCHAR BufferOut = ExAllocatePool(NonPagedPool, Samples * sizeof(UCHAR));
if (!BufferOut)
return STATUS_INSUFFICIENT_RESOURCES;
for(Index = 0; Index < Samples; Index++)
{
BufferOut[Index] = (Buffer[Index] / 16777216) & 0xFF;
}
*Result = BufferOut;
*ResultLength = Samples * sizeof(UCHAR);
}
else if (OldWidth == 32 && NewWidth == 16)
{
PUSHORT BufferOut = ExAllocatePool(NonPagedPool, Samples * sizeof(USHORT));
if (!BufferOut)
return STATUS_INSUFFICIENT_RESOURCES;
for(Index = 0; Index < Samples; Index++)
{
BufferOut[Index] = (Buffer[Index] / 65536) & 0xFFFF;
}
*Result = BufferOut;
*ResultLength = Samples * sizeof(USHORT);
}
else
{
DPRINT1("Not implemented conversion OldWidth %u NewWidth %u\n", OldWidth, NewWidth);
return STATUS_NOT_IMPLEMENTED;
}
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
Pin_fnDeviceIoControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PKSPROPERTY Property;
DPRINT1("Pin_fnDeviceIoControl called DeviceObject %p Irp %p\n", DeviceObject);
//TODO
// silverblade
// Perform Sample Rate Conversion
// Stream Mixing
// Up/down sampling
IoStack = IoGetCurrentIrpStackLocation(Irp);
if (IoStack->Parameters.DeviceIoControl.InputBufferLength == sizeof(KSPROPERTY) && IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(KSDATAFORMAT_WAVEFORMATEX))
{
Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
if (IsEqualGUIDAligned(&Property->Set, &KSPROPSETID_Connection))
{
if (Property->Id == KSPROPERTY_CONNECTION_DATAFORMAT && Property->Flags == KSPROPERTY_TYPE_SET)
{
PKSDATAFORMAT_WAVEFORMATEX WaveFormat2;
PKSDATAFORMAT_WAVEFORMATEX WaveFormat = ExAllocatePool(NonPagedPool, sizeof(KSDATAFORMAT_WAVEFORMATEX));
if (!WaveFormat)
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_NO_MEMORY;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NO_MEMORY;
}
if (IoStack->FileObject->FsContext2)
{
ExFreePool(IoStack->FileObject->FsContext2);
}
WaveFormat2 = (PKSDATAFORMAT_WAVEFORMATEX)Irp->UserBuffer;
WaveFormat->WaveFormatEx.nChannels = WaveFormat2->WaveFormatEx.nChannels;
WaveFormat->WaveFormatEx.nSamplesPerSec = WaveFormat2->WaveFormatEx.nSamplesPerSec;
WaveFormat->WaveFormatEx.wBitsPerSample = WaveFormat2->WaveFormatEx.wBitsPerSample;
IoStack->FileObject->FsContext2 = (PVOID)WaveFormat;
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
}
}
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
@ -179,9 +332,73 @@ Pin_fnFastWrite(
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject)
{
PKSPIN_CONNECT ConnectDetails;
PKSSTREAM_HEADER StreamHeader;
PVOID BufferOut;
ULONG BufferLength;
NTSTATUS Status = STATUS_SUCCESS;
LPWSTR PinName = L"{146F1A80-4791-11D0-A5D6-28DB04C10000}\\";
PKSDATAFORMAT_WAVEFORMATEX BaseFormat, TransformedFormat;
DPRINT1("Pin_fnFastWrite called DeviceObject %p Irp %p\n", DeviceObject);
return FALSE;
BaseFormat = (PKSDATAFORMAT_WAVEFORMATEX)FileObject->FsContext2;
if (!BaseFormat)
{
DPRINT1("Expected DataFormat\n");
DbgBreakPoint();
IoStatus->Status = STATUS_UNSUCCESSFUL;
IoStatus->Information = 0;
return FALSE;
}
if (FileObject->FileName.Length < wcslen(PinName) + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT))
{
DPRINT1("Expected DataFormat\n");
DbgBreakPoint();
IoStatus->Status = STATUS_INVALID_PARAMETER;
IoStatus->Information = 0;
return FALSE;
}
ConnectDetails = (PKSPIN_CONNECT)(FileObject->FileName.Buffer + wcslen(PinName));
TransformedFormat = (PKSDATAFORMAT_WAVEFORMATEX)(ConnectDetails + 1);
StreamHeader = (PKSSTREAM_HEADER)Buffer;
DPRINT1("Num Channels %u Old Channels %u\n SampleRate %u Old SampleRate %u\n BitsPerSample %u Old BitsPerSample %u\n",
BaseFormat->WaveFormatEx.nChannels, TransformedFormat->WaveFormatEx.nChannels,
BaseFormat->WaveFormatEx.nSamplesPerSec, TransformedFormat->WaveFormatEx.nSamplesPerSec,
BaseFormat->WaveFormatEx.wBitsPerSample, TransformedFormat->WaveFormatEx.wBitsPerSample);
if (BaseFormat->WaveFormatEx.wBitsPerSample != TransformedFormat->WaveFormatEx.wBitsPerSample)
{
Status = PerformQualityConversion(StreamHeader->Data,
StreamHeader->DataUsed,
BaseFormat->WaveFormatEx.wBitsPerSample,
TransformedFormat->WaveFormatEx.wBitsPerSample,
&BufferOut,
&BufferLength);
if (NT_SUCCESS(Status))
{
DPRINT1("Old BufferSize %u NewBufferSize %u\n", StreamHeader->DataUsed, BufferLength);
ExFreePool(StreamHeader->Data);
StreamHeader->Data = BufferOut;
StreamHeader->DataUsed = BufferLength;
}
}
if (BaseFormat->WaveFormatEx.nSamplesPerSec != TransformedFormat->WaveFormatEx.nSamplesPerSec)
{
/* sample format conversion must be done in a deferred routine */
return FALSE;
}
if (NT_SUCCESS(Status))
return TRUE;
else
return TRUE;
}
static KSDISPATCH_TABLE PinTable =

View file

@ -21,7 +21,9 @@ const GUID KSPROPSETID_Sysaudio_Pin = {0xA3A53220L, 0xC6E4, 0x11D0,
const GUID KSPROPSETID_General = {0x1464EDA5L, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
const GUID KSPROPSETID_Pin = {0x8C134960L, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
const GUID KSDATAFORMAT_TYPE_AUDIO = {0x73647561L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
NTSTATUS
SetIrpIoStatus(
@ -145,14 +147,19 @@ CreatePinWorkerRoutine(
{
NTSTATUS Status;
PSYSAUDIO_CLIENT AudioClient;
HANDLE RealPinHandle, VirtualPinHandle;
HANDLE RealPinHandle, VirtualPinHandle, MixerPinHandle = NULL;
HANDLE Filter;
ULONG NumHandels;
PFILE_OBJECT FileObject;
ULONG NumHandels, BytesReturned;
PFILE_OBJECT FileObject, MixerFileObject = NULL;
PSYSAUDIO_PIN_HANDLE ClientPinHandle;
PPIN_WORKER_CONTEXT WorkerContext = (PPIN_WORKER_CONTEXT)Context;
PKSPIN_CONNECT PinConnect = NULL;
KSPROPERTY PinRequest;
PKSDATAFORMAT_WAVEFORMATEX ClientFormat;
Filter = WorkerContext->PinConnect->PinToHandle;
WorkerContext->PinConnect->PinToHandle = NULL;
DPRINT1("CreatePinWorkerRoutine entered\n");
@ -162,11 +169,78 @@ CreatePinWorkerRoutine(
ASSERT(WorkerContext->Entry->Pins);
ASSERT(WorkerContext->Entry->NumberOfPins > WorkerContext->PinConnect->PinId);
PinConnect = WorkerContext->PinConnect;
ClientFormat = (PKSDATAFORMAT_WAVEFORMATEX)(PinConnect + 1);
if (WorkerContext->CreateMixerPin)
{
PinConnect = ExAllocatePool(NonPagedPool, sizeof(KSPIN_CONNECT) + WorkerContext->MixerFormat->DataFormat.FormatSize);
if (!PinConnect)
{
/* no memory */
SetIrpIoStatus(WorkerContext->Irp, STATUS_NO_MEMORY, 0);
ExFreePool(WorkerContext->DispatchContext);
ExFreePool(WorkerContext->MixerFormat);
ExFreePool(WorkerContext);
return;
}
RtlMoveMemory(PinConnect, WorkerContext->PinConnect, sizeof(KSPIN_CONNECT));
RtlMoveMemory((PinConnect + 1), WorkerContext->MixerFormat, WorkerContext->MixerFormat->DataFormat.FormatSize);
Status = KsCreatePin(WorkerContext->DeviceExtension->KMixerHandle, PinConnect, GENERIC_READ | GENERIC_WRITE, &MixerPinHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create Mixer Pin with %x\n", Status);
SetIrpIoStatus(WorkerContext->Irp, STATUS_UNSUCCESSFUL, 0);
ExFreePool(WorkerContext->DispatchContext);
ExFreePool(WorkerContext);
return;
}
Status = ObReferenceObjectByHandle(MixerPinHandle,
GENERIC_READ | GENERIC_WRITE,
IoFileObjectType, KernelMode, (PVOID*)&MixerFileObject, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to get file object with %x\n", Status);
SetIrpIoStatus(WorkerContext->Irp, STATUS_UNSUCCESSFUL, 0);
ExFreePool(WorkerContext->DispatchContext);
ExFreePool(WorkerContext);
return;
}
WorkerContext->DispatchContext->hMixerPin = MixerPinHandle;
WorkerContext->DispatchContext->MixerFileObject = MixerFileObject;
PinRequest.Set = KSPROPSETID_Connection;
PinRequest.Flags = KSPROPERTY_TYPE_SET;
PinRequest.Id = KSPROPERTY_CONNECTION_DATAFORMAT;
DPRINT1("ClientFormat %p Channels %u Samples %u Bits %u\n", ClientFormat, ClientFormat->WaveFormatEx.nChannels, ClientFormat->WaveFormatEx.nSamplesPerSec, ClientFormat->WaveFormatEx.wBitsPerSample);
Status = KsSynchronousIoControlDevice(MixerFileObject, KernelMode, IOCTL_KS_PROPERTY,
(PVOID)&PinRequest,
sizeof(KSPROPERTY),
(PVOID)ClientFormat,
sizeof(KSDATAFORMAT_WAVEFORMATEX),
&BytesReturned);
}
if (WorkerContext->CreateRealPin)
{
/* create the real pin */
DPRINT("Creating real pin\n");
Status = KsCreatePin(WorkerContext->Entry->Handle, WorkerContext->PinConnect, GENERIC_READ | GENERIC_WRITE, &RealPinHandle);
if (WorkerContext->CreateMixerPin)
Status = KsCreatePin(WorkerContext->Entry->Handle, PinConnect, GENERIC_READ | GENERIC_WRITE, &RealPinHandle);
else
Status = KsCreatePin(WorkerContext->Entry->Handle, WorkerContext->PinConnect, GENERIC_READ | GENERIC_WRITE, &RealPinHandle);
DPRINT1("Status %x\n", Status);
if (!NT_SUCCESS(Status))
{
@ -295,12 +369,15 @@ CreatePinWorkerRoutine(
AudioClient->Devs[AudioClient->NumDevices -1].ClientHandles[NumHandels].bHandle = TRUE;
AudioClient->Devs[AudioClient->NumDevices -1].ClientHandles[NumHandels].hPin = RealPinHandle;
AudioClient->Devs[AudioClient->NumDevices -1].ClientHandles[NumHandels].PinId = WorkerContext->PinConnect->PinId;
AudioClient->Devs[AudioClient->NumDevices -1].ClientHandles[NumHandels].hMixer = MixerPinHandle;
}
else
{
AudioClient->Devs[AudioClient->NumDevices -1].ClientHandles[NumHandels].bHandle = FALSE;
AudioClient->Devs[AudioClient->NumDevices -1].ClientHandles[NumHandels].hPin = VirtualPinHandle;
AudioClient->Devs[AudioClient->NumDevices -1].ClientHandles[NumHandels].PinId = WorkerContext->PinConnect->PinId;
AudioClient->Devs[AudioClient->NumDevices -1].ClientHandles[NumHandels].hMixer = MixerPinHandle;
}
/// increase reference count
@ -428,6 +505,7 @@ SetPinFormat(
PinRequest.Property.Id = KSPROPERTY_CONNECTION_DATAFORMAT;
PinRequest.PinId = PinConnect->PinId;
/* get pin file object */
Status = ObReferenceObjectByHandle(Entry->Pins[PinConnect->PinId].PinHandle,
GENERIC_READ | GENERIC_WRITE,
@ -444,6 +522,13 @@ SetPinFormat(
(PVOID)(PinConnect + 1), Length, &BytesReturned);
ObDereferenceObject(FileObject);
if (!NT_SUCCESS(Status))
{
/* set the format on the mixer pin */
UNIMPLEMENTED
return STATUS_SUCCESS;
}
return Status;
}
@ -469,6 +554,11 @@ HandleSysAudioFilterPinCreation(
PPIN_WORKER_CONTEXT WorkerContext;
PDISPATCH_CONTEXT DispatchContext;
ULONG Index, SubIndex;
BOOL CreateMixerPin;
PKSDATARANGE_AUDIO AudioRange;
PKSDATAFORMAT_WAVEFORMATEX MixerFormat = NULL, ClientFormat;
PKSMULTIPLE_ITEM MultipleItem;
IoStack = IoGetCurrentIrpStackLocation(Irp);
@ -522,6 +612,113 @@ HandleSysAudioFilterPinCreation(
return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
}
/* check the format */
PinRequest.PinId = PinConnect->PinId;
PinRequest.Property.Set = KSPROPSETID_Pin;
PinRequest.Property.Flags = KSPROPERTY_TYPE_SET;
PinRequest.Property.Id = KSPROPERTY_PIN_PROPOSEDATAFORMAT;
CreateMixerPin = FALSE;
BytesReturned = IoStack->Parameters.DeviceIoControl.InputBufferLength - sizeof(KSPIN_CONNECT) - sizeof(SYSAUDIO_INSTANCE_INFO);
if (BytesReturned != sizeof(KSDATAFORMAT_WAVEFORMATEX))
{
UNIMPLEMENTED
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
}
ClientFormat = (PKSDATAFORMAT_WAVEFORMATEX)(PinConnect + 1);
Status = KsSynchronousIoControlDevice(Entry->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinRequest, sizeof(KSP_PIN), (PVOID)ClientFormat, BytesReturned, &BytesReturned);
if (!NT_SUCCESS(Status))
{
//DPRINT("Property Request KSPROPERTY_PIN_PROPOSEDATAFORMAT failed with %x\n", Status);
if (!DeviceExtension->KMixerHandle || !DeviceExtension->KMixerFileObject)
{
DPRINT1("KMixer is not available\n");
DbgBreakPoint();
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
}
PinRequest.PinId = PinConnect->PinId;
PinRequest.Property.Set = KSPROPSETID_Pin;
PinRequest.Property.Flags = KSPROPERTY_TYPE_GET;
PinRequest.Property.Id = KSPROPERTY_PIN_DATARANGES;
Status = KsSynchronousIoControlDevice(Entry->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinRequest, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
if (Status != STATUS_BUFFER_TOO_SMALL)
{
DPRINT1("Property Request KSPROPERTY_PIN_DATARANGES failed with %x\n", Status);
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
}
MultipleItem = ExAllocatePool(NonPagedPool, BytesReturned);
if (!MultipleItem)
{
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
}
MixerFormat = ExAllocatePool(NonPagedPool, sizeof(KSDATAFORMAT_WAVEFORMATEX));
if (!MixerFormat)
{
ExFreePool(MultipleItem);
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
}
Status = KsSynchronousIoControlDevice(Entry->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinRequest, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
if (!NT_SUCCESS(Status))
{
DPRINT("Property Request KSPROPERTY_PIN_DATARANGES failed with %x\n", Status);
ExFreePool(MixerFormat);
ExFreePool(MultipleItem);
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
}
CreateMixerPin = FALSE;
AudioRange = (PKSDATARANGE_AUDIO)(MultipleItem + 1);
for(Index = 0; Index < MultipleItem->Count; Index++)
{
if (AudioRange->DataRange.FormatSize != sizeof(KSDATARANGE_AUDIO))
{
UNIMPLEMENTED
AudioRange = (PKSDATARANGE_AUDIO)((PUCHAR)AudioRange + AudioRange->DataRange.FormatSize);
}
MixerFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
MixerFormat->DataFormat.Flags = 0;
MixerFormat->DataFormat.Reserved = 0;
MixerFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
MixerFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
MixerFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
MixerFormat->DataFormat.SampleSize = 4;
MixerFormat->WaveFormatEx.wFormatTag = ClientFormat->WaveFormatEx.wFormatTag;
MixerFormat->WaveFormatEx.nChannels = min(AudioRange->MaximumChannels, ClientFormat->WaveFormatEx.nChannels);
MixerFormat->WaveFormatEx.nSamplesPerSec = max(AudioRange->MinimumSampleFrequency, min(AudioRange->MaximumSampleFrequency, ClientFormat->WaveFormatEx.nSamplesPerSec));
MixerFormat->WaveFormatEx.wBitsPerSample = max(AudioRange->MinimumBitsPerSample, min(AudioRange->MaximumBitsPerSample, ClientFormat->WaveFormatEx.wBitsPerSample));
MixerFormat->WaveFormatEx.cbSize = 0;
MixerFormat->WaveFormatEx.nBlockAlign = (MixerFormat->WaveFormatEx.nChannels * MixerFormat->WaveFormatEx.wBitsPerSample) / 8;
MixerFormat->WaveFormatEx.nAvgBytesPerSec = MixerFormat->WaveFormatEx.nChannels * MixerFormat->WaveFormatEx.nSamplesPerSec * (MixerFormat->WaveFormatEx.wBitsPerSample / 8);
CreateMixerPin = TRUE;
break;
AudioRange = (PKSDATARANGE_AUDIO)((PUCHAR)AudioRange + AudioRange->DataRange.FormatSize);
}
ExFreePool(MultipleItem);
if (!CreateMixerPin)
{
ExFreePool(MixerFormat);
DPRINT1("No Format found :(\n");
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
}
#if 0
DPRINT1("\nNum Channels %u Old Channels %u\n SampleRate %u Old SampleRate %u\n BitsPerSample %u Old BitsPerSample %u\n ClientFormat %p",
MixerFormat->WaveFormatEx.nChannels, ClientFormat->WaveFormatEx.nChannels,
MixerFormat->WaveFormatEx.nSamplesPerSec, ClientFormat->WaveFormatEx.nSamplesPerSec,
MixerFormat->WaveFormatEx.wBitsPerSample, ClientFormat->WaveFormatEx.wBitsPerSample, ClientFormat);
#endif
}
/* get the instances count */
PinRequest.PinId = PinConnect->PinId;
PinRequest.Property.Set = KSPROPSETID_Pin;
PinRequest.Property.Flags = KSPROPERTY_TYPE_GET;
@ -531,12 +728,16 @@ HandleSysAudioFilterPinCreation(
if (!NT_SUCCESS(Status))
{
DPRINT("Property Request KSPROPERTY_PIN_GLOBALCINSTANCES failed with %x\n", Status);
if (MixerFormat)
ExFreePool(MixerFormat);
return SetIrpIoStatus(Irp, Status, 0);
}
if (PinInstances.PossibleCount == 0)
{
/* caller wanted to open an instance-less pin */
if (MixerFormat)
ExFreePool(MixerFormat);
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
}
@ -572,6 +773,8 @@ HandleSysAudioFilterPinCreation(
{
/* FIXME need ksmixer */
DPRINT1("Device %u Pin %u References %u is already occupied, try later\n", InstanceInfo->DeviceNumber, PinConnect->PinId, Entry->Pins[PinConnect->PinId].References);
if (MixerFormat)
ExFreePool(MixerFormat);
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
}
}
@ -579,6 +782,8 @@ HandleSysAudioFilterPinCreation(
WorkItem = IoAllocateWorkItem(DeviceObject);
if (!WorkItem)
{
if (MixerFormat)
ExFreePool(MixerFormat);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
@ -590,6 +795,8 @@ HandleSysAudioFilterPinCreation(
if (!WorkerContext)
{
/* invalid parameters */
if (MixerFormat)
ExFreePool(MixerFormat);
IoFreeWorkItem(WorkItem);
return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
}
@ -599,6 +806,8 @@ HandleSysAudioFilterPinCreation(
if (!DispatchContext)
{
/* invalid parameters */
if (MixerFormat)
ExFreePool(MixerFormat);
IoFreeWorkItem(WorkItem);
ExFreePool(WorkerContext);
return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
@ -613,6 +822,8 @@ HandleSysAudioFilterPinCreation(
Status = SetPinFormat(Entry, PinConnect, Length);
if (!NT_SUCCESS(Status))
{
if (MixerFormat)
ExFreePool(MixerFormat);
IoFreeWorkItem(WorkItem);
ExFreePool(WorkerContext);
ExFreePool(DispatchContext);
@ -632,6 +843,9 @@ HandleSysAudioFilterPinCreation(
WorkerContext->Irp = Irp;
WorkerContext->PinConnect = PinConnect;
WorkerContext->AudioClient = ClientInfo;
WorkerContext->CreateMixerPin = CreateMixerPin;
WorkerContext->DeviceExtension = DeviceExtension;
WorkerContext->MixerFormat = MixerFormat;
DPRINT("Queing Irp %p\n", Irp);
/* queue the work item */

View file

@ -106,8 +106,51 @@ FilterPinWorkerRoutine(
DPRINT1("Num Pins %u Num WaveIn Pins %u Name WaveOut Pins %u\n", DeviceEntry->NumberOfPins, DeviceEntry->NumWaveInPin, DeviceEntry->NumWaveOutPin);
}
NTSTATUS
OpenDevice(
IN PUNICODE_STRING DeviceName,
IN PHANDLE HandleOut,
IN PFILE_OBJECT * FileObjectOut)
{
NTSTATUS Status;
HANDLE NodeHandle;
PFILE_OBJECT FileObject;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
InitializeObjectAttributes(&ObjectAttributes, DeviceName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwCreateFile(&NodeHandle,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
0,
0,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("ZwCreateFile failed with %x\n", Status);
return Status;
}
Status = ObReferenceObjectByHandle(NodeHandle, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
if (!NT_SUCCESS(Status))
{
ZwClose(NodeHandle);
DPRINT1("ObReferenceObjectByHandle failed with %x\n", Status);
return Status;
}
*HandleOut = NodeHandle;
*FileObjectOut = FileObject;
return Status;
}
NTSTATUS
NTAPI
@ -129,11 +172,7 @@ DeviceInterfaceChangeCallback(
{
/* a new device has arrived */
PFILE_OBJECT FileObject = NULL;
PKSAUDIO_DEVICE_ENTRY DeviceEntry;
HANDLE NodeHandle;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
PIO_WORKITEM WorkItem;
DeviceEntry = ExAllocatePool(NonPagedPool, sizeof(KSAUDIO_DEVICE_ENTRY));
@ -172,21 +211,7 @@ DeviceInterfaceChangeCallback(
DPRINT1("Sym %wZ\n", &DeviceEntry->DeviceName);
InitializeObjectAttributes(&ObjectAttributes, &DeviceEntry->DeviceName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwCreateFile(&NodeHandle,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
0,
0,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
Status = OpenDevice(&DeviceEntry->DeviceName, &DeviceEntry->Handle, &DeviceEntry->FileObject);
if (!NT_SUCCESS(Status))
{
DPRINT1("ZwCreateFile failed with %x\n", Status);
@ -194,19 +219,7 @@ DeviceInterfaceChangeCallback(
return Status;
}
Status = ObReferenceObjectByHandle(NodeHandle, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
if (!NT_SUCCESS(Status))
{
ZwClose(NodeHandle);
ExFreePool(DeviceEntry);
DPRINT1("ObReferenceObjectByHandle failed with %x\n", Status);
return Status;
}
DeviceEntry->Handle = NodeHandle;
DeviceEntry->FileObject = FileObject;
DPRINT1("Successfully opened audio device %u handle %p file object %p device object %p\n", DeviceExtension->KsAudioDeviceList, NodeHandle, FileObject, FileObject->DeviceObject);
DPRINT1("Successfully opened audio device %u handle %p file object %p device object %p\n", DeviceExtension->KsAudioDeviceList, DeviceEntry->Handle, DeviceEntry->FileObject, DeviceEntry->FileObject->DeviceObject);
DeviceExtension->NumberOfKsAudioDevices++;
WorkItem = IoAllocateWorkItem(DeviceObject);

View file

@ -334,3 +334,27 @@ SysAudioAllocateDeviceHeader(
return Status;
}
NTSTATUS
SysAudioOpenKMixer(
IN SYSAUDIODEVEXT *DeviceExtension)
{
NTSTATUS Status;
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\kmixer");
UNICODE_STRING DevicePath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\kmixer");
Status = ZwLoadDriver(&DevicePath);
if (NT_SUCCESS(Status))
{
Status = OpenDevice(&DeviceName, &DeviceExtension->KMixerHandle, &DeviceExtension->KMixerFileObject);
if (!NT_SUCCESS(Status))
{
DeviceExtension->KMixerHandle = NULL;
DeviceExtension->KMixerFileObject = NULL;
}
}
DPRINT("Status %lx KMixerHandle %p KMixerFileObject %p\n", Status, DeviceExtension->KMixerHandle, DeviceExtension->KMixerFileObject);
return STATUS_SUCCESS;
}

View file

@ -140,6 +140,13 @@ SysAudio_InstallDevice(
goto cleanup;
}
Status = SysAudioOpenKMixer(DeviceExtension);
if (!NT_SUCCESS(Status))
{
DPRINT1("SysAudioOpenKMixer failed with %x\n", Status);
goto cleanup;
}
/* set io flags */
DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
/* clear initializing flag */

View file

@ -222,6 +222,18 @@ Pin_fnFastWrite(
//DPRINT1("Pin_fnFastWrite called DeviceObject %p Irp %p\n", DeviceObject);
Context = (PDISPATCH_CONTEXT)FileObject->FsContext2;
#if 1
if (Context->hMixerPin && Context->MixerFileObject)
{
Status = KsStreamIo(Context->MixerFileObject, NULL, NULL, NULL, NULL, 0, IoStatus, Buffer, Length, KSSTREAM_WRITE, KernelMode);
if (!NT_SUCCESS(Status))
{
DPRINT1("Mixing stream failed with %lx\n", Status);
return FALSE;
}
}
#endif
Status = KsStreamIo(Context->FileObject, NULL, NULL, NULL, NULL, 0, IoStatus, Buffer, Length, KSSTREAM_WRITE, KernelMode);
if (Status == STATUS_SUCCESS)
return TRUE;

View file

@ -6,6 +6,7 @@ typedef struct
BOOL bHandle;
ULONG PinId;
HANDLE hPin;
HANDLE hMixer;
}SYSAUDIO_PIN_HANDLE, *PSYSAUDIO_PIN_HANDLE;
@ -62,6 +63,10 @@ typedef struct
PVOID KsAudioNotificationEntry;
PVOID EchoCancelNotificationEntry;
KMUTEX Mutex;
PFILE_OBJECT KMixerFileObject;
HANDLE KMixerHandle;
}SYSAUDIODEVEXT, *PSYSAUDIODEVEXT;
typedef struct
@ -71,16 +76,21 @@ typedef struct
ULONG PinId;
PKSAUDIO_DEVICE_ENTRY AudioEntry;
HANDLE hMixerPin;
PFILE_OBJECT MixerFileObject;
}DISPATCH_CONTEXT, *PDISPATCH_CONTEXT;
typedef struct
{
PIRP Irp;
BOOL CreateRealPin;
BOOL CreateMixerPin;
PKSAUDIO_DEVICE_ENTRY Entry;
KSPIN_CONNECT * PinConnect;
PDISPATCH_CONTEXT DispatchContext;
PSYSAUDIO_CLIENT AudioClient;
PSYSAUDIODEVEXT DeviceExtension;
PKSDATAFORMAT_WAVEFORMATEX MixerFormat;
}PIN_WORKER_CONTEXT, *PPIN_WORKER_CONTEXT;
NTSTATUS
@ -101,6 +111,16 @@ SysAudioHandleProperty(
PDEVICE_OBJECT DeviceObject,
PIRP Irp);
NTSTATUS
SysAudioOpenKMixer(
IN SYSAUDIODEVEXT *DeviceExtension);
NTSTATUS
OpenDevice(
IN PUNICODE_STRING DeviceName,
IN PHANDLE HandleOut,
IN PFILE_OBJECT * FileObjectOut);
PKSAUDIO_DEVICE_ENTRY
GetListEntry(
IN PLIST_ENTRY Head,

View file

@ -34,14 +34,16 @@ sysaudio.sys
wdmaud.sys
portcls.sys
drmk.sys
kmixer.sys
[Audio.CopyFiles.UserMode]
wdmaud.drv
ksuser.dll
[Audio_Inst.NT.Services]
AddService = wdmaud, , wdmaud_Service_Inst
AddService = sysaudio, , sysaudio_Service_Inst
AddService = wdmaud,,wdmaud_Service_Inst
AddService = sysaudio,,sysaudio_Service_Inst
AddService = kmixer,,kmixer_Service_Inst
[wdmaud_Service_Inst]
ServiceType = 1
@ -49,6 +51,12 @@ StartType = 3
ErrorControl = 0
ServiceBinary = %12%\wdmaud.sys
[kmixer_Service_Inst]
ServiceType = 1
StartType = 3
ErrorControl = 0
ServiceBinary = %12%\kmixer.sys
[sysaudio_Service_Inst]
ServiceType = 1
StartType = 3