[AUDIO-BRINGUP]
[reactos.git] / drivers / wdm / audio / backpln / portcls / pin_wavecyclic.cpp
index 0520480..d112c71 100644 (file)
@@ -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,11 +70,10 @@ protected:
     ULONG m_FrameSize;
     BOOL m_Capture;
 
-    ULONG m_TotalPackets;
-    ULONG m_StopCount;
+    ULONGLONG m_TotalPackets;
     KSAUDIO_POSITION m_Position;
     KSALLOCATOR_FRAMING m_AllocatorFraming;
-    SUBDEVICE_DESCRIPTOR m_Descriptor;
+    PSUBDEVICE_DESCRIPTOR m_Descriptor;
 
     KSPIN_LOCK m_EventListLock;
     LIST_ENTRY m_EventList;
@@ -82,6 +82,12 @@ protected:
 
     ULONG m_Delay;
 
+    ULONGLONG m_GlitchCount;
+    ULONGLONG m_GlitchLength;
+
+    LARGE_INTEGER m_LastPacketTime;
+    BOOLEAN m_Started;
+
     LONG m_Ref;
 };
 
@@ -105,10 +111,12 @@ NTSTATUS NTAPI PinWaveCyclicAudioPosition(IN PIRP Irp, IN PKSIDENTIFIER Request,
 NTSTATUS NTAPI PinWaveCyclicAllocatorFraming(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
 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);
+DEFINE_KSPROPERTY_DRMSET(PinWaveCyclicDRMSet, PinWaveCyclicDRMHandler);
 
 KSEVENT_ITEM PinWaveCyclicConnectionEventSet =
 {
@@ -146,6 +154,13 @@ KSPROPERTY_SET PinWaveCyclicPropertySet[] =
         (const KSPROPERTY_ITEM*)&PinWaveCyclicAudioSet,
         0,
         NULL
+    },
+    {
+        &KSPROPSETID_DrmAudioStream,
+        sizeof(PinWaveCyclicDRMSet) / sizeof(KSPROPERTY_ITEM),
+        (const KSPROPERTY_ITEM*)&PinWaveCyclicDRMSet,
+        0,
+        NULL
     }
 };
 
@@ -166,6 +181,7 @@ KSEVENT_SET PinWaveCyclicEventSet[] =
 
 //==================================================================================================================================
 
+
 NTSTATUS
 NTAPI
 CPortPinWaveCyclic::QueryInterface(
@@ -192,6 +208,157 @@ 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(
+    IN PIRP Irp,
+    IN PKSIDENTIFIER Request,
+    IN OUT PVOID Data)
+{
+    DPRINT1("PinWaveCyclicDRMHandler\n");
+    ASSERT(0);
+    return STATUS_INVALID_PARAMETER;
+}
+
+
 NTSTATUS
 NTAPI
 PinWaveCyclicAddEndOfStreamEvent(
@@ -338,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);
@@ -355,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(
@@ -448,18 +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;
     }
@@ -662,6 +805,7 @@ CPortPinWaveCyclic::UpdateCommonBuffer(
     ULONG BufferLength;
     ULONG BytesToCopy;
     ULONG BufferSize;
+    ULONG Gap;
     PUCHAR Buffer;
     NTSTATUS Status;
 
@@ -672,7 +816,20 @@ CPortPinWaveCyclic::UpdateCommonBuffer(
     {
         Status = m_IrpQueue->GetMapping(&Buffer, &BufferSize);
         if (!NT_SUCCESS(Status))
-            return;
+        {
+            Gap = Position - m_CommonBufferOffset;
+            if (Gap > BufferLength)
+            {
+                // increment glitchcount
+                m_GlitchCount++;
+                m_GlitchLength += BufferLength;
+                // insert silence samples
+                m_Stream->Silence((PUCHAR)m_CommonBuffer + m_CommonBufferOffset, BufferLength);
+
+                m_CommonBufferOffset += BufferLength;
+            }
+            break;
+        }
 
         BytesToCopy = min(BufferLength, BufferSize);
 
@@ -688,7 +845,7 @@ CPortPinWaveCyclic::UpdateCommonBuffer(
         m_IrpQueue->UpdateMapping(BytesToCopy);
         m_CommonBufferOffset += BytesToCopy;
 
-        BufferLength = Position - m_CommonBufferOffset;
+        BufferLength -= BytesToCopy;
         m_Position.PlayOffset += BytesToCopy;
 
         if (m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING)
@@ -720,11 +877,25 @@ CPortPinWaveCyclic::UpdateCommonBufferOverlap(
     {
         Status = m_IrpQueue->GetMapping(&Buffer, &BufferSize);
         if (!NT_SUCCESS(Status))
-            return;
+        {
+            Gap = m_CommonBufferSize - m_CommonBufferOffset + Position;
+            if (Gap > BufferLength)
+            {
+                // increment glitchcount
+                m_GlitchCount++;
+                m_GlitchLength += BufferLength;
+
+                // insert silence samples
+                m_Stream->Silence((PUCHAR)m_CommonBuffer + m_CommonBufferOffset, BufferLength);
+
+                m_CommonBufferOffset += BufferLength;
+            }
+            break;
+        }
 
         BytesToCopy = min(BufferLength, BufferSize);
 
-        if (m_Capture) 
+        if (m_Capture)
         {
             m_DmaChannel->CopyFrom(Buffer,
                                              (PUCHAR)m_CommonBuffer + m_CommonBufferOffset,
@@ -741,7 +912,7 @@ CPortPinWaveCyclic::UpdateCommonBufferOverlap(
         m_CommonBufferOffset += BytesToCopy;
         m_Position.PlayOffset += BytesToCopy;
 
-        BufferLength = m_CommonBufferSize - m_CommonBufferOffset;
+        BufferLength -=BytesToCopy;
 
         if (m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING)
         {
@@ -751,7 +922,6 @@ CPortPinWaveCyclic::UpdateCommonBufferOverlap(
                 m_Position.PlayOffset = m_Position.PlayOffset % m_Position.WriteOffset;
             }
         }
-
     }
 
     if (Gap == Length)
@@ -773,22 +943,13 @@ CPortPinWaveCyclic::RequestService()
 {
     ULONG Position;
     NTSTATUS Status;
-    PUCHAR Buffer;
-    ULONG BufferSize;
     ULONGLONG OldOffset, NewOffset;
 
     PC_ASSERT_IRQL(DISPATCH_LEVEL);
 
     if (m_State == KSSTATE_RUN)
     {
-        Status = m_IrpQueue->GetMapping(&Buffer, &BufferSize);
-        if (!NT_SUCCESS(Status))
-        {
-            return;
-        }
-
         Status = m_Stream->GetPosition(&Position);
-        DPRINT("Position %u Buffer %p BufferSize %u ActiveIrpOffset %u Capture %u\n", Position, Buffer, m_CommonBufferSize, BufferSize, m_Capture);
 
         OldOffset = m_Position.PlayOffset;
 
@@ -841,7 +1002,7 @@ CPortPinWaveCyclic::DeviceIoControl(
     if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_PROPERTY)
     {
         /* handle property with subdevice descriptor */
-        Status = PcHandlePropertyWithTable(Irp,  m_Descriptor.FilterPropertySetCount, m_Descriptor.FilterPropertySet, &m_Descriptor);
+        Status = PcHandlePropertyWithTable(Irp,  m_Descriptor->FilterPropertySetCount, m_Descriptor->FilterPropertySet, m_Descriptor);
 
         if (Status == STATUS_NOT_FOUND)
         {
@@ -854,11 +1015,11 @@ CPortPinWaveCyclic::DeviceIoControl(
     }
     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_ENABLE_EVENT)
     {
-        Status = PcHandleEnableEventWithTable(Irp, &m_Descriptor);
+        Status = PcHandleEnableEventWithTable(Irp, m_Descriptor);
     }
     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_DISABLE_EVENT)
     {
-        Status = PcHandleDisableEventWithTable(Irp, &m_Descriptor);
+        Status = PcHandleDisableEventWithTable(Irp, m_Descriptor);
     }
     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_RESET_STATE)
     {
@@ -896,6 +1057,8 @@ CPortPinWaveCyclic::DeviceIoControl(
              {
                 m_Position.WriteOffset += Data;
                 Status = STATUS_PENDING;
+                /* time stamp last packet */
+                KeQuerySystemTime(&m_LastPacketTime);
              }
          }
          else
@@ -959,28 +1122,30 @@ CPortPinWaveCyclic::Close(
     if (m_Format)
     {
         // free format
-        ExFreePool(m_Format);
+        FreeItem(m_Format, TAG_PORTCLASS);
+
+        // format is freed
         m_Format = NULL;
     }
 
     if (m_IrpQueue)
     {
-        // fixme cancel irps
-        m_IrpQueue->Release();
-    }
+        // cancel remaining irps
+        m_IrpQueue->CancelBuffers();
 
+        // release irp queue
+        m_IrpQueue->Release();
 
-    if (m_Port)
-    {
-        // release reference to port driver
-        m_Port->Release();
-        m_Port = NULL;
+        // queue is freed
+        m_IrpQueue = NULL;
     }
 
     if (m_ServiceGroup)
     {
         // remove member from service group
         m_ServiceGroup->RemoveMember(PSERVICESINK(this));
+
+        // do not release service group, it is released by the miniport object
         m_ServiceGroup = NULL;
     }
 
@@ -995,26 +1160,44 @@ 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;
 
-
         DPRINT("Closing stream at Irql %u\n", KeGetCurrentIrql());
+
         // release stream
         m_Stream->Release();
 
+        // stream is now freed
+        m_Stream = NULL;
     }
 
 
     if (m_Filter)
     {
-        // release reference to filter instance
+        // disconnect pin from filter
         m_Filter->FreePin((PPORTPINWAVECYCLIC)this);
+
+        // release filter reference
         m_Filter->Release();
+
+        // pin is done with filter
         m_Filter = NULL;
     }
 
+    if (m_Port)
+    {
+        // release reference to port driver
+        m_Port->Release();
+
+        // work is done for port
+        m_Port = NULL;
+    }
+
     Irp->IoStatus.Information = 0;
     Irp->IoStatus.Status = STATUS_SUCCESS;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
@@ -1103,7 +1286,6 @@ CPortPinWaveCyclic::Init(
     PKSDATAFORMAT DataFormat;
     PDEVICE_OBJECT DeviceObject;
     BOOLEAN Capture;
-    PVOID SilenceBuffer;
     PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor = NULL;
     //IDrmAudioStream * DrmAudio = NULL;
 
@@ -1162,7 +1344,6 @@ CPortPinWaveCyclic::Init(
 #endif
 
     DPRINT1("CPortPinWaveCyclic::Init Status %x PinId %u Capture %u\n", Status, ConnectDetails->PinId, Capture);
-    DPRINT1("Bits %u Samples %u Channels %u Tag %u FrameSize %u\n", ((PKSDATAFORMAT_WAVEFORMATEX)(DataFormat))->WaveFormatEx.wBitsPerSample, ((PKSDATAFORMAT_WAVEFORMATEX)(DataFormat))->WaveFormatEx.nSamplesPerSec, ((PKSDATAFORMAT_WAVEFORMATEX)(DataFormat))->WaveFormatEx.nChannels, ((PKSDATAFORMAT_WAVEFORMATEX)(DataFormat))->WaveFormatEx.wFormatTag, m_FrameSize);
 
     if (!NT_SUCCESS(Status))
         return Status;
@@ -1186,18 +1367,26 @@ CPortPinWaveCyclic::Init(
     InitializeListHead(&m_EventList);
     KeInitializeSpinLock(&m_EventListLock);
 
-    /* set up subdevice descriptor */
-    RtlZeroMemory(&m_Descriptor, sizeof(SUBDEVICE_DESCRIPTOR));
-    m_Descriptor.FilterPropertySet = PinWaveCyclicPropertySet;
-    m_Descriptor.FilterPropertySetCount = sizeof(PinWaveCyclicPropertySet) / sizeof(KSPROPERTY_SET);
-    m_Descriptor.UnknownStream = (PUNKNOWN)m_Stream;
-    m_Descriptor.DeviceDescriptor = SubDeviceDescriptor->DeviceDescriptor;
-    m_Descriptor.UnknownMiniport = SubDeviceDescriptor->UnknownMiniport;
-    m_Descriptor.PortPin = (PVOID)this;
-    m_Descriptor.EventSetCount = sizeof(PinWaveCyclicEventSet) / sizeof(KSEVENT_SET);
-    m_Descriptor.EventSet = PinWaveCyclicEventSet;
-    m_Descriptor.EventList = &m_EventList;
-    m_Descriptor.EventListLock = &m_EventListLock;
+    Status = PcCreateSubdeviceDescriptor(&m_Descriptor,
+                                         SubDeviceDescriptor->InterfaceCount,
+                                         SubDeviceDescriptor->Interfaces,
+                                         0, /* FIXME KSINTERFACE_STANDARD with KSINTERFACE_STANDARD_STREAMING / KSINTERFACE_STANDARD_LOOPED_STREAMING */
+                                         NULL,
+                                         sizeof(PinWaveCyclicPropertySet) / sizeof(KSPROPERTY_SET),
+                                         PinWaveCyclicPropertySet,
+                                         0,
+                                         0,
+                                         0,
+                                         NULL,
+                                         sizeof(PinWaveCyclicEventSet) / sizeof(KSEVENT_SET),
+                                         PinWaveCyclicEventSet,
+                                         SubDeviceDescriptor->DeviceDescriptor);
+
+    m_Descriptor->UnknownStream = (PUNKNOWN)m_Stream;
+    m_Descriptor->UnknownMiniport = SubDeviceDescriptor->UnknownMiniport;
+    m_Descriptor->PortPin = (PVOID)this;
+    m_Descriptor->EventList = &m_EventList;
+    m_Descriptor->EventListLock = &m_EventListLock;
 
     // initialize reset state
     m_ResetState = KSRESET_END;
@@ -1209,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;
     }
 
@@ -1222,13 +1411,15 @@ CPortPinWaveCyclic::Init(
     // delay of 10 milisec
     m_Delay = Int32x32To64(10, -10000);
 
+    // sanity checks
+    PC_ASSERT(m_CommonBufferSize);
+    PC_ASSERT(m_CommonBuffer);
+
     Status = m_Stream->SetNotificationFreq(10, &m_FrameSize);
     PC_ASSERT(NT_SUCCESS(Status));
     PC_ASSERT(m_FrameSize);
 
-    SilenceBuffer = AllocateItem(NonPagedPool, m_FrameSize, TAG_PORTCLASS);
-    if (!SilenceBuffer)
-        return STATUS_INSUFFICIENT_RESOURCES;
+    DPRINT1("Bits %u Samples %u Channels %u Tag %u FrameSize %u CommonBufferSize %lu, CommonBuffer %p\n", ((PKSDATAFORMAT_WAVEFORMATEX)(DataFormat))->WaveFormatEx.wBitsPerSample, ((PKSDATAFORMAT_WAVEFORMATEX)(DataFormat))->WaveFormatEx.nSamplesPerSec, ((PKSDATAFORMAT_WAVEFORMATEX)(DataFormat))->WaveFormatEx.nChannels, ((PKSDATAFORMAT_WAVEFORMATEX)(DataFormat))->WaveFormatEx.wFormatTag, m_FrameSize, m_CommonBufferSize, m_DmaChannel->SystemAddress());
 
 
     /* set up allocator framing */
@@ -1239,10 +1430,9 @@ CPortPinWaveCyclic::Init(
     m_AllocatorFraming.Reserved = 0;
     m_AllocatorFraming.FrameSize = m_FrameSize;
 
-    m_Stream->Silence(SilenceBuffer, m_FrameSize);
     m_Stream->Silence(m_CommonBuffer, m_CommonBufferSize);
 
-    Status = m_IrpQueue->Init(ConnectDetails, m_FrameSize, 0, SilenceBuffer);
+    Status = m_IrpQueue->Init(ConnectDetails, KsPinDescriptor, m_FrameSize, 0, FALSE);
     if (!NT_SUCCESS(Status))
     {
        m_IrpQueue->Release();
@@ -1261,9 +1451,6 @@ CPortPinWaveCyclic::Init(
     m_Port = Port;
     m_Filter = Filter;
 
-    //DPRINT("Setting state to acquire %x\n", m_Stream->SetState(KSSTATE_ACQUIRE));
-    //DPRINT("Setting state to pause %x\n", m_Stream->SetState(KSSTATE_PAUSE));
-
     return STATUS_SUCCESS;
 }