X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=drivers%2Fwdm%2Faudio%2Fbackpln%2Fportcls%2Fpin_wavecyclic.cpp;h=d112c7195a2ac57910144d86feadac19481c161d;hp=412c0d92e0524369ecd2cbd5a08194357148187f;hb=30d346530ebc5e3ca41bf6b5aa6ebfc94028168e;hpb=f93d9928e39320170fe5bee762a1ece633f4cf24 diff --git a/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp b/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp index 412c0d92e05..d112c7195a2 100644 --- a/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp +++ b/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp @@ -48,6 +48,7 @@ protected: friend NTSTATUS NTAPI PinWaveCyclicAddEndOfStreamEvent(IN PIRP Irp, IN PKSEVENTDATA EventData, IN PKSEVENT_ENTRY EventEntry); friend NTSTATUS NTAPI PinWaveCyclicAddLoopedStreamEvent(IN PIRP Irp, IN PKSEVENTDATA EventData, IN PKSEVENT_ENTRY EventEntry); friend VOID CALLBACK PinSetStateWorkerRoutine(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context); + friend VOID NTAPI PinWaveCyclicIoTimerRoutine(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context); IPortWaveCyclic * m_Port; IPortFilterWaveCyclic * m_Filter; @@ -69,8 +70,7 @@ protected: ULONG m_FrameSize; BOOL m_Capture; - ULONG m_TotalPackets; - ULONG m_StopCount; + ULONGLONG m_TotalPackets; KSAUDIO_POSITION m_Position; KSALLOCATOR_FRAMING m_AllocatorFraming; PSUBDEVICE_DESCRIPTOR m_Descriptor; @@ -82,6 +82,12 @@ protected: ULONG m_Delay; + ULONGLONG m_GlitchCount; + ULONGLONG m_GlitchLength; + + LARGE_INTEGER m_LastPacketTime; + BOOLEAN m_Started; + LONG m_Ref; }; @@ -106,7 +112,7 @@ NTSTATUS NTAPI PinWaveCyclicAllocatorFraming(IN PIRP Irp, IN PKSIDENTIFIER Reque NTSTATUS NTAPI PinWaveCyclicAddEndOfStreamEvent(IN PIRP Irp, IN PKSEVENTDATA EventData, IN PKSEVENT_ENTRY EventEntry); NTSTATUS NTAPI PinWaveCyclicAddLoopedStreamEvent(IN PIRP Irp, IN PKSEVENTDATA EventData, IN PKSEVENT_ENTRY EventEntry); NTSTATUS NTAPI PinWaveCyclicDRMHandler(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data); - +VOID NTAPI PinWaveCyclicIoTimerRoutine(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context); DEFINE_KSPROPERTY_CONNECTIONSET(PinWaveCyclicConnectionSet, PinWaveCyclicState, PinWaveCyclicDataFormat, PinWaveCyclicAllocatorFraming); DEFINE_KSPROPERTY_AUDIOSET(PinWaveCyclicAudioSet, PinWaveCyclicAudioPosition); @@ -175,6 +181,7 @@ KSEVENT_SET PinWaveCyclicEventSet[] = //================================================================================================================================== + NTSTATUS NTAPI CPortPinWaveCyclic::QueryInterface( @@ -201,6 +208,144 @@ CPortPinWaveCyclic::QueryInterface( return STATUS_UNSUCCESSFUL; } +typedef struct +{ + CPortPinWaveCyclic *Pin; + KSSTATE NewState; + PIO_WORKITEM WorkItem; + PIRP Irp; + +}SETPIN_CONTEXT, *PSETPIN_CONTEXT; + +VOID +CALLBACK +PinSetStateWorkerRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PVOID Context) +{ + PSETPIN_CONTEXT PinWorkContext = (PSETPIN_CONTEXT)Context; + NTSTATUS Status; + + // try set stream + Status = PinWorkContext->Pin->m_Stream->SetState(PinWorkContext->NewState); + + DPRINT1("Setting state %u %x\n", PinWorkContext->NewState, Status); + if (NT_SUCCESS(Status)) + { + // store new state + PinWorkContext->Pin->m_State = PinWorkContext->NewState; + + if (PinWorkContext->Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING && PinWorkContext->Pin->m_State == KSSTATE_STOP) + { + /* FIXME complete pending irps with successfull state */ + PinWorkContext->Pin->m_IrpQueue->CancelBuffers(); + PinWorkContext->Pin->m_Stream->Silence(PinWorkContext->Pin->m_CommonBuffer, PinWorkContext->Pin->m_CommonBufferSize); + PinWorkContext->Pin->m_IrpQueue->CancelBuffers(); + PinWorkContext->Pin->m_Position.PlayOffset = 0; + PinWorkContext->Pin->m_Position.WriteOffset = 0; + PinWorkContext->Pin->m_GlitchCount = 0; + PinWorkContext->Pin->m_GlitchLength = 0; + + // unregister the time out + PcUnregisterIoTimeout(GetDeviceObject(PinWorkContext->Pin->m_Port), PinWaveCyclicIoTimerRoutine, (PVOID)PinWorkContext->Pin); + } + else if (PinWorkContext->Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_STREAMING && PinWorkContext->Pin->m_State == KSSTATE_STOP) + { + /* FIXME complete pending irps with successfull state */ + PinWorkContext->Pin->m_IrpQueue->CancelBuffers(); + PinWorkContext->Pin->m_Stream->Silence(PinWorkContext->Pin->m_CommonBuffer, PinWorkContext->Pin->m_CommonBufferSize); + PinWorkContext->Pin->m_IrpQueue->CancelBuffers(); + PinWorkContext->Pin->m_Position.PlayOffset = 0; + PinWorkContext->Pin->m_Position.WriteOffset = 0; + PinWorkContext->Pin->m_GlitchCount = 0; + PinWorkContext->Pin->m_GlitchLength = 0; + + // unregister the time out + PcUnregisterIoTimeout(GetDeviceObject(PinWorkContext->Pin->m_Port), PinWaveCyclicIoTimerRoutine, (PVOID)PinWorkContext->Pin); + } + } + + // store result + if (PinWorkContext->Irp) + { + PinWorkContext->Irp->IoStatus.Information = sizeof(KSSTATE); + PinWorkContext->Irp->IoStatus.Status = Status; + + // complete irp + IoCompleteRequest(PinWorkContext->Irp, IO_NO_INCREMENT); + } + + // free work item + IoFreeWorkItem(PinWorkContext->WorkItem); + + // free work context + FreeItem(PinWorkContext, TAG_PORTCLASS); + +} + +VOID +NTAPI +PinWaveCyclicIoTimerRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PVOID Context) +{ + CPortPinWaveCyclic *Pin; + //PSETPIN_CONTEXT Ctx; + LARGE_INTEGER CurrentTime; + + // cast to pin impl + Pin = (CPortPinWaveCyclic*)Context; + + /* query system time */ + KeQuerySystemTime(&CurrentTime); + + /* check if the connection matches */ + if (Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_STREAMING && Pin->m_ResetState == KSRESET_END && Pin->m_State != KSSTATE_STOP && Pin->m_Started) + { + LARGE_INTEGER Diff; + + Diff.QuadPart = CurrentTime.QuadPart - Pin->m_LastPacketTime.QuadPart; + + if (Diff.QuadPart >= Int32x32To64(3000, 10000)) + { + DPRINT1("AudioThread Hang detected: Last Packet %I64u CurrentTime %I64u Diff %I64u\n", Pin->m_LastPacketTime.QuadPart, CurrentTime.QuadPart, Diff.QuadPart); +#if 0 + /* allocate pin context */ + Ctx = (PSETPIN_CONTEXT)AllocateItem(NonPagedPool, sizeof(SETPIN_CONTEXT), TAG_PORTCLASS); + + if (!Ctx) + { + /* no memory */ + return; + } + + /* initialize ctx */ + Ctx->Pin = Pin; + if (Pin->m_State == KSSTATE_RUN) + Ctx->NewState = KSSTATE_PAUSE; + else if (Pin->m_State == KSSTATE_PAUSE) + Ctx->NewState = KSSTATE_ACQUIRE; + else if (Pin->m_State == KSSTATE_ACQUIRE) + Ctx->NewState = KSSTATE_STOP; + + Ctx->WorkItem = IoAllocateWorkItem(DeviceObject); + Ctx->Irp = NULL; + + if (!Ctx->WorkItem) + { + /* no memory */ + FreeItem(Ctx, TAG_PORTCLASS); + return; + } + + /* queue the work item */ + IoQueueWorkItem(Ctx->WorkItem, PinSetStateWorkerRoutine, DelayedWorkQueue, (PVOID)Ctx); +#endif + } + } +} + + NTSTATUS NTAPI PinWaveCyclicDRMHandler( @@ -360,13 +505,13 @@ PinWaveCyclicAudioPosition( if (Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_STREAMING) { RtlMoveMemory(Data, &Pin->m_Position, sizeof(KSAUDIO_POSITION)); - DPRINT("Play %lu Record %lu\n", Pin->m_Position.PlayOffset, Pin->m_Position.WriteOffset); + DPRINT("Play %I64u Record %I64u\n", Pin->m_Position.PlayOffset, Pin->m_Position.WriteOffset); } else if (Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING) { Position->PlayOffset = Pin->m_Position.PlayOffset; Position->WriteOffset = (ULONGLONG)Pin->m_IrpQueue->GetCurrentIrpOffset(); - DPRINT("Play %lu Write %lu\n", Position->PlayOffset, Position->WriteOffset); + DPRINT("Play %I64u Write %I64u\n", Position->PlayOffset, Position->WriteOffset); } Irp->IoStatus.Information = sizeof(KSAUDIO_POSITION); @@ -377,58 +522,6 @@ PinWaveCyclicAudioPosition( return STATUS_NOT_SUPPORTED; } -typedef struct -{ - CPortPinWaveCyclic *Pin; - KSSTATE NewState; - PIO_WORKITEM WorkItem; - PIRP Irp; - -}SETPIN_CONTEXT, *PSETPIN_CONTEXT; - -VOID -CALLBACK -PinSetStateWorkerRoutine( - IN PDEVICE_OBJECT DeviceObject, - IN PVOID Context) -{ - PSETPIN_CONTEXT PinWorkContext = (PSETPIN_CONTEXT)Context; - NTSTATUS Status; - - // try set stream - Status = PinWorkContext->Pin->m_Stream->SetState(PinWorkContext->NewState); - - DPRINT1("Setting state %u %x\n", PinWorkContext->NewState, Status); - if (NT_SUCCESS(Status)) - { - // store new state - PinWorkContext->Pin->m_State = PinWorkContext->NewState; - - if (PinWorkContext->Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING && PinWorkContext->Pin->m_State == KSSTATE_STOP) - { - /* FIXME complete pending irps with successfull state */ - PinWorkContext->Pin->m_IrpQueue->CancelBuffers(); - } - //HACK - //PinWorkContext->Pin->m_IrpQueue->CancelBuffers(); - } - - // store result - PinWorkContext->Irp->IoStatus.Information = sizeof(KSSTATE); - PinWorkContext->Irp->IoStatus.Status = Status; - - // complete irp - IoCompleteRequest(PinWorkContext->Irp, IO_NO_INCREMENT); - - // free work item - IoFreeWorkItem(PinWorkContext->WorkItem); - - // free work context - FreeItem(PinWorkContext, TAG_PORTCLASS); - -} - - NTSTATUS NTAPI PinWaveCyclicState( @@ -470,20 +563,46 @@ PinWaveCyclicState( { // FIXME // complete with successful state + DPRINT1("BytesPlayed %I64u, GlitchCount %I64u GlitchLength %I64u\n", Pin->m_Position.PlayOffset, Pin->m_GlitchCount, Pin->m_GlitchLength); Pin->m_Stream->Silence(Pin->m_CommonBuffer, Pin->m_CommonBufferSize); Pin->m_IrpQueue->CancelBuffers(); Pin->m_Position.PlayOffset = 0; Pin->m_Position.WriteOffset = 0; + Pin->m_GlitchCount = 0; + Pin->m_GlitchLength = 0; + + + // unregister the time out + PcUnregisterIoTimeout(GetDeviceObject(Pin->m_Port), PinWaveCyclicIoTimerRoutine, (PVOID)Pin); } else if (Pin->m_State == KSSTATE_STOP) { + DPRINT1("BytesPlayed %I64u, GlitchCount %I64u GlitchLength %I64u\n", Pin->m_Position.PlayOffset, Pin->m_GlitchCount, Pin->m_GlitchLength); Pin->m_Stream->Silence(Pin->m_CommonBuffer, Pin->m_CommonBufferSize); Pin->m_IrpQueue->CancelBuffers(); Pin->m_Position.PlayOffset = 0; Pin->m_Position.WriteOffset = 0; + Pin->m_GlitchCount = 0; + Pin->m_GlitchLength = 0; + + // unregister the time out + PcUnregisterIoTimeout(GetDeviceObject(Pin->m_Port), PinWaveCyclicIoTimerRoutine, (PVOID)Pin); } // store result Irp->IoStatus.Information = sizeof(KSSTATE); + + if (*State == KSSTATE_RUN) + { + // register wave hung routine + NTSTATUS PcStatus = PcRegisterIoTimeout(GetDeviceObject(Pin->m_Port), PinWaveCyclicIoTimerRoutine, (PVOID)Pin); + if (!NT_SUCCESS(PcStatus)) + { + DPRINT1("Failed to register timer routine with %x\n", PcStatus); + } + + // set flag that stream has started for the wave hung routine + Pin->m_Started = TRUE; + } } return Status; } @@ -701,8 +820,10 @@ CPortPinWaveCyclic::UpdateCommonBuffer( Gap = Position - m_CommonBufferOffset; if (Gap > BufferLength) { + // increment glitchcount + m_GlitchCount++; + m_GlitchLength += BufferLength; // insert silence samples - DPRINT1("Inserting Silence Buffer Offset %lu GapLength %lu\n", m_CommonBufferOffset, BufferLength); m_Stream->Silence((PUCHAR)m_CommonBuffer + m_CommonBufferOffset, BufferLength); m_CommonBufferOffset += BufferLength; @@ -760,8 +881,11 @@ CPortPinWaveCyclic::UpdateCommonBufferOverlap( Gap = m_CommonBufferSize - m_CommonBufferOffset + Position; if (Gap > BufferLength) { + // increment glitchcount + m_GlitchCount++; + m_GlitchLength += BufferLength; + // insert silence samples - DPRINT1("Overlap Inserting Silence Buffer Size %lu Offset %lu Gap %lu Position %lu\n", m_CommonBufferSize, m_CommonBufferOffset, Gap, Position); m_Stream->Silence((PUCHAR)m_CommonBuffer + m_CommonBufferOffset, BufferLength); m_CommonBufferOffset += BufferLength; @@ -933,6 +1057,8 @@ CPortPinWaveCyclic::DeviceIoControl( { m_Position.WriteOffset += Data; Status = STATUS_PENDING; + /* time stamp last packet */ + KeQuerySystemTime(&m_LastPacketTime); } } else @@ -1034,6 +1160,9 @@ CPortPinWaveCyclic::Close( DPRINT("Warning: failed to stop stream with %x\n", Status); PC_ASSERT(0); } + + // unregister the time out + PcUnregisterIoTimeout(GetDeviceObject(m_Port), PinWaveCyclicIoTimerRoutine, (PVOID)this); } // set state to stop m_State = KSSTATE_STOP; @@ -1269,7 +1398,7 @@ CPortPinWaveCyclic::Init( Status = m_ServiceGroup->AddMember(PSERVICESINK(this)); if (!NT_SUCCESS(Status)) { - DPRINT("Failed to add pin to service group\n"); + DPRINT1("Failed to add pin to service group\n"); return Status; }