/*++Copyright (c) 1997-2000 Microsoft Corporation All Rights Reserved Module Name: minstream.cpp Abstract: Implementation of wavecyclic stream.--*/ #pragma warning (disable : 4127) #include "scream.h"#include "common.h"#include "minwave.h"#include "minstream.h"#include "wavtable.h"#include <stdlib.h> #define SILENCE_SAMPLE_LEVEL 5 // #pragma code_seg("PAGE") //=============================================================================// CMiniportWaveStreamCyclic//=============================================================================CMiniportWaveCyclicStream::CMiniportWaveCyclicStream(PUNKNOWN other) : CUnknown(other){ // PAGED_CODE(); m_pMiniport = NULL; m_fCapture = FALSE; m_fFormat16Bit = FALSE; m_usBlockAlign = 0; m_ksState = KSSTATE_STOP; m_ulPin = (ULONG)-1; m_pDpc = NULL; m_pTimer = NULL; m_fDmaActive = FALSE; m_ulDmaPosition = 0; m_ullElapsedTimeCarryForward = 0; m_ulByteDisplacementCarryForward = 0; m_pvDmaBuffer = NULL; m_ulDmaBufferSize = 0; m_ulDmaMovementRate = 0; m_ullDmaTimeStamp = 0; m_silenceState = 0;} //=============================================================================CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream(void)/*++Routine Description: Destructor for wavecyclicstream Arguments: Return Value: NT status code.--*/{ // PAGED_CODE(); DPF_ENTER(("[CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream]")); if (m_pTimer) { KeCancelTimer(m_pTimer); ExFreePoolWithTag(m_pTimer, MSVAD_POOLTAG); } if (m_pDpc) { ExFreePoolWithTag( m_pDpc, MSVAD_POOLTAG ); } // Free the DMA buffer FreeBuffer(); if (NULL != m_pMiniport) { if (m_fCapture) { m_pMiniport->m_fCaptureAllocated = FALSE; } else { m_pMiniport->m_fRenderAllocated = FALSE; } }} // ~CMiniportWaveCyclicStream //=============================================================================NTSTATUS CMiniportWaveCyclicStream::Init( IN PCMiniportWaveCyclic Miniport_, IN ULONG Pin_, IN BOOLEAN Capture_, IN PKSDATAFORMAT DataFormat_)/*++Routine Description: Initializes the stream object. Allocate a DMA buffer, timer and DPC Arguments: Miniport_ - Pin_ - Capture_ - DataFormat - DmaChannel_ - Return Value: NT status code.--*/{ // PAGED_CODE(); 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_usBlockAlign = pWfx->nBlockAlign; m_fFormat16Bit = (pWfx->wBitsPerSample == 16); m_bitsPerSample = pWfx->wBitsPerSample; m_bChannels = (BYTE)(pWfx->nChannels); m_ksState = KSSTATE_STOP; m_ulDmaPosition = 0; m_ullElapsedTimeCarryForward = 0; m_ulByteDisplacementCarryForward = 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) { if (NT_SUCCESS(ntStatus)) { DWORD dwChannelMask = KSAUDIO_SPEAKER_STEREO; if ((pWfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) && (pWfx->cbSize == CB_EXTENSIBLE)) { WAVEFORMATEXTENSIBLE* pWfxT = (WAVEFORMATEXTENSIBLE*)pWfx; dwChannelMask = pWfxT->dwChannelMask; } if (g_UseIVSHMEM) { ntStatus = m_IVSHMEMSaveData.Initialize(pWfx->nSamplesPerSec, pWfx->wBitsPerSample, pWfx->nChannels, dwChannelMask); } else { ntStatus = m_SaveData.Initialize(pWfx->nSamplesPerSec, pWfx->wBitsPerSample, pWfx->nChannels, dwChannelMask); } } } } // 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 (STATUS_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 //=============================================================================STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclicStream::NonDelegatingQueryInterface( IN REFIID Interface, OUT PVOID * Object )/*++Routine Description: QueryInterface Arguments: Interface - GUID Object - interface pointer to be returned Return Value: NT status code.--*/{ // PAGED_CODE(); ASSERT(Object); if (IsEqualGUIDAligned(Interface, IID_IUnknown)) { *Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLICSTREAM(this))); } else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclicStream)) { *Object = PVOID(PMINIPORTWAVECYCLICSTREAM(this)); } else if (IsEqualGUIDAligned(Interface, IID_IDmaChannel)) { *Object = PVOID(PDMACHANNEL(this)); } else { *Object = NULL; } if (*Object) { PUNKNOWN(*Object)->AddRef(); return STATUS_SUCCESS; } return STATUS_INVALID_PARAMETER;} // NonDelegatingQueryInterface //=============================================================================STDMETHODIMP CMiniportWaveCyclicStream::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) { // Get the current time ULONGLONG CurrentTime = KeQueryInterruptTime(); // Calculate the time elapsed since the last call to GetPosition() or since the // DMA engine started. Note that the division by 10000 to convert to milliseconds // may cause us to lose some of the time, so we will carry the remainder forward // to the next GetPosition() call. ULONG TimeElapsedInMS = ((ULONG) (CurrentTime - m_ullDmaTimeStamp + m_ullElapsedTimeCarryForward)) / 10000; // Carry forward the remainder of this division so we don't fall behind with our position. m_ullElapsedTimeCarryForward = (CurrentTime - m_ullDmaTimeStamp + m_ullElapsedTimeCarryForward) % 10000; // Calculate how many bytes in the DMA buffer would have been processed in the elapsed // time. Note that the division by 1000 to convert to milliseconds may cause us to // lose some bytes, so we will carry the remainder forward to the next GetPosition() call. ULONG ByteDisplacement = ((m_ulDmaMovementRate * TimeElapsedInMS) + m_ulByteDisplacementCarryForward) / 1000; // Carry forward the remainder of this division so we don't fall behind with our position. m_ulByteDisplacementCarryForward = ((m_ulDmaMovementRate * TimeElapsedInMS) + m_ulByteDisplacementCarryForward) % 1000; // Increment the DMA position by the number of bytes displaced since the last // call to GetPosition() and ensure we properly wrap at buffer length. m_ulDmaPosition = (m_ulDmaPosition + ByteDisplacement) % m_ulDmaBufferSize; // Return the new DMA position *Position = m_ulDmaPosition; // Update the DMA time stamp for the next call to GetPosition() m_ullDmaTimeStamp = CurrentTime; } else { // DMA is inactive so just return the current DMA position. *Position = m_ulDmaPosition; } return STATUS_SUCCESS;} // GetPosition //=============================================================================STDMETHODIMP CMiniportWaveCyclicStream::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.--*/{ ASSERT(PhysicalPosition); *PhysicalPosition = (_100NS_UNITS_PER_SECOND / m_usBlockAlign * *PhysicalPosition) / m_pMiniport->m_SamplingFrequency; return STATUS_SUCCESS;} // NormalizePhysicalPosition //=============================================================================STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclicStream::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(("[CMiniportWaveCyclicStream::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 (STATUS_SUCCESS == ntStatus) { m_usBlockAlign = pWfx->nBlockAlign; m_fFormat16Bit = (pWfx->wBitsPerSample == 16); m_pMiniport->m_SamplingFrequency = pWfx->nSamplesPerSec; m_ulDmaMovementRate = pWfx->nAvgBytesPerSec; DPF(D_TERSE, ("New Format - SpS: %d - BpS: %d - aBypS: %d - C: %d", pWfx->nSamplesPerSec, pWfx->wBitsPerSample, pWfx->nAvgBytesPerSec, pWfx->nChannels)); } KeReleaseMutex(&m_pMiniport->m_SampleRateSync, FALSE); } } return ntStatus;} // SetFormat //=============================================================================STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::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(("[CMiniportWaveCyclicStream::SetNotificationFreq]")); m_pMiniport->m_NotificationInterval = Interval; *FramingSize = m_usBlockAlign * m_pMiniport->m_SamplingFrequency * Interval / 1000; return m_pMiniport->m_NotificationInterval;} // SetNotificationFreq //=============================================================================STDMETHODIMP CMiniportWaveCyclicStream::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(("[CMiniportWaveCyclicStream::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_ullElapsedTimeCarryForward = 0; 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; m_ullElapsedTimeCarryForward = 0; m_ulByteDisplacementCarryForward = 0; KeCancelTimer(m_pTimer); // Wait until all work items are completed. if (!m_fCapture) { if (g_UseIVSHMEM) { m_IVSHMEMSaveData.WaitAllWorkItems(); } else { m_SaveData.WaitAllWorkItems(); } } break; } m_ksState = NewState; } return ntStatus;} // SetState //=============================================================================STDMETHODIMP_(void) CMiniportWaveCyclicStream::Silence( __out_bcount(ByteCount) 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:Lines 1–500 of 861. Load more
/*++ Copyright (c) 1997-2000 Microsoft Corporation All Rights Reserved Module Name: minstream.cpp Abstract: Implementation of wavecyclic stream. --*/ #pragma warning (disable : 4127) #include "scream.h" #include "common.h" #include "minwave.h" #include "minstream.h" #include "wavtable.h" #include <stdlib.h> #define SILENCE_SAMPLE_LEVEL 5 // #pragma code_seg("PAGE") //============================================================================= // CMiniportWaveStreamCyclic //============================================================================= CMiniportWaveCyclicStream::CMiniportWaveCyclicStream(PUNKNOWN other) : CUnknown(other) { // PAGED_CODE(); m_pMiniport = NULL; m_fCapture = FALSE; m_fFormat16Bit = FALSE; m_usBlockAlign = 0; m_ksState = KSSTATE_STOP; m_ulPin = (ULONG)-1; m_pDpc = NULL; m_pTimer = NULL; m_fDmaActive = FALSE; m_ulDmaPosition = 0; m_ullElapsedTimeCarryForward = 0; m_ulByteDisplacementCarryForward = 0; m_pvDmaBuffer = NULL; m_ulDmaBufferSize = 0; m_ulDmaMovementRate = 0; m_ullDmaTimeStamp = 0; m_silenceState = 0; } //============================================================================= CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream(void) /*++ Routine Description: Destructor for wavecyclicstream Arguments: Return Value: NT status code. --*/ { // PAGED_CODE(); DPF_ENTER(("[CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream]")); if (m_pTimer) { KeCancelTimer(m_pTimer); ExFreePoolWithTag(m_pTimer, MSVAD_POOLTAG); } if (m_pDpc) { ExFreePoolWithTag( m_pDpc, MSVAD_POOLTAG ); } // Free the DMA buffer FreeBuffer(); if (NULL != m_pMiniport) { if (m_fCapture) { m_pMiniport->m_fCaptureAllocated = FALSE; } else { m_pMiniport->m_fRenderAllocated = FALSE; } } } // ~CMiniportWaveCyclicStream //============================================================================= NTSTATUS CMiniportWaveCyclicStream::Init( IN PCMiniportWaveCyclic Miniport_, IN ULONG Pin_, IN BOOLEAN Capture_, IN PKSDATAFORMAT DataFormat_ ) /*++ Routine Description: Initializes the stream object. Allocate a DMA buffer, timer and DPC Arguments: Miniport_ - Pin_ - Capture_ - DataFormat - DmaChannel_ - Return Value: NT status code. --*/ { // PAGED_CODE(); 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_usBlockAlign = pWfx->nBlockAlign; m_fFormat16Bit = (pWfx->wBitsPerSample == 16); m_bitsPerSample = pWfx->wBitsPerSample; m_bChannels = (BYTE)(pWfx->nChannels); m_ksState = KSSTATE_STOP; m_ulDmaPosition = 0; m_ullElapsedTimeCarryForward = 0; m_ulByteDisplacementCarryForward = 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) { if (NT_SUCCESS(ntStatus)) { DWORD dwChannelMask = KSAUDIO_SPEAKER_STEREO; if ((pWfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) && (pWfx->cbSize == CB_EXTENSIBLE)) { WAVEFORMATEXTENSIBLE* pWfxT = (WAVEFORMATEXTENSIBLE*)pWfx; dwChannelMask = pWfxT->dwChannelMask; } if (g_UseIVSHMEM) { ntStatus = m_IVSHMEMSaveData.Initialize(pWfx->nSamplesPerSec, pWfx->wBitsPerSample, pWfx->nChannels, dwChannelMask); } else { ntStatus = m_SaveData.Initialize(pWfx->nSamplesPerSec, pWfx->wBitsPerSample, pWfx->nChannels, dwChannelMask); } } } } // 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 (STATUS_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 //============================================================================= STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclicStream::NonDelegatingQueryInterface( IN REFIID Interface, OUT PVOID * Object ) /*++ Routine Description: QueryInterface Arguments: Interface - GUID Object - interface pointer to be returned Return Value: NT status code. --*/ { // PAGED_CODE(); ASSERT(Object); if (IsEqualGUIDAligned(Interface, IID_IUnknown)) { *Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLICSTREAM(this))); } else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclicStream)) { *Object = PVOID(PMINIPORTWAVECYCLICSTREAM(this)); } else if (IsEqualGUIDAligned(Interface, IID_IDmaChannel)) { *Object = PVOID(PDMACHANNEL(this)); } else { *Object = NULL; } if (*Object) { PUNKNOWN(*Object)->AddRef(); return STATUS_SUCCESS; } return STATUS_INVALID_PARAMETER; } // NonDelegatingQueryInterface //============================================================================= STDMETHODIMP CMiniportWaveCyclicStream::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) { // Get the current time ULONGLONG CurrentTime = KeQueryInterruptTime(); // Calculate the time elapsed since the last call to GetPosition() or since the // DMA engine started. Note that the division by 10000 to convert to milliseconds // may cause us to lose some of the time, so we will carry the remainder forward // to the next GetPosition() call. ULONG TimeElapsedInMS = ((ULONG) (CurrentTime - m_ullDmaTimeStamp + m_ullElapsedTimeCarryForward)) / 10000; // Carry forward the remainder of this division so we don't fall behind with our position. m_ullElapsedTimeCarryForward = (CurrentTime - m_ullDmaTimeStamp + m_ullElapsedTimeCarryForward) % 10000; // Calculate how many bytes in the DMA buffer would have been processed in the elapsed // time. Note that the division by 1000 to convert to milliseconds may cause us to // lose some bytes, so we will carry the remainder forward to the next GetPosition() call. ULONG ByteDisplacement = ((m_ulDmaMovementRate * TimeElapsedInMS) + m_ulByteDisplacementCarryForward) / 1000; // Carry forward the remainder of this division so we don't fall behind with our position. m_ulByteDisplacementCarryForward = ((m_ulDmaMovementRate * TimeElapsedInMS) + m_ulByteDisplacementCarryForward) % 1000; // Increment the DMA position by the number of bytes displaced since the last // call to GetPosition() and ensure we properly wrap at buffer length. m_ulDmaPosition = (m_ulDmaPosition + ByteDisplacement) % m_ulDmaBufferSize; // Return the new DMA position *Position = m_ulDmaPosition; // Update the DMA time stamp for the next call to GetPosition() m_ullDmaTimeStamp = CurrentTime; } else { // DMA is inactive so just return the current DMA position. *Position = m_ulDmaPosition; } return STATUS_SUCCESS; } // GetPosition //============================================================================= STDMETHODIMP CMiniportWaveCyclicStream::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. --*/ { ASSERT(PhysicalPosition); *PhysicalPosition = (_100NS_UNITS_PER_SECOND / m_usBlockAlign * *PhysicalPosition) / m_pMiniport->m_SamplingFrequency; return STATUS_SUCCESS; } // NormalizePhysicalPosition //============================================================================= STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclicStream::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(("[CMiniportWaveCyclicStream::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 (STATUS_SUCCESS == ntStatus) { m_usBlockAlign = pWfx->nBlockAlign; m_fFormat16Bit = (pWfx->wBitsPerSample == 16); m_pMiniport->m_SamplingFrequency = pWfx->nSamplesPerSec; m_ulDmaMovementRate = pWfx->nAvgBytesPerSec; DPF(D_TERSE, ("New Format - SpS: %d - BpS: %d - aBypS: %d - C: %d", pWfx->nSamplesPerSec, pWfx->wBitsPerSample, pWfx->nAvgBytesPerSec, pWfx->nChannels)); } KeReleaseMutex(&m_pMiniport->m_SampleRateSync, FALSE); } } return ntStatus; } // SetFormat //============================================================================= STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::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(("[CMiniportWaveCyclicStream::SetNotificationFreq]")); m_pMiniport->m_NotificationInterval = Interval; *FramingSize = m_usBlockAlign * m_pMiniport->m_SamplingFrequency * Interval / 1000; return m_pMiniport->m_NotificationInterval; } // SetNotificationFreq //============================================================================= STDMETHODIMP CMiniportWaveCyclicStream::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(("[CMiniportWaveCyclicStream::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_ullElapsedTimeCarryForward = 0; 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; m_ullElapsedTimeCarryForward = 0; m_ulByteDisplacementCarryForward = 0; KeCancelTimer(m_pTimer); // Wait until all work items are completed. if (!m_fCapture) { if (g_UseIVSHMEM) { m_IVSHMEMSaveData.WaitAllWorkItems(); } else { m_SaveData.WaitAllWorkItems(); } } break; } m_ksState = NewState; } return ntStatus; } // SetState //============================================================================= STDMETHODIMP_(void) CMiniportWaveCyclicStream::Silence( __out_bcount(ByteCount) 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: