mirror of
https://github.com/reactos/reactos.git
synced 2025-04-25 16:10:29 +00:00
- 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:
parent
acdae19a65
commit
0a23e307a1
11 changed files with 566 additions and 48 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue