📄 basewave.cpp
字号:
Arguments:
Miniport_ - miniport object
Pin_ - pin id
Capture_ - TRUE if this is a capture stream
DataFormat_ - new dataformat
Return Value:
NT status code.
--*/
{
PAGED_CODE();
DPF_ENTER(("[CMiniportWaveCyclicStreamMSVAD::Init]"));
ASSERT(Miniport_);
ASSERT(DataFormat_);
NTSTATUS ntStatus = STATUS_SUCCESS;
PWAVEFORMATEX pWfx;
pWfx = GetWaveFormatEx(DataFormat_);
if (!pWfx)
{
DPF(D_TERSE, ("Invalid DataFormat param in NewStream"));
ntStatus = STATUS_INVALID_PARAMETER;
}
if (NT_SUCCESS(ntStatus))
{
m_pMiniport = Miniport_;
m_ulPin = Pin_;
m_fCapture = Capture_;
m_fFormatStereo = (pWfx->nChannels == 2);
m_fFormat16Bit = (pWfx->wBitsPerSample == 16);
m_ksState = KSSTATE_STOP;
m_ulDmaPosition = 0;
m_fDmaActive = FALSE;
m_pDpc = NULL;
m_pTimer = NULL;
m_pvDmaBuffer = NULL;
// If this is not the capture stream, create the output file.
//
if (!m_fCapture)
{
DPF(D_TERSE, ("SaveData %X", &m_SaveData));
ntStatus = m_SaveData.SetDataFormat(DataFormat_);
if (NT_SUCCESS(ntStatus))
{
ntStatus = m_SaveData.Initialize();
}
}
}
// Allocate DMA buffer for this stream.
//
if (NT_SUCCESS(ntStatus))
{
ntStatus = AllocateBuffer(m_pMiniport->m_MaxDmaBufferSize, NULL);
}
// Set sample frequency. Note that m_SampleRateSync access should
// be syncronized.
//
if (NT_SUCCESS(ntStatus))
{
ntStatus =
KeWaitForSingleObject
(
&m_pMiniport->m_SampleRateSync,
Executive,
KernelMode,
FALSE,
NULL
);
if (NT_SUCCESS(ntStatus))
{
m_pMiniport->m_SamplingFrequency = pWfx->nSamplesPerSec;
KeReleaseMutex(&m_pMiniport->m_SampleRateSync, FALSE);
}
else
{
DPF(D_TERSE, ("[SamplingFrequency Sync failed: %08X]", ntStatus));
}
}
if (NT_SUCCESS(ntStatus))
{
ntStatus = SetFormat(DataFormat_);
}
if (NT_SUCCESS(ntStatus))
{
m_pDpc = (PRKDPC)
ExAllocatePoolWithTag
(
NonPagedPool,
sizeof(KDPC),
MSVAD_POOLTAG
);
if (!m_pDpc)
{
DPF(D_TERSE, ("[Could not allocate memory for DPC]"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
if (NT_SUCCESS(ntStatus))
{
m_pTimer = (PKTIMER)
ExAllocatePoolWithTag
(
NonPagedPool,
sizeof(KTIMER),
MSVAD_POOLTAG
);
if (!m_pTimer)
{
DPF(D_TERSE, ("[Could not allocate memory for Timer]"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
if (NT_SUCCESS(ntStatus))
{
KeInitializeDpc(m_pDpc, TimerNotify, m_pMiniport);
KeInitializeTimerEx(m_pTimer, NotificationTimer);
}
return ntStatus;
} // Init
#pragma code_seg()
//=============================================================================
// CMiniportWaveCyclicStreamMSVAD IMiniportWaveCyclicStream
//=============================================================================
//=============================================================================
STDMETHODIMP
CMiniportWaveCyclicStreamMSVAD::GetPosition
(
OUT PULONG Position
)
/*++
Routine Description:
The GetPosition function gets the current position of the DMA read or write
pointer for the stream. Callers of GetPosition should run at
IRQL <= DISPATCH_LEVEL.
Arguments:
Position - Position of the DMA pointer
Return Value:
NT status code.
--*/
{
if (m_fDmaActive)
{
ULONGLONG CurrentTime = KeQueryInterruptTime();
ULONG TimeElapsedInMS =
( (ULONG) (CurrentTime - m_ullDmaTimeStamp) ) / 10000;
ULONG ByteDisplacement =
(m_ulDmaMovementRate * TimeElapsedInMS) / 1000;
m_ulDmaPosition =
(m_ulDmaPosition + ByteDisplacement) % m_ulDmaBufferSize;
*Position = m_ulDmaPosition;
m_ullDmaTimeStamp = CurrentTime;
}
else
{
*Position = m_ulDmaPosition;
}
return STATUS_SUCCESS;
} // GetPosition
//=============================================================================
STDMETHODIMP
CMiniportWaveCyclicStreamMSVAD::NormalizePhysicalPosition
(
IN OUT PLONGLONG PhysicalPosition
)
/*++
Routine Description:
Given a physical position based on the actual number of bytes transferred,
NormalizePhysicalPosition converts the position to a time-based value of
100 nanosecond units. Callers of NormalizePhysicalPosition can run at any IRQL.
Arguments:
PhysicalPosition - On entry this variable contains the value to convert.
On return it contains the converted value
Return Value:
NT status code.
--*/
{
*PhysicalPosition =
( _100NS_UNITS_PER_SECOND /
( 1 << ( m_fFormatStereo + m_fFormat16Bit ) ) * *PhysicalPosition ) /
m_pMiniport->m_SamplingFrequency;
return STATUS_SUCCESS;
} // NormalizePhysicalPosition
#pragma code_seg("PAGE")
//=============================================================================
STDMETHODIMP_(NTSTATUS)
CMiniportWaveCyclicStreamMSVAD::SetFormat
(
IN PKSDATAFORMAT Format
)
/*++
Routine Description:
The SetFormat function changes the format associated with a stream.
Callers of SetFormat should run at IRQL PASSIVE_LEVEL
Arguments:
Format - Pointer to a KSDATAFORMAT structure which indicates the new format
of the stream.
Return Value:
NT status code.
--*/
{
PAGED_CODE();
ASSERT(Format);
DPF_ENTER(("[CMiniportWaveCyclicStreamMSVAD::SetFormat]"));
NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
PWAVEFORMATEX pWfx;
if (m_ksState != KSSTATE_RUN)
{
// MSVAD does not validate the format.
//
pWfx = GetWaveFormatEx(Format);
if (pWfx)
{
ntStatus =
KeWaitForSingleObject
(
&m_pMiniport->m_SampleRateSync,
Executive,
KernelMode,
FALSE,
NULL
);
if (NT_SUCCESS(ntStatus))
{
if (!m_fCapture)
{
ntStatus = m_SaveData.SetDataFormat(Format);
}
m_fFormatStereo = (pWfx->nChannels == 2);
m_fFormat16Bit = (pWfx->wBitsPerSample == 16);
m_pMiniport->m_SamplingFrequency =
pWfx->nSamplesPerSec;
m_ulDmaMovementRate = pWfx->nAvgBytesPerSec;
DPF(D_TERSE, ("New Format: %d", pWfx->nSamplesPerSec));
}
KeReleaseMutex(&m_pMiniport->m_SampleRateSync, FALSE);
}
}
return ntStatus;
} // SetFormat
//=============================================================================
STDMETHODIMP_(ULONG)
CMiniportWaveCyclicStreamMSVAD::SetNotificationFreq
(
IN ULONG Interval,
OUT PULONG FramingSize
)
/*++
Routine Description:
The SetNotificationFrequency function sets the frequency at which
notification interrupts are generated. Callers of SetNotificationFrequency
should run at IRQL PASSIVE_LEVEL.
Arguments:
Interval - Value indicating the interval between interrupts,
expressed in milliseconds
FramingSize - Pointer to a ULONG value where the number of bytes equivalent
to Interval milliseconds is returned
Return Value:
NT status code.
--*/
{
PAGED_CODE();
ASSERT(FramingSize);
DPF_ENTER(("[CMiniportWaveCyclicStreamMSVAD::SetNotificationFreq]"));
m_pMiniport->m_NotificationInterval = Interval;
*FramingSize =
( 1 << ( m_fFormatStereo + m_fFormat16Bit ) ) *
m_pMiniport->m_SamplingFrequency *
Interval / 1000;
return m_pMiniport->m_NotificationInterval;
} // SetNotificationFreq
//=============================================================================
STDMETHODIMP
CMiniportWaveCyclicStreamMSVAD::SetState
(
IN KSSTATE NewState
)
/*++
Routine Description:
The SetState function sets the new state of playback or recording for the
stream. SetState should run at IRQL PASSIVE_LEVEL
Arguments:
NewState - KSSTATE indicating the new state for the stream.
Return Value:
NT status code.
--*/
{
PAGED_CODE();
DPF_ENTER(("[CMiniportWaveCyclicStreamMSVAD::SetState]"));
NTSTATUS ntStatus = STATUS_SUCCESS;
// The acquire state is not distinguishable from the stop state for our
// purposes.
//
if (NewState == KSSTATE_ACQUIRE)
{
NewState = KSSTATE_STOP;
}
if (m_ksState != NewState)
{
switch(NewState)
{
case KSSTATE_PAUSE:
{
DPF(D_TERSE, ("KSSTATE_PAUSE"));
m_fDmaActive = FALSE;
}
break;
case KSSTATE_RUN:
{
DPF(D_TERSE, ("KSSTATE_RUN"));
LARGE_INTEGER delay;
// Set the timer for DPC.
//
m_ullDmaTimeStamp = KeQueryInterruptTime();
m_fDmaActive = TRUE;
delay.HighPart = 0;
delay.LowPart = m_pMiniport->m_NotificationInterval;
KeSetTimerEx
(
m_pTimer,
delay,
m_pMiniport->m_NotificationInterval,
m_pDpc
);
}
break;
case KSSTATE_STOP:
DPF(D_TERSE, ("KSSTATE_STOP"));
m_fDmaActive = FALSE;
m_ulDmaPosition = 0;
KeCancelTimer( m_pTimer );
// Wait until all work items are completed.
//
if (!m_fCapture)
{
m_SaveData.WaitAllWorkItems();
}
break;
}
m_ksState = NewState;
}
return ntStatus;
} // SetState
#pragma code_seg()
//=============================================================================
STDMETHODIMP_(void)
CMiniportWaveCyclicStreamMSVAD::Silence
(
IN PVOID Buffer,
IN ULONG ByteCount
)
/*++
Routine Description:
The Silence function is used to copy silence samplings to a certain location.
Callers of Silence can run at any IRQL
Arguments:
Buffer - Pointer to the buffer where the silence samplings should
be deposited.
ByteCount - Size of buffer indicating number of bytes to be deposited.
Return Value:
NT status code.
--*/
{
RtlFillMemory(Buffer, ByteCount, m_fFormat16Bit ? 0 : 0x80);
} // Silence
//=============================================================================
void
TimerNotify
(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SA1,
IN PVOID SA2
)
/*++
Routine Description:
Dpc routine. This simulates an interrupt service routine. The Dpc will be
called whenever CMiniportWaveCyclicStreamMSVAD::m_pTimer triggers.
Arguments:
Dpc - the Dpc object
DeferredContext - Pointer to a caller-supplied context to be passed to
the DeferredRoutine when it is called
SA1 - System argument 1
SA2 - System argument 2
Return Value:
NT status code.
--*/
{
PCMiniportWaveCyclicMSVAD pMiniport =
(PCMiniportWaveCyclicMSVAD) DeferredContext;
if (pMiniport && pMiniport->m_Port)
{
pMiniport->m_Port->Notify(pMiniport->m_ServiceGroup);
}
} // TimerNotify
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -