⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 basewave.cpp

📁 在微软例子下实现的虚拟声卡,实现了各种接口,是学习的一个好例子
💻 CPP
📖 第 1 页 / 共 2 页
字号:

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 + -