diff --git a/reactos/boot/bootdata/packages/reactos.dff b/reactos/boot/bootdata/packages/reactos.dff index 62146e3767f..777c4246c37 100644 --- a/reactos/boot/bootdata/packages/reactos.dff +++ b/reactos/boot/bootdata/packages/reactos.dff @@ -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 diff --git a/reactos/drivers/wdm/audio/backpln/portcls/irpstream.c b/reactos/drivers/wdm/audio/backpln/portcls/irpstream.c index b725fb16653..035fc330587 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/irpstream.c +++ b/reactos/drivers/wdm/audio/backpln/portcls/irpstream.c @@ -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); } diff --git a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c index 676c1054734..9e3e55768f0 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c +++ b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c @@ -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; } diff --git a/reactos/drivers/wdm/audio/filters/kmixer/pin.c b/reactos/drivers/wdm/audio/filters/kmixer/pin.c index b3498f05912..5932c4c6de3 100644 --- a/reactos/drivers/wdm/audio/filters/kmixer/pin.c +++ b/reactos/drivers/wdm/audio/filters/kmixer/pin.c @@ -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 = diff --git a/reactos/drivers/wdm/audio/sysaudio/control.c b/reactos/drivers/wdm/audio/sysaudio/control.c index d2faf0af3c9..c47ce8abc58 100644 --- a/reactos/drivers/wdm/audio/sysaudio/control.c +++ b/reactos/drivers/wdm/audio/sysaudio/control.c @@ -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 */ diff --git a/reactos/drivers/wdm/audio/sysaudio/deviface.c b/reactos/drivers/wdm/audio/sysaudio/deviface.c index 72d653c451e..154a7b6c1b1 100644 --- a/reactos/drivers/wdm/audio/sysaudio/deviface.c +++ b/reactos/drivers/wdm/audio/sysaudio/deviface.c @@ -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); diff --git a/reactos/drivers/wdm/audio/sysaudio/dispatcher.c b/reactos/drivers/wdm/audio/sysaudio/dispatcher.c index d11afab256a..f3422850442 100644 --- a/reactos/drivers/wdm/audio/sysaudio/dispatcher.c +++ b/reactos/drivers/wdm/audio/sysaudio/dispatcher.c @@ -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; +} diff --git a/reactos/drivers/wdm/audio/sysaudio/main.c b/reactos/drivers/wdm/audio/sysaudio/main.c index a61bf080c74..a5f30576c3a 100644 --- a/reactos/drivers/wdm/audio/sysaudio/main.c +++ b/reactos/drivers/wdm/audio/sysaudio/main.c @@ -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 */ diff --git a/reactos/drivers/wdm/audio/sysaudio/pin.c b/reactos/drivers/wdm/audio/sysaudio/pin.c index 88bb5cf18e3..6c60e1eceee 100644 --- a/reactos/drivers/wdm/audio/sysaudio/pin.c +++ b/reactos/drivers/wdm/audio/sysaudio/pin.c @@ -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; diff --git a/reactos/drivers/wdm/audio/sysaudio/sysaudio.h b/reactos/drivers/wdm/audio/sysaudio/sysaudio.h index e4bc6fb0c0d..da1ee28ab5f 100644 --- a/reactos/drivers/wdm/audio/sysaudio/sysaudio.h +++ b/reactos/drivers/wdm/audio/sysaudio/sysaudio.h @@ -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, diff --git a/reactos/media/inf/audio.inf b/reactos/media/inf/audio.inf index a7a9f05891d..dcebf878ec6 100644 --- a/reactos/media/inf/audio.inf +++ b/reactos/media/inf/audio.inf @@ -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