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

📄 dsound_wrapper.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 2 页
字号:
        return hr;
    }
    dsw->dsw_FramesWritten = dsw->dsw_WriteOffset / dsw->dsw_BytesPerOutputFrame;
    /* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */
    return DS_OK;
}

/************************************************************************************/
HRESULT DSW_StartOutput( DSoundWrapper *dsw )
{
    HRESULT        hr;
    QueryPerformanceCounter( &dsw->dsw_LastPlayTime );
    dsw->dsw_LastPlayCursor = 0;
    dsw->dsw_FramesPlayed = 0;
    hr = IDirectSoundBuffer_SetCurrentPosition( dsw->dsw_OutputBuffer, 0 );
    if( hr != DS_OK )
    {
        return hr;
    }
    // Start the buffer playback in a loop.
    if( dsw->dsw_OutputBuffer != NULL )
    {
        hr = IDirectSoundBuffer_Play( dsw->dsw_OutputBuffer, 0, 0, DSBPLAY_LOOPING );
        if( hr != DS_OK )
        {
            return hr;
        }
        dsw->dsw_OutputRunning = TRUE;
    }

    return 0;
}
/************************************************************************************/
HRESULT DSW_StopOutput( DSoundWrapper *dsw )
{
    // Stop the buffer playback
    if( dsw->dsw_OutputBuffer != NULL )
    {
        dsw->dsw_OutputRunning = FALSE;
        return IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );
    }
    else return 0;
}

/************************************************************************************/
HRESULT DSW_QueryOutputFilled( DSoundWrapper *dsw, long *bytesFilledPtr )
{
    HRESULT hr;
    DWORD   playCursor;
    DWORD   writeCursor;
    long    bytesFilled;
    // Query to see where play position is.
    // We don't need the writeCursor but sometimes DirectSound doesn't handle NULLS correctly
    // so let's pass a pointer just to be safe.
    hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );
    if( hr != DS_OK )
    {
        return hr;
    }
    bytesFilled = dsw->dsw_WriteOffset - playCursor;
    if( bytesFilled < 0 ) bytesFilled += dsw->dsw_OutputSize; // unwrap offset
    *bytesFilledPtr = bytesFilled;
    return hr;
}

/************************************************************************************
 * Determine how much space can be safely written to in DS buffer.
 * Detect underflows and overflows.
 * Does not allow writing into safety gap maintained by DirectSound.
 */
HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty )
{
    HRESULT hr;
    DWORD   playCursor;
    DWORD   writeCursor;
    long    numBytesEmpty;
    long    playWriteGap;
    // Query to see how much room is in buffer.
    hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );
    if( hr != DS_OK )
    {
        return hr;
    }
    // Determine size of gap between playIndex and WriteIndex that we cannot write into.
    playWriteGap = writeCursor - playCursor;
    if( playWriteGap < 0 ) playWriteGap += dsw->dsw_OutputSize; // unwrap
    /* DirectSound doesn't have a large enough playCursor so we cannot detect wrap-around. */
    /* Attempt to detect playCursor wrap-around and correct it. */
    if( dsw->dsw_OutputRunning && (dsw->dsw_CounterTicksPerBuffer.QuadPart != 0) )
    {
        /* How much time has elapsed since last check. */
        LARGE_INTEGER   currentTime;
        LARGE_INTEGER   elapsedTime;
        long            bytesPlayed;
        long            bytesExpected;
        long            buffersWrapped;
        QueryPerformanceCounter( &currentTime );
        elapsedTime.QuadPart = currentTime.QuadPart - dsw->dsw_LastPlayTime.QuadPart;
        dsw->dsw_LastPlayTime = currentTime;
        /* How many bytes does DirectSound say have been played. */
        bytesPlayed = playCursor - dsw->dsw_LastPlayCursor;
        if( bytesPlayed < 0 ) bytesPlayed += dsw->dsw_OutputSize; // unwrap
        dsw->dsw_LastPlayCursor = playCursor;
        /* Calculate how many bytes we would have expected to been played by now. */
        bytesExpected = (long) ((elapsedTime.QuadPart * dsw->dsw_OutputSize) / dsw->dsw_CounterTicksPerBuffer.QuadPart);
        buffersWrapped = (bytesExpected - bytesPlayed) / dsw->dsw_OutputSize;
        if( buffersWrapped > 0 )
        {
            playCursor += (buffersWrapped * dsw->dsw_OutputSize);
            bytesPlayed += (buffersWrapped * dsw->dsw_OutputSize);
        }
        /* Maintain frame output cursor. */
        dsw->dsw_FramesPlayed += (bytesPlayed / dsw->dsw_BytesPerOutputFrame);
    }
    numBytesEmpty = playCursor - dsw->dsw_WriteOffset;
    if( numBytesEmpty < 0 ) numBytesEmpty += dsw->dsw_OutputSize; // unwrap offset
    /* Have we underflowed? */
    if( numBytesEmpty > (dsw->dsw_OutputSize - playWriteGap) )
    {
        if( dsw->dsw_OutputRunning )
        {
            dsw->dsw_OutputUnderflows += 1;
        }
        dsw->dsw_WriteOffset = writeCursor;
        numBytesEmpty = dsw->dsw_OutputSize - playWriteGap;
    }
    *bytesEmpty = numBytesEmpty;
    return hr;
}

/************************************************************************************/
HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw )
{
    HRESULT hr;
    LPBYTE lpbuf1 = NULL;
    LPBYTE lpbuf2 = NULL;
    DWORD dwsize1 = 0;
    DWORD dwsize2 = 0;
    long  bytesEmpty;
    hr = DSW_QueryOutputSpace( dsw, &bytesEmpty ); // updates dsw_FramesPlayed
    if (hr != DS_OK) return hr;
    if( bytesEmpty == 0 ) return DS_OK;
    // Lock free space in the DS
    hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, bytesEmpty, (void **) &lpbuf1, &dwsize1,
                                  (void **) &lpbuf2, &dwsize2, 0);
    if (hr == DS_OK)
    {
        // Copy the buffer into the DS
        ZeroMemory(lpbuf1, dwsize1);
        if(lpbuf2 != NULL)
        {
            ZeroMemory(lpbuf2, dwsize2);
        }
        // Update our buffer offset and unlock sound buffer
        dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;
        IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
        dsw->dsw_FramesWritten += bytesEmpty / dsw->dsw_BytesPerOutputFrame;
    }
    return hr;
}

/************************************************************************************/
HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes )
{
    HRESULT hr;
    LPBYTE lpbuf1 = NULL;
    LPBYTE lpbuf2 = NULL;
    DWORD dwsize1 = 0;
    DWORD dwsize2 = 0;
    // Lock free space in the DS
    hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, numBytes, (void **) &lpbuf1, &dwsize1,
                                  (void **) &lpbuf2, &dwsize2, 0);
    if (hr == DS_OK)
    {
        // Copy the buffer into the DS
        CopyMemory(lpbuf1, buf, dwsize1);
        if(lpbuf2 != NULL)
        {
            CopyMemory(lpbuf2, buf+dwsize1, dwsize2);
        }
        // Update our buffer offset and unlock sound buffer
        dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;
        IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
        dsw->dsw_FramesWritten += numBytes / dsw->dsw_BytesPerOutputFrame;
    }
    return hr;
}

/************************************************************************************/
DWORD DSW_GetOutputStatus( DSoundWrapper *dsw )
{
    DWORD status;
    if (IDirectSoundBuffer_GetStatus( dsw->dsw_OutputBuffer, &status ) != DS_OK)
        return( DSERR_INVALIDPARAM );
    else
        return( status );
}

/* These routines are used to support audio input.
 * Do NOT compile these calls when using NT4 because it does
 * not support the entry points.
 */
/************************************************************************************/
HRESULT DSW_InitInputDevice( DSoundWrapper *dsw, LPGUID lpGUID )
{
    HRESULT hr = dswDSoundEntryPoints.DirectSoundCaptureCreate(  lpGUID, &dsw->dsw_pDirectSoundCapture,   NULL );
    if( hr != DS_OK ) return hr;
    return hr;
}
/************************************************************************************/
HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer )
{
    DSCBUFFERDESC  captureDesc;
    WAVEFORMATEX   wfFormat;
    HRESULT        result;
    
    dsw->dsw_BytesPerInputFrame = nChannels * sizeof(short);

    // Define the buffer format
    wfFormat.wFormatTag      = WAVE_FORMAT_PCM;
    wfFormat.nChannels       = nChannels;
    wfFormat.nSamplesPerSec  = nFrameRate;
    wfFormat.wBitsPerSample  = 8 * sizeof(short);
    wfFormat.nBlockAlign     = (WORD)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));
    wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
    wfFormat.cbSize          = 0;   /* No extended format info. */
    dsw->dsw_InputSize = bytesPerBuffer;
    // ----------------------------------------------------------------------
    // Setup the secondary buffer description
    ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));
    captureDesc.dwSize = sizeof(DSCBUFFERDESC);
    captureDesc.dwFlags =  0;
    captureDesc.dwBufferBytes = bytesPerBuffer;
    captureDesc.lpwfxFormat = &wfFormat;
    // Create the capture buffer
    if ((result = IDirectSoundCapture_CreateCaptureBuffer( dsw->dsw_pDirectSoundCapture,
                  &captureDesc, &dsw->dsw_InputBuffer, NULL)) != DS_OK) return result;
    dsw->dsw_ReadOffset = 0;  // reset last read position to start of buffer
    return DS_OK;
}

/************************************************************************************/
HRESULT DSW_StartInput( DSoundWrapper *dsw )
{
    // Start the buffer playback
    if( dsw->dsw_InputBuffer != NULL )
    {
        return IDirectSoundCaptureBuffer_Start( dsw->dsw_InputBuffer, DSCBSTART_LOOPING );
    }
    else return 0;
}

/************************************************************************************/
HRESULT DSW_StopInput( DSoundWrapper *dsw )
{
    // Stop the buffer playback
    if( dsw->dsw_InputBuffer != NULL )
    {
        return IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );
    }
    else return 0;
}

/************************************************************************************/
HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled )
{
    HRESULT hr;
    DWORD capturePos;
    DWORD readPos;
    long  filled;
    // Query to see how much data is in buffer.
    // We don't need the capture position but sometimes DirectSound doesn't handle NULLS correctly
    // so let's pass a pointer just to be safe.
    hr = IDirectSoundCaptureBuffer_GetCurrentPosition( dsw->dsw_InputBuffer, &capturePos, &readPos );
    if( hr != DS_OK )
    {
        return hr;
    }
    filled = readPos - dsw->dsw_ReadOffset;
    if( filled < 0 ) filled += dsw->dsw_InputSize; // unwrap offset
    *bytesFilled = filled;
    return hr;
}

/************************************************************************************/
HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes )
{
    HRESULT hr;
    LPBYTE lpbuf1 = NULL;
    LPBYTE lpbuf2 = NULL;
    DWORD dwsize1 = 0;
    DWORD dwsize2 = 0;
    // Lock free space in the DS
    hr = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer, dsw->dsw_ReadOffset, numBytes, (void **) &lpbuf1, &dwsize1,
                                          (void **) &lpbuf2, &dwsize2, 0);
    if (hr == DS_OK)
    {
        // Copy from DS to the buffer
        CopyMemory( buf, lpbuf1, dwsize1);
        if(lpbuf2 != NULL)
        {
            CopyMemory( buf+dwsize1, lpbuf2, dwsize2);
        }
        // Update our buffer offset and unlock sound buffer
        dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + dwsize1 + dwsize2) % dsw->dsw_InputSize;
        IDirectSoundCaptureBuffer_Unlock ( dsw->dsw_InputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
    }
    return hr;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -