From 2babefdc4212d773d00666150e32da8f64ad2dfa Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Sun, 8 Mar 2009 16:25:28 +0000 Subject: [PATCH] - Wait for the APC in wdmaud.drv - Queue ~ one second of audio data before starting to stream - Check if an audio pin is already open and re-use it in that case svn path=/trunk/; revision=39907 --- reactos/dll/win32/wdmaud.drv/wdmaud.c | 6 +- .../wdm/audio/backpln/portcls/interfaces.h | 3 +- .../wdm/audio/backpln/portcls/irpstream.c | 77 +++++++++++---- .../audio/backpln/portcls/pin_wavecyclic.c | 52 +++++++--- .../drivers/wdm/audio/legacy/wdmaud/control.c | 6 +- reactos/drivers/wdm/audio/sysaudio/control.c | 95 +++++++++++++------ 6 files changed, 165 insertions(+), 74 deletions(-) diff --git a/reactos/dll/win32/wdmaud.drv/wdmaud.c b/reactos/dll/win32/wdmaud.drv/wdmaud.c index 6064fa61562..bb3f38660cc 100644 --- a/reactos/dll/win32/wdmaud.drv/wdmaud.c +++ b/reactos/dll/win32/wdmaud.drv/wdmaud.c @@ -309,10 +309,8 @@ WriteFileEx_Committer2( } else { - /* HACK - * The CompletionRoutine should be called by the system - */ - CompletionRoutine(0, Length, (LPOVERLAPPED)Overlap); + WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE); + } return MMSYSERR_NOERROR; diff --git a/reactos/drivers/wdm/audio/backpln/portcls/interfaces.h b/reactos/drivers/wdm/audio/backpln/portcls/interfaces.h index bb704bfe774..5accd1e1dce 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/interfaces.h +++ b/reactos/drivers/wdm/audio/backpln/portcls/interfaces.h @@ -193,6 +193,7 @@ DECLARE_INTERFACE_(IIrpQueue, IUnknown) STDMETHOD_(NTSTATUS, Init)(THIS_ IN KSPIN_CONNECT *ConnectDetails, + IN PKSDATAFORMAT DataFormat, IN PDEVICE_OBJECT DeviceObject); STDMETHOD_(NTSTATUS, AddMapping)(THIS_ @@ -211,7 +212,7 @@ DECLARE_INTERFACE_(IIrpQueue, IUnknown) STDMETHOD_(ULONG, MinMappings)(THIS); - STDMETHOD_(ULONG, MaxMappings)(THIS); + STDMETHOD_(BOOL, MinimumDataAvailable)(THIS); }; diff --git a/reactos/drivers/wdm/audio/backpln/portcls/irpstream.c b/reactos/drivers/wdm/audio/backpln/portcls/irpstream.c index 33d02092016..676f010296c 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/irpstream.c +++ b/reactos/drivers/wdm/audio/backpln/portcls/irpstream.c @@ -18,8 +18,6 @@ typedef struct _IRP_MAPPING_ struct _IRP_MAPPING_ * Next; }IRP_MAPPING, *PIRP_MAPPING; -#define MAX_MAPPING (100) - typedef struct { IIrpQueueVtbl *lpVtbl; @@ -27,9 +25,10 @@ typedef struct LONG ref; ULONG CurrentOffset; - ULONG NextMapping; LONG NumMappings; - IN KSPIN_CONNECT *ConnectDetails; + ULONG NumDataAvailable; + KSPIN_CONNECT *ConnectDetails; + PKSDATAFORMAT_WAVEFORMATEX DataFormat; KDPC Dpc; PIRP_MAPPING FirstMap; @@ -38,7 +37,7 @@ typedef struct ULONG DpcActive; PIRP_MAPPING FreeMapHead; PIRP_MAPPING FreeMapTail; - + ULONG FreeDataSize; LONG FreeCount; }IIrpQueueImpl; @@ -63,20 +62,27 @@ DpcRoutine( { NextMapping = CurMapping->Next; - CurMapping->Irp->IoStatus.Information = CurMapping->Header->DataUsed; - CurMapping->Irp->IoStatus.Status = STATUS_SUCCESS; - IoCompleteRequest(CurMapping->Irp, IO_SOUND_INCREMENT); + This->FreeDataSize -= CurMapping->Header->DataUsed; + + if (CurMapping->Irp) + { + CurMapping->Irp->IoStatus.Information = CurMapping->Header->DataUsed; + CurMapping->Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(CurMapping->Irp, IO_SOUND_INCREMENT); + } ExFreePool(CurMapping->Header->Data); ExFreePool(CurMapping->Header); + ExFreePool(CurMapping); CurMapping = NextMapping; InterlockedDecrement(&This->FreeCount); + Count++; } This->DpcActive = FALSE; - DPRINT1("Freed %u Buffers / IRP\n", Count); + DPRINT1("Freed %u Buffers / IRP Available Mappings %u\n", Count, This->NumMappings); } @@ -132,11 +138,14 @@ NTAPI IIrpQueue_fnInit( IN IIrpQueue *iface, IN KSPIN_CONNECT *ConnectDetails, + IN PKSDATAFORMAT DataFormat, IN PDEVICE_OBJECT DeviceObject) { IIrpQueueImpl * This = (IIrpQueueImpl*)iface; This->ConnectDetails = ConnectDetails; + This->DataFormat = (PKSDATAFORMAT_WAVEFORMATEX)DataFormat; + KeInitializeDpc(&This->Dpc, DpcRoutine, (PVOID)This); return STATUS_SUCCESS; @@ -161,6 +170,8 @@ IIrpQueue_fnAddMapping( Mapping->Irp = Irp; Mapping->Next = NULL; + DPRINT1("FirstMap %p LastMap %p NumMappings %u\n", This->FirstMap, This->LastMap, This->NumMappings); + if (!This->FirstMap) This->FirstMap = Mapping; else @@ -170,8 +181,16 @@ IIrpQueue_fnAddMapping( InterlockedIncrement(&This->NumMappings); - DPRINT1("IIrpQueue_fnAddMapping NumMappings %u SizeOfMapping %lu\n", This->NumMappings, Mapping->Header->DataUsed); + if (Irp) + { + Irp->IoStatus.Status = STATUS_PENDING; + Irp->IoStatus.Information = 0; + IoMarkIrpPending(Irp); + } + This->NumDataAvailable += Mapping->Header->DataUsed; + + DPRINT1("IIrpQueue_fnAddMapping NumMappings %u SizeOfMapping %lu NumDataAvailable %lu\n", This->NumMappings, Mapping->Header->DataUsed, This->NumDataAvailable); return STATUS_SUCCESS; } @@ -221,8 +240,13 @@ IIrpQueue_fnUpdateMapping( This->FreeMapTail = Mapping; Mapping->Next = NULL; + This->FreeDataSize += Mapping->Header->DataUsed; + InterlockedDecrement(&This->NumMappings); + This->NumDataAvailable -= Mapping->Header->DataUsed; - if (This->FreeCount > iface->lpVtbl->MinMappings(iface) && This->DpcActive == FALSE) + + if ((This->FreeDataSize > This->DataFormat->WaveFormatEx.nAvgBytesPerSec || This->FreeCount > 25) && + This->DpcActive == FALSE) { Mapping = This->FreeMapHead; This->FreeMapHead = NULL; @@ -243,22 +267,33 @@ IIrpQueue_fnNumMappings( return This->NumMappings; } -ULONG -NTAPI -IIrpQueue_fnMaxMappings( - IN IIrpQueue *iface) -{ - return MAX_MAPPING; -} - ULONG NTAPI IIrpQueue_fnMinMappings( IN IIrpQueue *iface) { - return MAX_MAPPING / 4; + return 25; } + +BOOL +NTAPI +IIrpQueue_fnMinimumDataAvailable( + IN IIrpQueue *iface) +{ + BOOL Result; + IIrpQueueImpl * This = (IIrpQueueImpl*)iface; + + if (This->DataFormat->WaveFormatEx.nAvgBytesPerSec < This->NumDataAvailable) + Result = TRUE; + else + Result = FALSE; + + return Result; +} + + + static IIrpQueueVtbl vt_IIrpQueue = { IIrpQueue_fnQueryInterface, @@ -270,7 +305,7 @@ static IIrpQueueVtbl vt_IIrpQueue = IIrpQueue_fnUpdateMapping, IIrpQueue_fnNumMappings, IIrpQueue_fnMinMappings, - IIrpQueue_fnMaxMappings + IIrpQueue_fnMinimumDataAvailable }; diff --git a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c index fea335d70a1..2483dcac155 100644 --- a/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c +++ b/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.c @@ -27,6 +27,7 @@ typedef struct ULONG ActiveIrpOffset; ULONG DelayedRequestInProgress; ULONG RetryCount; + ULONG FrameSize; }IPortPinWaveCyclicImpl; @@ -172,16 +173,16 @@ IServiceSink_fnRequestService( IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)CONTAINING_RECORD(iface, IPortPinWaveCyclicImpl, lpVtblServiceSink); - Status = This->IrpQueue->lpVtbl->GetMapping(This->IrpQueue, &Buffer, &BufferSize); if (!NT_SUCCESS(Status)) { This->RetryCount++; if (This->RetryCount > 30) { - DPRINT1("Stopping\n"); + DPRINT1("Stopping %u\n", This->IrpQueue->lpVtbl->NumMappings(This->IrpQueue)); This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_STOP); This->RetryCount = 0; + This->State = KSSTATE_STOP; return; } DPRINT("IServiceSink_fnRequestService> Waiting for mapping\n"); @@ -380,7 +381,10 @@ IPortPinWaveCyclic_HandleKsProperty( if (This->Stream) { - Status = This->Stream->lpVtbl->SetFormat(This->Stream, DataFormat); + This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_STOP); + This->State = KSSTATE_STOP; + + Status = This->Stream->lpVtbl->SetFormat(This->Stream, NewDataFormat); if (NT_SUCCESS(Status)) { if (This->Format) @@ -646,27 +650,46 @@ IPortPinWaveCyclic_fnFastWrite( { NTSTATUS Status; PCONTEXT_WRITE Packet; + PIRP Irp; IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)iface; DPRINT1("IPortPinWaveCyclic_fnFastWrite entered\n"); Packet = (PCONTEXT_WRITE)Buffer; + //if (This->IrpQueue->lpVtbl->MinimumDataAvailable(This->IrpQueue)) + // Irp = Packet->Irp; + //else + Irp = NULL; - Status = This->IrpQueue->lpVtbl->AddMapping(This->IrpQueue, Buffer, Length, Packet->Irp); + Status = This->IrpQueue->lpVtbl->AddMapping(This->IrpQueue, Buffer, Length, Irp); if (!NT_SUCCESS(Status)) return FALSE; - if ((This->IrpQueue->lpVtbl->NumMappings(This->IrpQueue) > This->IrpQueue->lpVtbl->MinMappings(This->IrpQueue)) && - This->State != KSSTATE_RUN) + if (This->IrpQueue->lpVtbl->MinimumDataAvailable(This->IrpQueue) == TRUE && This->State != KSSTATE_RUN) { /* some should initiate a state request but didnt do it */ DPRINT1("Starting stream with %lu mappings\n", This->IrpQueue->lpVtbl->NumMappings(This->IrpQueue)); + This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_RUN); This->State = KSSTATE_RUN; } + if (!Irp) + { + DPRINT1("Completing Irp %p\n", Packet->Irp); + + Packet->Irp->IoStatus.Status = STATUS_SUCCESS; + Packet->Irp->IoStatus.Information = Packet->Header.DataUsed; + IoCompleteRequest(Packet->Irp, IO_SOUND_INCREMENT); + StatusBlock->Status = STATUS_SUCCESS; + } + else + { + StatusBlock->Status = STATUS_PENDING; + } + return TRUE; } @@ -697,13 +720,6 @@ IPortPinWaveCyclic_fnInit( DeviceObject = GetDeviceObject(Port); - - Status = NewIrpQueue(&This->IrpQueue); - if (!NT_SUCCESS(Status)) - return Status; - - Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, DeviceObject); - DataFormat = (PKSDATAFORMAT)(ConnectDetails + 1); DPRINT("IPortPinWaveCyclic_fnInit entered\n"); @@ -714,6 +730,12 @@ IPortPinWaveCyclic_fnInit( RtlMoveMemory(This->Format, DataFormat, DataFormat->FormatSize); + Status = NewIrpQueue(&This->IrpQueue); + if (!NT_SUCCESS(Status)) + return Status; + + Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, DataFormat, DeviceObject); + Status = This->Miniport->lpVtbl->NewStream(This->Miniport, &This->Stream, NULL, @@ -729,7 +751,7 @@ IPortPinWaveCyclic_fnInit( if (!NT_SUCCESS(Status)) return Status; - Status = This->ServiceGroup->lpVtbl->AddMember(This->ServiceGroup, + Status = This->ServiceGroup->lpVtbl->AddMember(This->ServiceGroup, (PSERVICESINK)&This->lpVtblServiceSink); if (!NT_SUCCESS(Status)) { @@ -743,6 +765,8 @@ IPortPinWaveCyclic_fnInit( This->CommonBufferSize = This->DmaChannel->lpVtbl->AllocatedBufferSize(This->DmaChannel); This->CommonBuffer = This->DmaChannel->lpVtbl->SystemAddress(This->DmaChannel); + //Status = This->Stream->lpVtbl->SetNotificationFreq(This->Stream, 10, &This->FrameSize); + return STATUS_SUCCESS; } diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/control.c b/reactos/drivers/wdm/audio/legacy/wdmaud/control.c index c3ab174f56b..24f240acd75 100644 --- a/reactos/drivers/wdm/audio/legacy/wdmaud/control.c +++ b/reactos/drivers/wdm/audio/legacy/wdmaud/control.c @@ -733,10 +733,8 @@ WdmAudWrite( KsStreamIo(FileObject, NULL, NULL, NULL, NULL, 0, &IoStatusBlock, Packet, sizeof(CONTEXT_WRITE), KSSTREAM_WRITE, KernelMode); - Irp->IoStatus.Status = STATUS_PENDING; - Irp->IoStatus.Information = 0; - IoMarkIrpPending(Irp); - return STATUS_PENDING; + + return IoStatusBlock.Status; //return SetIrpIoStatus(Irp, STATUS_SUCCESS, 0); } diff --git a/reactos/drivers/wdm/audio/sysaudio/control.c b/reactos/drivers/wdm/audio/sysaudio/control.c index 480782adfa9..d2faf0af3c9 100644 --- a/reactos/drivers/wdm/audio/sysaudio/control.c +++ b/reactos/drivers/wdm/audio/sysaudio/control.c @@ -299,7 +299,7 @@ CreatePinWorkerRoutine( else { AudioClient->Devs[AudioClient->NumDevices -1].ClientHandles[NumHandels].bHandle = FALSE; - AudioClient->Devs[AudioClient->NumDevices -1].ClientHandles[NumHandels].hPin = NULL; + AudioClient->Devs[AudioClient->NumDevices -1].ClientHandles[NumHandels].hPin = VirtualPinHandle; AudioClient->Devs[AudioClient->NumDevices -1].ClientHandles[NumHandels].PinId = WorkerContext->PinConnect->PinId; } @@ -411,6 +411,43 @@ HandleSysAudioFilterPinProperties( } } +NTSTATUS +SetPinFormat( + PKSAUDIO_DEVICE_ENTRY Entry, + KSPIN_CONNECT * PinConnect, + ULONG Length) +{ + KSP_PIN PinRequest; + PFILE_OBJECT FileObject; + ULONG BytesReturned; + NTSTATUS Status; + + /* re-using pin */ + PinRequest.Property.Set = KSPROPSETID_Connection; + PinRequest.Property.Flags = KSPROPERTY_TYPE_SET; + 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, + IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to get pin file object with %x\n", Status); + return Status; + } + + Length -= sizeof(KSPIN_CONNECT) + sizeof(SYSAUDIO_INSTANCE_INFO); + Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinRequest, sizeof(KSPROPERTY), + (PVOID)(PinConnect + 1), Length, &BytesReturned); + ObDereferenceObject(FileObject); + + return Status; +} + + NTSTATUS HandleSysAudioFilterPinCreation( PIRP Irp, @@ -429,9 +466,9 @@ HandleSysAudioFilterPinCreation( NTSTATUS Status; KSPIN_CINSTANCES PinInstances; PIO_WORKITEM WorkItem; - PFILE_OBJECT FileObject; PPIN_WORKER_CONTEXT WorkerContext; PDISPATCH_CONTEXT DispatchContext; + ULONG Index, SubIndex; IoStack = IoGetCurrentIrpStackLocation(Irp); @@ -456,8 +493,7 @@ HandleSysAudioFilterPinCreation( /* get client context */ ClientInfo = (PSYSAUDIO_CLIENT)CreateItem->Context; - if (!ClientInfo || !ClientInfo->NumDevices || !ClientInfo->Devs || - ClientInfo->Devs[ClientInfo->NumDevices-1].DeviceId != InstanceInfo->DeviceNumber) + if (!ClientInfo || !ClientInfo->NumDevices || !ClientInfo->Devs) { /* we have a problem */ KeBugCheckEx(0, 0, 0, 0, 0); @@ -506,6 +542,30 @@ HandleSysAudioFilterPinCreation( if (PinInstances.CurrentCount == PinInstances.PossibleCount) { + for (Index = 0; Index < ClientInfo->NumDevices; Index++) + { + if (ClientInfo->Devs[Index].DeviceId == InstanceInfo->DeviceNumber) + { + if (ClientInfo->Devs[Index].ClientHandlesCount) + { + for(SubIndex = 0; SubIndex < ClientInfo->Devs[Index].ClientHandlesCount; SubIndex++) + { + if (ClientInfo->Devs[Index].ClientHandles[SubIndex].PinId == PinConnect->PinId) + { + /* reuse opened pin */ + Length = IoStack->Parameters.DeviceIoControl.InputBufferLength - sizeof(KSPIN_CONNECT) + sizeof(SYSAUDIO_INSTANCE_INFO); + Status = SetPinFormat(Entry, PinConnect, Length); + DPRINT1("Reusing instance handle Status %x\n", Status); + ASSERT(ClientInfo->Devs[Index].ClientHandles[SubIndex].bHandle == FALSE); + *((PHANDLE)Irp->UserBuffer) = ClientInfo->Devs[Index].ClientHandles[SubIndex].hPin; + return SetIrpIoStatus(Irp, Status, sizeof(HANDLE)); + } + } + } + + } + } + /* pin already exists */ ASSERT(Entry->Pins[PinConnect->PinId].PinHandle != NULL); if (Entry->Pins[PinConnect->PinId].References > 1) @@ -550,39 +610,14 @@ HandleSysAudioFilterPinCreation( if (PinInstances.CurrentCount == PinInstances.PossibleCount) { /* re-using pin */ - PinRequest.Property.Set = KSPROPSETID_Connection; - PinRequest.Property.Flags = KSPROPERTY_TYPE_SET; - PinRequest.Property.Id = KSPROPERTY_CONNECTION_DATAFORMAT; - - /* get pin file object */ - Status = ObReferenceObjectByHandle(Entry->Pins[PinConnect->PinId].PinHandle, - GENERIC_READ | GENERIC_WRITE, - IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); - + Status = SetPinFormat(Entry, PinConnect, Length); if (!NT_SUCCESS(Status)) { - DPRINT1("Failed to get pin file object with %x\n", Status); IoFreeWorkItem(WorkItem); ExFreePool(WorkerContext); ExFreePool(DispatchContext); return SetIrpIoStatus(Irp, Status, 0); } - - Length -= sizeof(KSPIN_CONNECT) + sizeof(SYSAUDIO_INSTANCE_INFO); - Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinRequest, sizeof(KSPROPERTY), - (PVOID)(PinConnect + 1), Length, &BytesReturned); - - ObDereferenceObject(FileObject); - - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to set format with Status %x\n", Status); - IoFreeWorkItem(WorkItem); - ExFreePool(WorkerContext); - ExFreePool(DispatchContext); - return SetIrpIoStatus(Irp, Status, 0); - } - } else {