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

📄 audiomanager.cpp

📁 一个WinCE6。0下的IP phone的源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//

#include "AudioManager.hpp"
#include "Common.hpp"
#include "Debug.hpp"

// -----------------------------------------------------------------------------
//                              FileHeader
// -----------------------------------------------------------------------------
typedef struct
{
   DWORD   dwRiff;     // Type of file header.
   DWORD   dwSize;     // Size of file header.
   DWORD   dwWave;     // Type of wave.
} RIFF_FILEHEADER, *PRIFF_FILEHEADER;


// -----------------------------------------------------------------------------
//                              ChunkHeader
// -----------------------------------------------------------------------------
typedef struct
{
   DWORD   dwCKID;        // Type Identification for current chunk header.
   DWORD   dwSize;        // Size of current chunk header.
} RIFF_CHUNKHEADER, *PRIFF_CHUNKHEADER;

/*  Chunk Types  
*/
#define RIFF_FILE       mmioFOURCC('R','I','F','F')
#define RIFF_WAVE       mmioFOURCC('W','A','V','E')
#define RIFF_FORMAT     mmioFOURCC('f','m','t',' ')
#define RIFF_CHANNEL    mmioFOURCC('d','a','t','a')

bool
ReadChunk(
    HANDLE                  FileHandle, 
    DWORD                   ChunkType, 
    __deref_out_opt VOID**  ppBuffer, 
    __out_opt       DWORD*  pSize, 
    __out_opt       DWORD*  pBytesLeft
    )
{ 
    DWORD               BytesRead;
    PVOID               pBuffer;
    RIFF_CHUNKHEADER    Chunk;

    if ((!pBytesLeft) || (*pBytesLeft <= 0) || (!pSize) || (!ppBuffer)) 
    {
        PHONEAPP_DEBUGMSG(ZONE_PHONEAPP_ERROR, (L"Invalid parameter to ReadChunk()\r\n"));
        return false;
    }

    // now scan for the format chunk
    while (*pBytesLeft > 0) 
    {
        // now read the wave header (or what we hope is the wave header)
        if (! ReadFile(
                FileHandle, 
                &Chunk, 
                sizeof(Chunk), 
                &BytesRead, 
                NULL) || 
                BytesRead < sizeof(Chunk)
                ) 
        {
            PHONEAPP_DEBUGMSG(ZONE_PHONEAPP_ERROR, (L"Error reading chunk header\n"));
            return false;
        }
        
        *pBytesLeft -= BytesRead;
        PHONEAPP_DEBUGMSG(ZONE_PHONEAPP_ERROR, (L"Chunk: \"%c%c%c%c\" size=0x%08x\r\n", 
            (Chunk.dwCKID >>  0) & 0xff, 
            (Chunk.dwCKID >>  8) & 0xff, 
            (Chunk.dwCKID >> 16) & 0xff, 
            (Chunk.dwCKID >> 24) & 0xff, 
            Chunk.dwSize));
        if (Chunk.dwCKID == ChunkType) {
            // found the desired chunk
            break;
        }
        // skip the data we don't know or care about...
        if (0xFFFFFFFF == SetFilePointer (
                            FileHandle, 
                            Chunk.dwSize, 
                            NULL, 
                            FILE_CURRENT
                            )) 
        {
            PHONEAPP_DEBUGMSG(ZONE_PHONEAPP_ERROR,  (L"Error setting file pointer while scanning for chunk\n"));
            return false;
        }
        *pBytesLeft -= Chunk.dwSize;
    }
    // found the desired chunk.
    // allocate a buffer and read in the data
    pBuffer = new BYTE[Chunk.dwSize];
    if (pBuffer == NULL) {
        PHONEAPP_DEBUGMSG(ZONE_PHONEAPP_ERROR, (L"Unable to allocate chunk buffer\r\n"));
        return false;
    }
    if (! ReadFile(
            FileHandle, 
            pBuffer, 
            Chunk.dwSize, 
            &BytesRead, 
            NULL
            ) || 
            BytesRead < Chunk.dwSize
            ) 
    {
        delete [] pBuffer;
        PHONEAPP_DEBUGMSG(ZONE_PHONEAPP_ERROR, (L"Unable to read chunk data\r\n"));
        return false;
    }
    
    *pBytesLeft -= BytesRead;
    *ppBuffer = pBuffer;
    *pSize = Chunk.dwSize;
    return true;
}

MMRESULT
ReadWaveFile(
    __in        LPCTSTR         pFileName, 
    __deref_out WAVEFORMATEX**  ppWaveFormat, 
    __out       DWORD*          pBufferSize, 
    __deref_out BYTE**          ppBufferBytes
    )
{ 
    RIFF_FILEHEADER FileHeader;
    DWORD           BytesRead;
    DWORD           BufferSize;
    DWORD           FormatSize;
    PBYTE           pBufferBytes = NULL;
    PWAVEFORMATEX   pWaveFormat = NULL;
    DWORD           BytesInChunk;
    HANDLE          FileHandle;
    MMRESULT        MMResult = MMSYSERR_ERROR;

    FileHandle = CreateFile(
                    pFileName, 
                    GENERIC_READ, 
                    FILE_SHARE_READ, 
                    NULL, 
                    OPEN_EXISTING, 
                    0, 
                    NULL
                    );    
    if( FileHandle == INVALID_HANDLE_VALUE ) 
    {
        PHONEAPP_DEBUGMSG(ZONE_PHONEAPP_ERROR, (L"Error opening %s. Error code = 0x%08x\n", pFileName, GetLastError()));
        return MMResult;
    }

    // Read file and determine sound format
    // Start with RIFF header:

    if (! ReadFile(
            FileHandle, 
            &FileHeader, 
            sizeof(FileHeader), 
            &BytesRead, NULL
            ) || 
            BytesRead < sizeof(FileHeader)
            ) 
    {
        PHONEAPP_DEBUGMSG(ZONE_PHONEAPP_ERROR, (L"Error reading file header\n"));
        goto error_exit;
    }

    if ( FileHeader.dwRiff != RIFF_FILE || FileHeader.dwWave != RIFF_WAVE) 
    {
        PHONEAPP_DEBUGMSG(ZONE_PHONEAPP_ERROR, (L"Invalid wave file header\n"));
        goto error_exit;
    }

    BytesInChunk = FileHeader.dwSize;

    // load the wave format
    if (! ReadChunk(
            FileHandle, 
            RIFF_FORMAT, 
            (PVOID*)&pWaveFormat, 
            &FormatSize, 
            &BytesInChunk
            )) 
    {
        PHONEAPP_DEBUGMSG(ZONE_PHONEAPP_ERROR, (L"Unable to read format chunk\r\n"));
        goto error_exit;
    }
    if (FormatSize < sizeof(PCMWAVEFORMAT)) 
    {
        PHONEAPP_DEBUGMSG(ZONE_PHONEAPP_ERROR, (L"Format record too small\r\n"));
        goto error_exit;
    }

    // load the wave data
    if (!ReadChunk(
            FileHandle, 
            RIFF_CHANNEL, 
            (PVOID*) &pBufferBytes, 
            &BufferSize, 
            &BytesInChunk
            )) 
    {
        PHONEAPP_DEBUGMSG(ZONE_PHONEAPP_ERROR, (L"Unable to read format chunk\r\n"));
        goto error_exit;
    }

    *ppWaveFormat   = pWaveFormat;
    *pBufferSize    = BufferSize;
    *ppBufferBytes  = pBufferBytes;

    // Success
    MMResult = MMSYSERR_NOERROR;
    goto exit;

error_exit:
    delete [] pBufferBytes;
    delete [] pWaveFormat;
    
exit:
    CloseHandle(FileHandle);
    return MMResult;   
}

//Paths for progress tones we handle
const WCHAR AudioManager_t::sc_CallWaitingTone[]  = L"\\Windows\\waiting.wav";
const WCHAR AudioManager_t::sc_DialTone[]         = L"\\Windows\\dialtone.wav";
const WCHAR AudioManager_t::sc_ClientBusyTone[]   = L"\\Windows\\busy.wav";
const WCHAR AudioManager_t::sc_ReorderTone[]      = L"\\Windows\\reorder.wav";
const WCHAR AudioManager_t::sc_RingbackTone[]     = L"\\Windows\\ringback.wav";

AudioManager_t::AudioManager_t(
    void
    )
{
    ZeroMemory(&m_RingWaveDataBlockHeader, sizeof(m_RingWaveDataBlockHeader)); 
    ZeroMemory(&m_Lock, sizeof(m_Lock)); 

    m_RingWaveOutHandle     = NULL; 
    m_ProgressToneThreadId  = NULL; 
    m_StopToneEvent         = NULL; 
    m_pProgressTonePath     = NULL; 

    m_RingThreadId          = NULL; 
    m_StopRingEvent         = NULL; 
}

AudioManager_t::~AudioManager_t(
    void
    )
{
    CloseHandle(m_RingThreadId); 
    m_RingThreadId = NULL; 

    CloseHandle(m_StopRingEvent); 
    m_StopRingEvent = NULL; 

    CloseHandle(m_RingWaveOutHandle); 
    m_RingWaveOutHandle = NULL; 

    CloseHandle(m_ProgressToneThreadId); 
    m_ProgressToneThreadId = NULL; 

    CloseHandle(m_StopToneEvent); 
    m_StopToneEvent = NULL; 
    
}

HRESULT
AudioManager_t::Initialize(
    void
    )
{
    m_StopToneEvent = CreateEvent(
                        NULL, 
                        TRUE, 
                        FALSE, 
                        NULL
                        );
    InitializeCriticalSection(&m_Lock);
    m_StopRingEvent = CreateEvent(
                        NULL, 
                        TRUE, 
                        FALSE, 
                        NULL
                        ); 

    if (m_StopToneEvent == NULL || m_StopRingEvent == NULL)
    {
        return E_FAIL; 
    }
    
    return S_OK;
    
}

void
AudioManager_t::Uninitialize(
    void
    )
{
    SetEvent(m_StopToneEvent); 
    if (m_ProgressToneThreadId != NULL)
    {
        WaitForSingleObject(m_ProgressToneThreadId, INFINITE); 
    }

    DeleteCriticalSection(&m_Lock); 

    SetEvent(m_StopRingEvent); 
    if (m_RingThreadId != NULL)
    {
        WaitForSingleObject(m_RingThreadId, INFINITE); 
    }

}

HRESULT
AudioManager_t::PlayProgressTone(
    ProgressToneType_e ProgressToneType
    )
{
    HRESULT hr = S_OK;

    EnterCriticalSection(&m_Lock); 

    //Ensure we are the only progress tone playing
    StopProgressTone();

    if (SUCCEEDED(hr))
    {
        //Set which progress tone to play for this progress tone thread
        switch (ProgressToneType)
        {
        case ProgressToneInvalid:
            hr = E_INVALIDARG;
            break;

        case ProgressToneCallWaiting:
            m_pProgressTonePath = sc_CallWaitingTone;
            break;

        case ProgressToneClientBusy:
            m_pProgressTonePath = sc_ClientBusyTone;
            break;

        case ProgressToneDial:
            m_pProgressTonePath = sc_DialTone;
            break;

        case ProgressToneReorder:
            m_pProgressTonePath = sc_ReorderTone;
            break;

        case ProgressToneRingback:
            m_pProgressTonePath = sc_RingbackTone;
            break;

        default:
            hr = E_NOTIMPL;
            break;
        }
    }

    if (SUCCEEDED(hr))
    {
        //Create a thread that will play the progress tone continuously
        m_ProgressToneThreadId = CreateThread(
            NULL,
            0,
            s_ProgressToneThreadProc,
            static_cast<VOID*>(this), //pass in 'this' as the parameters
            0,
            NULL
            );

        //Make sure the thread was actually started
        if (m_ProgressToneThreadId == NULL)
        {
            hr = CommonUtilities_t::GetErrorFromWin32();
        }
    }

    LeaveCriticalSection(&m_Lock); 
    
    return hr;
}

/*------------------------------------------------------------------------------
    AudioManager_t::s_ProgressToneThreadProc
    
    Static thread proc to play progress tones continually using waveout
    
    Parameters:
        Parameter: This is the instance of the mediamanager packed into a void
------------------------------------------------------------------------------*/
/*static */DWORD WINAPI 
AudioManager_t::s_ProgressToneThreadProc(
    LPVOID Parameter
    )
{
    if (Parameter == NULL)
    {
        ASSERT(FALSE);
        return E_POINTER;
    }

    //Unpack the media manager instance
    AudioManager_t  *pAudioManager  = static_cast<AudioManager_t*>(Parameter);

    //Use the instance to play the progress tone
    return pAudioManager->ProgressToneThreadProc();
}

/*------------------------------------------------------------------------------
    AudioManager_t::ProgressToneThreadProc
    
    Thread Proc that plays a progress tone continuously through waveOutWrite. 
    The tone keeps playing until StopProgressTone is called
------------------------------------------------------------------------------*/
HRESULT AudioManager_t::ProgressToneThreadProc()
{
    MMRESULT     MMResult           = MMSYSERR_NOERROR;
    DWORD        BufferSize         = 0;
    BYTE*        ppBufferBytes      = NULL;
    WAVEFORMATEX* pWaveFormat       = NULL;
    HWAVEOUT     WaveOutHandle      = NULL;
    WAVEHDR      WaveBufferHeader   = {0};
    HANDLE       SoundDoneEvent     = NULL;

    
    //Callback event
    SoundDoneEvent = CreateEvent(
        NULL,
        TRUE,
        FALSE,
        NULL
        );

    //Read the wave file using the helper functions
    MMResult = ReadWaveFile(
                    m_pProgressTonePath, 
                    &pWaveFormat, 
                    &BufferSize, 
                    &ppBufferBytes
                    );
    
    if (MMResult != MMSYSERR_NOERROR)
    {
        goto cleanup; 
    }
    
    //Open the waveout device
    MMResult = waveOutOpen(
                    &WaveOutHandle, //handle to the out wave
                    0,              //unused
                    pWaveFormat,    //the waveformatex struct that contains the wav info
                    reinterpret_cast<DWORD>(SoundDoneEvent),
                    0,   
                    CALLBACK_EVENT  //SoundDoneEvent will be called back when the sound is done being played
                    );

    if (MMResult != MMSYSERR_NOERROR)
    {
        goto cleanup; 
    }
    
    //Prepare the header
    WaveBufferHeader.dwBufferLength = BufferSize;
    //Yes it should be a 'char' even though we are using unicode!
    WaveBufferHeader.lpData         = (char *)ppBufferBytes;
    
    //Inform the wave handle about the header
    MMResult = waveOutPrepareHeader(
                    WaveOutHandle, 
                    &WaveBufferHeader, 
                    sizeof(WaveBufferHeader)
                    );

    if (MMResult != MMSYSERR_NOERROR)
    {
        goto cleanup; 
    }

⌨️ 快捷键说明

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