- 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
This commit is contained in:
Johannes Anderwald
2009-03-08 16:25:28 +00:00
parent 74c6572ab1
commit 2babefdc42
6 changed files with 165 additions and 74 deletions
+2 -4
View File
@@ -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;
@@ -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);
};
@@ -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
};
@@ -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;
}
@@ -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);
}
+65 -30
View File
@@ -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
{