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

📄 dsound_wrapper.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * $Id: dsound_wrapper.c,v 1.1.1.1.2.11 2003/09/07 13:04:53 rossbencina Exp $
 * Simplified DirectSound interface.
 *
 * Author: Phil Burk & Robert Marsanyi
 *
 * PortAudio Portable Real-Time Audio Library
 * For more information see: http://www.softsynth.com/portaudio/
 * DirectSound Implementation
 * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * Any person wishing to distribute modifications to the Software is
 * requested to send the modifications to the original developer so that
 * they can be incorporated into the canonical version.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "dsound_wrapper.h"
#include "pa_trace.h"

/*
    Rather than linking with dxguid.a or using "#define INITGUID" to force a
    header file to instantiate the required GUID(s), we define them directly
    below.
*/
#include <initguid.h> // needed for the DEFINE_GUID macro
DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16);


/************************************************************************************/
DSoundEntryPoints dswDSoundEntryPoints = { 0, 0, 0, 0, 0, 0, 0 };
/************************************************************************************/
static HRESULT WINAPI DummyDirectSoundCreate(LPGUID lpcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter)
{
    (void)lpcGuidDevice; /* unused parameter */
    (void)ppDS; /* unused parameter */
    (void)pUnkOuter; /* unused parameter */
    return E_NOTIMPL;
}

static HRESULT WINAPI DummyDirectSoundEnumerateW(LPDSENUMCALLBACKW lpDSEnumCallback, LPVOID lpContext)
{
    (void)lpDSEnumCallback; /* unused parameter */
    (void)lpContext; /* unused parameter */
    return E_NOTIMPL;
}

static HRESULT WINAPI DummyDirectSoundEnumerateA(LPDSENUMCALLBACKA lpDSEnumCallback, LPVOID lpContext)
{
    (void)lpDSEnumCallback; /* unused parameter */
    (void)lpContext; /* unused parameter */
    return E_NOTIMPL;
}

static HRESULT WINAPI DummyDirectSoundCaptureCreate(LPGUID lpcGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter)
{
    (void)lpcGUID; /* unused parameter */
    (void)lplpDSC; /* unused parameter */
    (void)pUnkOuter; /* unused parameter */
    return E_NOTIMPL;
}

static HRESULT WINAPI DummyDirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW lpDSCEnumCallback, LPVOID lpContext)
{
    (void)lpDSCEnumCallback; /* unused parameter */
    (void)lpContext; /* unused parameter */
    return E_NOTIMPL;
}

static HRESULT WINAPI DummyDirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA lpDSCEnumCallback, LPVOID lpContext)
{
    (void)lpDSCEnumCallback; /* unused parameter */
    (void)lpContext; /* unused parameter */
    return E_NOTIMPL;
}

#ifndef _T
#   define _T(s)    s
#endif

/************************************************************************************/
void DSW_InitializeDSoundEntryPoints(void)
{
    dswDSoundEntryPoints.hInstance_ = LoadLibrary(_T("dsound.dll"));
    if( dswDSoundEntryPoints.hInstance_ != NULL )
    {
        dswDSoundEntryPoints.DirectSoundCreate =
                (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN))
                GetProcAddress( dswDSoundEntryPoints.hInstance_, _T("DirectSoundCreate") );
        if( dswDSoundEntryPoints.DirectSoundCreate == NULL )
            dswDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;

        dswDSoundEntryPoints.DirectSoundEnumerateW =
                (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
                GetProcAddress( dswDSoundEntryPoints.hInstance_, _T("DirectSoundEnumerateW") );
        if( dswDSoundEntryPoints.DirectSoundEnumerateW == NULL )
            dswDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;

        dswDSoundEntryPoints.DirectSoundEnumerateA =
                (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))
                GetProcAddress( dswDSoundEntryPoints.hInstance_, _T("DirectSoundEnumerateA") );
        if( dswDSoundEntryPoints.DirectSoundEnumerateA == NULL )
            dswDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;

        dswDSoundEntryPoints.DirectSoundCaptureCreate =
                (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN))
                GetProcAddress( dswDSoundEntryPoints.hInstance_, _T("DirectSoundCaptureCreate") );
        if( dswDSoundEntryPoints.DirectSoundCaptureCreate == NULL )
            dswDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;

        dswDSoundEntryPoints.DirectSoundCaptureEnumerateW =
                (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
                GetProcAddress( dswDSoundEntryPoints.hInstance_, _T("DirectSoundCaptureEnumerateW") );
        if( dswDSoundEntryPoints.DirectSoundCaptureEnumerateW == NULL )
            dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;

        dswDSoundEntryPoints.DirectSoundCaptureEnumerateA =
                (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))
                GetProcAddress( dswDSoundEntryPoints.hInstance_, _T("DirectSoundCaptureEnumerateA") );
        if( dswDSoundEntryPoints.DirectSoundCaptureEnumerateA == NULL )
            dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;
    }
    else
    {
        /* initialize with dummy entry points to make live easy when ds isn't present */
        dswDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;
        dswDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;
        dswDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;
        dswDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;
        dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;
        dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;
    }
}
/************************************************************************************/
void DSW_TerminateDSoundEntryPoints(void)
{
    if( dswDSoundEntryPoints.hInstance_ != NULL )
    {
        FreeLibrary( dswDSoundEntryPoints.hInstance_ );
        dswDSoundEntryPoints.hInstance_ = NULL;
        /* ensure that we crash reliably if the entry points arent initialised */
        dswDSoundEntryPoints.DirectSoundCreate = 0;
        dswDSoundEntryPoints.DirectSoundEnumerateW = 0;
        dswDSoundEntryPoints.DirectSoundEnumerateA = 0;
        dswDSoundEntryPoints.DirectSoundCaptureCreate = 0;
        dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = 0;
        dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = 0;
    }
}
/************************************************************************************/
void DSW_Term( DSoundWrapper *dsw )
{
    // Cleanup the sound buffers
    if (dsw->dsw_OutputBuffer)
    {
        IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );
        IDirectSoundBuffer_Release( dsw->dsw_OutputBuffer );
        dsw->dsw_OutputBuffer = NULL;
    }

    if (dsw->dsw_InputBuffer)
    {
        IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );
        IDirectSoundCaptureBuffer_Release( dsw->dsw_InputBuffer );
        dsw->dsw_InputBuffer = NULL;
    }

    if (dsw->dsw_pDirectSoundCapture)
    {
        IDirectSoundCapture_Release( dsw->dsw_pDirectSoundCapture );
        dsw->dsw_pDirectSoundCapture = NULL;
    }

    if (dsw->dsw_pDirectSound)
    {
        IDirectSound_Release( dsw->dsw_pDirectSound );
        dsw->dsw_pDirectSound = NULL;
    }
}
/************************************************************************************/
HRESULT DSW_Init( DSoundWrapper *dsw )
{
    memset( dsw, 0, sizeof(DSoundWrapper) );
    return 0;
}
/************************************************************************************/
HRESULT DSW_InitOutputDevice( DSoundWrapper *dsw, LPGUID lpGUID )
{
    // Create the DS object
    HRESULT hr = dswDSoundEntryPoints.DirectSoundCreate( lpGUID, &dsw->dsw_pDirectSound, NULL );
    if( hr != DS_OK ) return hr;
    return hr;
}

/************************************************************************************/
HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer )
{
    DWORD          dwDataLen;
    DWORD          playCursor;
    HRESULT        result;
    LPDIRECTSOUNDBUFFER pPrimaryBuffer;
    HWND           hWnd;
    HRESULT        hr;
    WAVEFORMATEX   wfFormat;
    DSBUFFERDESC   primaryDesc;
    DSBUFFERDESC   secondaryDesc;
    unsigned char* pDSBuffData;
    LARGE_INTEGER  counterFrequency;

    dsw->dsw_OutputSize = bytesPerBuffer;
    dsw->dsw_OutputRunning = FALSE;
    dsw->dsw_OutputUnderflows = 0;
    dsw->dsw_FramesWritten = 0;
    dsw->dsw_BytesPerOutputFrame = nChannels * sizeof(short);

    // We were using getForegroundWindow() but sometimes the ForegroundWindow may not be the
    // applications's window. Also if that window is closed before the Buffer is closed
    // then DirectSound can crash. (Thanks for Scott Patterson for reporting this.)
    // So we will use GetDesktopWindow() which was suggested by Miller Puckette.
    // hWnd = GetForegroundWindow();
    //
    //  FIXME: The example code I have on the net creates a hidden window that
    //      is managed by our code - I think we should do that - one hidden
    //      window for the whole of Pa_DS
    //
    hWnd = GetDesktopWindow();

    // Set cooperative level to DSSCL_EXCLUSIVE so that we can get 16 bit output, 44.1 KHz.
    // Exclusize also prevents unexpected sounds from other apps during a performance.
    if ((hr = IDirectSound_SetCooperativeLevel( dsw->dsw_pDirectSound,
              hWnd, DSSCL_EXCLUSIVE)) != DS_OK)
    {
        return hr;
    }

    // -----------------------------------------------------------------------
    // Create primary buffer and set format just so we can specify our custom format.
    // Otherwise we would be stuck with the default which might be 8 bit or 22050 Hz.
    // Setup the primary buffer description
    ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC));
    primaryDesc.dwSize        = sizeof(DSBUFFERDESC);
    primaryDesc.dwFlags       = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth
    primaryDesc.dwBufferBytes = 0;
    primaryDesc.lpwfxFormat   = NULL;
    // Create the buffer
    if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound,
                  &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK) return result;
    // 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. */
    // Set the primary buffer's format
    if((result = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &wfFormat)) != DS_OK) return result;

    // ----------------------------------------------------------------------
    // Setup the secondary buffer description
    ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC));
    secondaryDesc.dwSize = sizeof(DSBUFFERDESC);
    secondaryDesc.dwFlags =  DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
    secondaryDesc.dwBufferBytes = bytesPerBuffer;
    secondaryDesc.lpwfxFormat = &wfFormat;
    // Create the secondary buffer
    if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound,
                  &secondaryDesc, &dsw->dsw_OutputBuffer, NULL)) != DS_OK) return result;
    // Lock the DS buffer
    if ((result = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, 0, dsw->dsw_OutputSize, (LPVOID*)&pDSBuffData,
                                           &dwDataLen, NULL, 0, 0)) != DS_OK) return result;
    // Zero the DS buffer
    ZeroMemory(pDSBuffData, dwDataLen);
    // Unlock the DS buffer
    if ((result = IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) return result;
    if( QueryPerformanceFrequency( &counterFrequency ) )
    {
        int framesInBuffer = bytesPerBuffer / (nChannels * sizeof(short));
        dsw->dsw_CounterTicksPerBuffer.QuadPart = (counterFrequency.QuadPart * framesInBuffer) / nFrameRate;
    }
    else
    {
        dsw->dsw_CounterTicksPerBuffer.QuadPart = 0;
    }
    // Let DSound set the starting write position because if we set it to zero, it looks like the
    // buffer is full to begin with. This causes a long pause before sound starts when using large buffers.
    hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &dsw->dsw_WriteOffset );
    if( hr != DS_OK )
    {

⌨️ 快捷键说明

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