mirror of
https://github.com/jamesstringer90/appsandbox.git
synced 2026-10-22 02:52:49 -05:00
- M15 wavminiport.cpp: reject PinId >= WaveDescriptor->PinCount in the proposed-format property handler. - M16 wavstream.cpp: guard divide-by-zero on m_ulDmaMovementRate and nAvgBytesPerSec in buffer allocation and presentation-position. - L14 topology.cpp: set PropertyRequest->ValueSize in both jack description GET paths. - L15 adaptercommon.cpp: balance the adapter instance count on the allocation-failure path.
1077 lines
28 KiB
C++
1077 lines
28 KiB
C++
#include "driverdefs.h"
|
|
#include <limits.h>
|
|
#include <ks.h>
|
|
#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<CVadWaveMiniport*>(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;
|
|
}
|