#include "driverdefs.h" #include #include #include "pinnodes.h" #include "wavminiport.h" #include "wavstream.h" #pragma warning (disable : 4127) //============================================================================= // CVadWaveStream //============================================================================= #pragma code_seg("PAGE") CVadWaveStream::~CVadWaveStream(void) { PAGED_CODE(); if (NULL != m_pMiniport) { if (m_bUnregisterStream) { m_pMiniport->StreamClosed(m_ulPin, this); m_bUnregisterStream = FALSE; } m_pMiniport->Release(); m_pMiniport = NULL; } if (m_pDpc) { ExFreePoolWithTag(m_pDpc, VAD_WAVRT_POOLTAG); m_pDpc = NULL; } if (m_pTimer) { ExFreePoolWithTag(m_pTimer, VAD_WAVRT_POOLTAG); m_pTimer = NULL; } if (m_pbMuted) { ExFreePoolWithTag(m_pbMuted, VAD_WAVRT_POOLTAG); m_pbMuted = NULL; } if (m_plVolumeLevel) { ExFreePoolWithTag(m_plVolumeLevel, VAD_WAVRT_POOLTAG); m_plVolumeLevel = NULL; } if (m_plPeakMeter) { ExFreePoolWithTag(m_plPeakMeter, VAD_WAVRT_POOLTAG); m_plPeakMeter = NULL; } if (m_pWfExt) { ExFreePoolWithTag(m_pWfExt, VAD_WAVRT_POOLTAG); m_pWfExt = NULL; } if (m_pNotificationTimer) { ExDeleteTimer ( m_pNotificationTimer, TRUE, TRUE, NULL ); } KeFlushQueuedDpcs(); DPF_ENTER(("[CVadWaveStream::~CVadWaveStream]")); } //============================================================================= #pragma code_seg("PAGE") NTSTATUS CVadWaveStream::Init ( _In_ PCVadWaveMiniport Miniport_, _In_ PPORTWAVERTSTREAM PortStream_, _In_ ULONG Pin_, _In_ BOOLEAN Capture_, _In_ PKSDATAFORMAT DataFormat_, _In_ GUID SignalProcessingMode ) { PAGED_CODE(); PWAVEFORMATEX pWfEx = NULL; NTSTATUS ntStatus = STATUS_SUCCESS; m_pMiniport = NULL; m_ulPin = 0; m_bUnregisterStream = FALSE; m_bCapture = FALSE; m_ulDmaBufferSize = 0; m_pDmaBuffer = NULL; m_ulNotificationsPerBuffer = 0; m_KsState = KSSTATE_STOP; m_pTimer = NULL; m_pDpc = NULL; m_llPacketCounter = 0; m_ullPlayPosition = 0; m_ullWritePosition = 0; m_ullDmaTimeStamp = 0; m_hnsElapsedTimeCarryForward = 0; m_ullLastDPCTimeStamp = 0; m_hnsDPCTimeCarryForward = 0; m_ulDmaMovementRate = 0; m_byteDisplacementCarryForward = 0; m_bLfxEnabled = FALSE; m_pbMuted = NULL; m_plVolumeLevel = NULL; m_plPeakMeter = NULL; m_pWfExt = NULL; m_ullLinearPosition = 0; m_ullPresentationPosition = 0; m_ulContentId = 0; m_ulCurrentWritePosition = 0; m_ulLastOsReadPacket = ULONG_MAX; m_ulLastOsWritePacket = ULONG_MAX; m_IsCurrentWritePositionUpdated = 0; m_SignalProcessingMode = SignalProcessingMode; m_bEoSReceived = FALSE; m_bLastBufferRendered = FALSE; m_pPortStream = PortStream_; InitializeListHead(&m_NotificationList); m_ulNotificationIntervalMs = 0; KeInitializeSpinLock(&m_PositionSpinLock); m_pNotificationTimer = ExAllocateTimer( VadTimerNotifyRT, this, EX_TIMER_HIGH_RESOLUTION ); if (!m_pNotificationTimer) { return STATUS_INSUFFICIENT_RESOURCES; } pWfEx = GetWaveFormatEx(DataFormat_); if (NULL == pWfEx) { return STATUS_UNSUCCESSFUL; } m_pMiniport = reinterpret_cast(Miniport_); if (m_pMiniport == NULL) { return STATUS_INVALID_PARAMETER; } m_pMiniport->AddRef(); if (!NT_SUCCESS(ntStatus)) { return ntStatus; } m_ulPin = Pin_; m_bCapture = Capture_; m_ulDmaMovementRate = pWfEx->nAvgBytesPerSec; m_pDpc = (PRKDPC)ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(KDPC), VAD_WAVRT_POOLTAG); if (!m_pDpc) { return STATUS_INSUFFICIENT_RESOURCES; } m_pWfExt = (PWAVEFORMATEXTENSIBLE)ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(WAVEFORMATEX) + pWfEx->cbSize, VAD_WAVRT_POOLTAG); if (m_pWfExt == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory(m_pWfExt, pWfEx, sizeof(WAVEFORMATEX) + pWfEx->cbSize); m_pbMuted = (PBOOL)ExAllocatePool2(POOL_FLAG_NON_PAGED, m_pWfExt->Format.nChannels * sizeof(BOOL), VAD_WAVRT_POOLTAG); if (m_pbMuted == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } m_plVolumeLevel = (PLONG)ExAllocatePool2(POOL_FLAG_NON_PAGED, m_pWfExt->Format.nChannels * sizeof(LONG), VAD_WAVRT_POOLTAG); if (m_plVolumeLevel == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } m_plPeakMeter = (PLONG)ExAllocatePool2(POOL_FLAG_NON_PAGED, m_pWfExt->Format.nChannels * sizeof(LONG), VAD_WAVRT_POOLTAG); if (m_plPeakMeter == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } ntStatus = m_pMiniport->StreamCreated(m_ulPin, this); if (NT_SUCCESS(ntStatus)) { m_bUnregisterStream = TRUE; } return ntStatus; } //============================================================================= #pragma code_seg("PAGE") STDMETHODIMP_(NTSTATUS) CVadWaveStream::NonDelegatingQueryInterface ( _In_ REFIID Interface, _COM_Outptr_ PVOID * Object ) { PAGED_CODE(); ASSERT(Object); if (IsEqualGUIDAligned(Interface, IID_IUnknown)) { *Object = PVOID(PUNKNOWN(PMINIPORTWAVERTSTREAM(this))); } else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRTStream)) { *Object = PVOID(PMINIPORTWAVERTSTREAM(this)); } else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRTStreamNotification)) { *Object = PVOID(PMINIPORTWAVERTSTREAMNOTIFICATION(this)); } else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRTOutputStream)) { *Object = PVOID(PMINIPORTWAVERTOUTPUTSTREAM(this)); } else if (IsEqualGUIDAligned(Interface, IID_IDrmAudioStream)) { *Object = (PVOID)(IDrmAudioStream*)this; } else { *Object = NULL; } if (*Object) { PUNKNOWN(*Object)->AddRef(); return STATUS_SUCCESS; } return STATUS_INVALID_PARAMETER; } //============================================================================= #pragma code_seg("PAGE") NTSTATUS CVadWaveStream::AllocateBufferWithNotification ( _In_ ULONG NotificationCount_, _In_ ULONG RequestedSize_, _Out_ PMDL *AudioBufferMdl_, _Out_ ULONG *ActualSize_, _Out_ ULONG *OffsetFromFirstPage_, _Out_ MEMORY_CACHING_TYPE *CacheType_ ) { PAGED_CODE(); ULONG ulBufferDurationMs = 0; if ((0 == RequestedSize_) || (RequestedSize_ < m_pWfExt->Format.nBlockAlign)) { return STATUS_UNSUCCESSFUL; } if ((NotificationCount_ == 0) || (RequestedSize_ % NotificationCount_ != 0)) { return STATUS_INVALID_PARAMETER; } if (0 == m_ulDmaMovementRate) { return STATUS_INVALID_PARAMETER; } RequestedSize_ -= RequestedSize_ % (m_pWfExt->Format.nBlockAlign); PHYSICAL_ADDRESS highAddress; highAddress.HighPart = 0; highAddress.LowPart = MAXULONG; PMDL pBufferMdl = m_pPortStream->AllocatePagesForMdl(highAddress, RequestedSize_); if (NULL == pBufferMdl) { return STATUS_UNSUCCESSFUL; } m_pDmaBuffer = (BYTE*)m_pPortStream->MapAllocatedPages(pBufferMdl, MmCached); m_ulNotificationsPerBuffer = NotificationCount_; m_ulDmaBufferSize = RequestedSize_; ulBufferDurationMs = (RequestedSize_ * 1000) / m_ulDmaMovementRate; m_ulNotificationIntervalMs = ulBufferDurationMs / NotificationCount_; *AudioBufferMdl_ = pBufferMdl; *ActualSize_ = RequestedSize_; *OffsetFromFirstPage_ = 0; *CacheType_ = MmCached; return STATUS_SUCCESS; } //============================================================================= #pragma code_seg("PAGE") VOID CVadWaveStream::FreeBufferWithNotification ( _In_ PMDL Mdl_, _In_ ULONG Size_ ) { UNREFERENCED_PARAMETER(Size_); PAGED_CODE(); if (Mdl_ != NULL) { if (m_pDmaBuffer != NULL) { m_pPortStream->UnmapAllocatedPages(m_pDmaBuffer, Mdl_); m_pDmaBuffer = NULL; } m_pPortStream->FreePagesFromMdl(Mdl_); } m_ulDmaBufferSize = 0; m_ulNotificationsPerBuffer = 0; } //============================================================================= #pragma code_seg("PAGE") NTSTATUS CVadWaveStream::RegisterNotificationEvent ( _In_ PKEVENT NotificationEvent_ ) { UNREFERENCED_PARAMETER(NotificationEvent_); PAGED_CODE(); NotificationListEntry *nleNew = (NotificationListEntry*)ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof(NotificationListEntry), VAD_WAVRT_POOLTAG); if (NULL == nleNew) { return STATUS_INSUFFICIENT_RESOURCES; } nleNew->NotificationEvent = NotificationEvent_; if (!IsListEmpty(&m_NotificationList)) { PLIST_ENTRY leCurrent = m_NotificationList.Flink; while (leCurrent != &m_NotificationList) { NotificationListEntry* nleCurrent = CONTAINING_RECORD(leCurrent, NotificationListEntry, ListEntry); if (nleCurrent->NotificationEvent == NotificationEvent_) { ExFreePoolWithTag(nleNew, VAD_WAVRT_POOLTAG); return STATUS_UNSUCCESSFUL; } leCurrent = leCurrent->Flink; } } InsertTailList(&m_NotificationList, &(nleNew->ListEntry)); return STATUS_SUCCESS; } //============================================================================= #pragma code_seg("PAGE") NTSTATUS CVadWaveStream::UnregisterNotificationEvent ( _In_ PKEVENT NotificationEvent_ ) { UNREFERENCED_PARAMETER(NotificationEvent_); PAGED_CODE(); if (!IsListEmpty(&m_NotificationList)) { PLIST_ENTRY leCurrent = m_NotificationList.Flink; while (leCurrent != &m_NotificationList) { NotificationListEntry* nleCurrent = CONTAINING_RECORD(leCurrent, NotificationListEntry, ListEntry); if (nleCurrent->NotificationEvent == NotificationEvent_) { RemoveEntryList(leCurrent); ExFreePoolWithTag(nleCurrent, VAD_WAVRT_POOLTAG); return STATUS_SUCCESS; } leCurrent = leCurrent->Flink; } } return STATUS_NOT_FOUND; } //============================================================================= #pragma code_seg("PAGE") NTSTATUS CVadWaveStream::GetClockRegister ( _Out_ PKSRTAUDIO_HWREGISTER Register_ ) { UNREFERENCED_PARAMETER(Register_); PAGED_CODE(); return STATUS_NOT_IMPLEMENTED; } //============================================================================= #pragma code_seg("PAGE") NTSTATUS CVadWaveStream::GetPositionRegister ( _Out_ PKSRTAUDIO_HWREGISTER Register_ ) { UNREFERENCED_PARAMETER(Register_); PAGED_CODE(); return STATUS_NOT_IMPLEMENTED; } //============================================================================= #pragma code_seg("PAGE") VOID CVadWaveStream::GetHWLatency ( _Out_ PKSRTAUDIO_HWLATENCY Latency_ ) { PAGED_CODE(); ASSERT(Latency_); Latency_->ChipsetDelay = 0; Latency_->CodecDelay = 0; Latency_->FifoSize = 0; } //============================================================================= #pragma code_seg("PAGE") VOID CVadWaveStream::FreeAudioBuffer ( _In_opt_ PMDL Mdl_, _In_ ULONG Size_ ) { UNREFERENCED_PARAMETER(Size_); PAGED_CODE(); if (Mdl_ != NULL) { if (m_pDmaBuffer != NULL) { m_pPortStream->UnmapAllocatedPages(m_pDmaBuffer, Mdl_); m_pDmaBuffer = NULL; } m_pPortStream->FreePagesFromMdl(Mdl_); } m_ulDmaBufferSize = 0; m_ulNotificationsPerBuffer = 0; } //============================================================================= #pragma code_seg("PAGE") NTSTATUS CVadWaveStream::AllocateAudioBuffer ( _In_ ULONG RequestedSize_, _Out_ PMDL *AudioBufferMdl_, _Out_ ULONG *ActualSize_, _Out_ ULONG *OffsetFromFirstPage_, _Out_ MEMORY_CACHING_TYPE *CacheType_ ) { PAGED_CODE(); if ((0 == RequestedSize_) || (RequestedSize_ < m_pWfExt->Format.nBlockAlign)) { return STATUS_UNSUCCESSFUL; } RequestedSize_ -= RequestedSize_ % (m_pWfExt->Format.nBlockAlign); PHYSICAL_ADDRESS highAddress; highAddress.HighPart = 0; highAddress.LowPart = MAXULONG; PMDL pBufferMdl = m_pPortStream->AllocatePagesForMdl(highAddress, RequestedSize_); if (NULL == pBufferMdl) { return STATUS_UNSUCCESSFUL; } m_pDmaBuffer = (BYTE*)m_pPortStream->MapAllocatedPages(pBufferMdl, MmCached); m_ulDmaBufferSize = RequestedSize_; m_ulNotificationsPerBuffer = 0; *AudioBufferMdl_ = pBufferMdl; *ActualSize_ = RequestedSize_; *OffsetFromFirstPage_ = 0; *CacheType_ = MmCached; return STATUS_SUCCESS; } //============================================================================= #pragma code_seg() NTSTATUS CVadWaveStream::GetPosition ( _Out_ KSAUDIO_POSITION *Position_ ) { NTSTATUS ntStatus; KIRQL oldIrql; KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql); if (m_KsState == KSSTATE_RUN) { LARGE_INTEGER ilQPC = KeQueryPerformanceCounter(NULL); UpdatePosition(ilQPC); } Position_->PlayOffset = m_ullPlayPosition; Position_->WriteOffset = m_ullWritePosition; KeReleaseSpinLock(&m_PositionSpinLock, oldIrql); ntStatus = STATUS_SUCCESS; return ntStatus; } //============================================================================= #pragma code_seg() _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS CVadWaveStream::SetWritePacket ( _In_ ULONG PacketNumber, _In_ DWORD Flags, _In_ ULONG EosPacketLength ) { UNREFERENCED_PARAMETER(EosPacketLength); NTSTATUS ntStatus; if (m_ulNotificationsPerBuffer == 0) { return STATUS_NOT_SUPPORTED; } ULONG oldLastOsWritePacket = m_ulLastOsWritePacket; if (m_bEoSReceived) { return STATUS_INVALID_DEVICE_STATE; } KIRQL oldIrql; KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql); LONGLONG currentPacket = m_llPacketCounter; KeReleaseSpinLock(&m_PositionSpinLock, oldIrql); ULONG expectedPacket = LODWORD(currentPacket); if (m_KsState == KSSTATE_RUN) { expectedPacket++; } LONG deltaFromExpectedPacket = PacketNumber - expectedPacket; if (deltaFromExpectedPacket < 0) { return STATUS_DATA_LATE_ERROR; } else if (deltaFromExpectedPacket > 0) { return STATUS_DATA_OVERRUN; } ULONG packetSize = (m_ulDmaBufferSize / m_ulNotificationsPerBuffer); ULONG packetIndex = PacketNumber % m_ulNotificationsPerBuffer; ULONG ulCurrentWritePosition = packetIndex * packetSize; if (Flags & KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM) { return STATUS_INVALID_PARAMETER; } else { m_ulLastOsWritePacket = PacketNumber; KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql); ntStatus = SetCurrentWritePositionInternal(ulCurrentWritePosition); KeReleaseSpinLock(&m_PositionSpinLock, oldIrql); } if (!NT_SUCCESS(ntStatus)) { m_ulLastOsWritePacket = oldLastOsWritePacket; } return ntStatus; } //============================================================================= #pragma code_seg() _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS CVadWaveStream::GetOutputStreamPresentationPosition ( _Out_ KSAUDIO_PRESENTATION_POSITION *pPresentationPosition ) { ASSERT(pPresentationPosition); if (m_ulNotificationsPerBuffer == 0) { return STATUS_NOT_SUPPORTED; } return GetPresentationPosition(pPresentationPosition); } //============================================================================= #pragma code_seg() _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS CVadWaveStream::GetPacketCount ( _Out_ ULONG *pPacketCount ) { ASSERT(pPacketCount); if (m_ulNotificationsPerBuffer == 0) { return STATUS_NOT_SUPPORTED; } KIRQL oldIrql; KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql); if (m_KsState == KSSTATE_RUN) { LARGE_INTEGER ilQPC = KeQueryPerformanceCounter(NULL); UpdatePosition(ilQPC); } *pPacketCount = LODWORD(m_llPacketCounter); KeReleaseSpinLock(&m_PositionSpinLock, oldIrql); return STATUS_SUCCESS; } //============================================================================= #pragma code_seg() NTSTATUS CVadWaveStream::GetPositions( _Out_opt_ ULONGLONG* _pullLinearBufferPosition, _Out_opt_ ULONGLONG* _pullPresentationPosition, _Out_opt_ LARGE_INTEGER* _pliQPCTime ) { DPF_ENTER(("[CVadWaveStream::GetPositions]")); NTSTATUS ntStatus; LARGE_INTEGER ilQPC; KIRQL oldIrql; KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql); ilQPC = KeQueryPerformanceCounter(NULL); if (m_KsState == KSSTATE_RUN) { UpdatePosition(ilQPC); } if (_pullLinearBufferPosition) { *_pullLinearBufferPosition = m_ullLinearPosition; } if (_pullPresentationPosition) { *_pullPresentationPosition = m_ullPresentationPosition; } KeReleaseSpinLock(&m_PositionSpinLock, oldIrql); if (_pliQPCTime) { *_pliQPCTime = ilQPC; } ntStatus = STATUS_SUCCESS; return ntStatus; } //============================================================================= #pragma code_seg() NTSTATUS CVadWaveStream::GetPresentationPosition( _Out_ KSAUDIO_PRESENTATION_POSITION* _pPresentationPosition ) { ASSERT(_pPresentationPosition); LARGE_INTEGER timeStamp; DPF_ENTER(("[CVadWaveStream::GetPresentationPosition]")); ULONGLONG ullLinearPosition = { 0 }; ULONGLONG ullPresentationPosition = { 0 }; NTSTATUS status = STATUS_SUCCESS; status = GetPositions(&ullLinearPosition, &ullPresentationPosition, &timeStamp); if (!NT_SUCCESS(status)) { return status; } if (0 == m_pWfExt->Format.nAvgBytesPerSec) { return STATUS_INVALID_DEVICE_STATE; } _pPresentationPosition->u64PositionInBlocks = ullPresentationPosition * m_pWfExt->Format.nSamplesPerSec / m_pWfExt->Format.nAvgBytesPerSec; _pPresentationPosition->u64QPCPosition = (UINT64)timeStamp.QuadPart; return STATUS_SUCCESS; } //============================================================================= #pragma code_seg() NTSTATUS CVadWaveStream::SetCurrentWritePositionInternal( _In_ ULONG _ulCurrentWritePosition ) { DPF_ENTER(("[CVadWaveStream::SetCurrentWritePositionInternal]")); ASSERT(m_bEoSReceived == FALSE); if (m_bEoSReceived) { return STATUS_INVALID_DEVICE_REQUEST; } if (_ulCurrentWritePosition > m_ulDmaBufferSize) { return STATUS_INVALID_DEVICE_REQUEST; } PADAPTERCOMMON pAdapterComm = m_pMiniport->GetAdapterCommObj(); pAdapterComm->WriteEtwEvent(eMINIPORT_SET_WAVERT_BUFFER_WRITE_POSITION, m_ullLinearPosition, m_ulCurrentWritePosition, _ulCurrentWritePosition, 0); if (m_ulNotificationIntervalMs > 0) { if (m_ulCurrentWritePosition == _ulCurrentWritePosition) { pAdapterComm->WriteEtwEvent(eMINIPORT_GLITCH_REPORT, m_ullLinearPosition, m_ulCurrentWritePosition, 3, _ulCurrentWritePosition); } } m_ulCurrentWritePosition = _ulCurrentWritePosition; InterlockedExchange(&m_IsCurrentWritePositionUpdated, 1); return STATUS_SUCCESS; } //============================================================================= #pragma code_seg() NTSTATUS CVadWaveStream::SetState ( _In_ KSSTATE State_ ) { NTSTATUS ntStatus = STATUS_SUCCESS; KIRQL oldIrql; switch (State_) { case KSSTATE_STOP: if (m_KsState == KSSTATE_ACQUIRE) { // Acquire stream resources } KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql); m_llPacketCounter = 0; m_ullPlayPosition = 0; m_ullWritePosition = 0; m_ullLinearPosition = 0; m_ullPresentationPosition = 0; m_ulLastOsReadPacket = ULONG_MAX; m_ulCurrentWritePosition = 0; m_ulLastOsWritePacket = ULONG_MAX; m_bEoSReceived = FALSE; m_bLastBufferRendered = FALSE; KeReleaseSpinLock(&m_PositionSpinLock, oldIrql); break; case KSSTATE_ACQUIRE: if (m_KsState == KSSTATE_STOP) { // Acquire stream resources } break; case KSSTATE_PAUSE: if (m_KsState > KSSTATE_PAUSE) { // Run -> Pause if (m_ulNotificationIntervalMs > 0) { ExCancelTimer(m_pNotificationTimer, NULL); KeFlushQueuedDpcs(); if (m_ullLastDPCTimeStamp > 0) { LARGE_INTEGER qpc; LARGE_INTEGER qpcFrequency; LONGLONG hnsCurrentTime; qpc = KeQueryPerformanceCounter(&qpcFrequency); hnsCurrentTime = KSCONVERT_PERFORMANCE_TIME(m_ullPerformanceCounterFrequency.QuadPart, qpc); m_hnsDPCTimeCarryForward = hnsCurrentTime - m_ullLastDPCTimeStamp + m_hnsDPCTimeCarryForward; } } } GetPositions(NULL, NULL, NULL); break; case KSSTATE_RUN: { LARGE_INTEGER ullPerfCounterTemp; ullPerfCounterTemp = KeQueryPerformanceCounter(&m_ullPerformanceCounterFrequency); m_ullLastDPCTimeStamp = m_ullDmaTimeStamp = KSCONVERT_PERFORMANCE_TIME(m_ullPerformanceCounterFrequency.QuadPart, ullPerfCounterTemp); if (m_ulNotificationIntervalMs > 0) { ExSetTimer ( m_pNotificationTimer, (-1) * HNSTIME_PER_MILLISECOND, HNSTIME_PER_MILLISECOND, NULL ); } break; } } m_KsState = State_; return ntStatus; } //============================================================================= #pragma code_seg("PAGE") NTSTATUS CVadWaveStream::SetFormat ( _In_ KSDATAFORMAT *DataFormat_ ) { UNREFERENCED_PARAMETER(DataFormat_); PAGED_CODE(); return STATUS_NOT_SUPPORTED; } //============================================================================= #pragma code_seg() VOID CVadWaveStream::UpdatePosition ( _In_ LARGE_INTEGER ilQPC ) { // Convert ticks to 100ns units LONGLONG hnsCurrentTime = KSCONVERT_PERFORMANCE_TIME(m_ullPerformanceCounterFrequency.QuadPart, ilQPC); ULONG TimeElapsedInMS = (ULONG)(hnsCurrentTime - m_ullDmaTimeStamp + m_hnsElapsedTimeCarryForward) / 10000; m_hnsElapsedTimeCarryForward = (hnsCurrentTime - m_ullDmaTimeStamp + m_hnsElapsedTimeCarryForward) % 10000; ULONG ByteDisplacement = ((m_ulDmaMovementRate * TimeElapsedInMS) + m_byteDisplacementCarryForward) / 1000; m_byteDisplacementCarryForward = ((m_ulDmaMovementRate * TimeElapsedInMS) + m_byteDisplacementCarryForward) % 1000; // Increment presentation position even after last buffer is rendered m_ullPresentationPosition += ByteDisplacement; // Render path: handle EoS boundary if (m_bEoSReceived) { if (m_ullWritePosition <= m_ulCurrentWritePosition) { ByteDisplacement = min(ByteDisplacement, m_ulCurrentWritePosition - (ULONG)m_ullWritePosition); } else if ((m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize < m_ullWritePosition) { if ((m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize > m_ulCurrentWritePosition) { ByteDisplacement = ByteDisplacement - (((ULONG)m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize - m_ulCurrentWritePosition); } } } if (m_bEoSReceived && !m_bLastBufferRendered && (m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize == m_ulCurrentWritePosition) { m_bLastBufferRendered = TRUE; } // Audio data is silently discarded — no read/write of the DMA buffer // Advance the DMA position and wrap at buffer length m_ullPlayPosition = m_ullWritePosition = (m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize; m_ullLinearPosition += ByteDisplacement; m_ullDmaTimeStamp = hnsCurrentTime; } //============================================================================= #pragma code_seg("PAGE") STDMETHODIMP_(NTSTATUS) CVadWaveStream::SetContentId ( _In_ ULONG contentId, _In_ PCDRMRIGHTS drmRights ) { PAGED_CODE(); UNREFERENCED_PARAMETER(drmRights); DPF_ENTER(("[CVadWaveStream::SetContentId]")); NTSTATUS ntStatus; ULONG ulOldContentId = contentId; m_ulContentId = contentId; ntStatus = m_pMiniport->UpdateDrmRights(); if (!NT_SUCCESS(ntStatus)) { m_ulContentId = ulOldContentId; } return ntStatus; } //============================================================================= #pragma code_seg() void VadTimerNotifyRT ( _In_ PEX_TIMER Timer, _In_opt_ PVOID DeferredContext ) { LARGE_INTEGER qpc; LARGE_INTEGER qpcFrequency; BOOL bufferCompleted = FALSE; UNREFERENCED_PARAMETER(Timer); _IRQL_limited_to_(DISPATCH_LEVEL); CVadWaveStream* _this = (CVadWaveStream*)DeferredContext; if (NULL == _this) { return; } KIRQL oldIrql; KeAcquireSpinLock(&_this->m_PositionSpinLock, &oldIrql); qpc = KeQueryPerformanceCounter(&qpcFrequency); LONGLONG hnsCurrentTime = KSCONVERT_PERFORMANCE_TIME(_this->m_ullPerformanceCounterFrequency.QuadPart, qpc); ULONG TimeElapsedInMS = (ULONG)(hnsCurrentTime - _this->m_ullLastDPCTimeStamp + _this->m_hnsDPCTimeCarryForward) / 10000; if (TimeElapsedInMS >= _this->m_ulNotificationIntervalMs) { _this->m_hnsDPCTimeCarryForward = hnsCurrentTime - _this->m_ullLastDPCTimeStamp + _this->m_hnsDPCTimeCarryForward - (_this->m_ulNotificationIntervalMs * 10000); _this->m_ullLastDPCTimeStamp = hnsCurrentTime; bufferCompleted = TRUE; } if (!bufferCompleted && !_this->m_bEoSReceived) { goto End; } _this->UpdatePosition(qpc); if (!_this->m_bEoSReceived) { _this->m_llPacketCounter++; } if (_this->m_KsState != KSSTATE_RUN) { goto End; } PADAPTERCOMMON pAdapterComm = _this->m_pMiniport->GetAdapterCommObj(); if (!_this->IsCurrentWaveRTWritePositionUpdated() && !_this->m_bEoSReceived) { pAdapterComm->WriteEtwEvent(eMINIPORT_GLITCH_REPORT, _this->m_ullLinearPosition, _this->GetCurrentWaveRTWritePosition(), 1, 0); } if (!IsListEmpty(&_this->m_NotificationList) && (bufferCompleted || _this->m_bLastBufferRendered)) { PLIST_ENTRY leCurrent = _this->m_NotificationList.Flink; while (leCurrent != &_this->m_NotificationList) { NotificationListEntry* nleCurrent = CONTAINING_RECORD(leCurrent, NotificationListEntry, ListEntry); KeSetEvent(nleCurrent->NotificationEvent, 0, 0); leCurrent = leCurrent->Flink; } } if (_this->m_bLastBufferRendered) { ExCancelTimer(_this->m_pNotificationTimer, NULL); } End: KeReleaseSpinLock(&_this->m_PositionSpinLock, oldIrql); return; }