waveOutOpen()API中的回调函数

时间:2012-04-03 04:07:27

标签: visual-c++ mfc wav

我正在构建一个播放'.wav'文件的音频播放器,我对从waveOutOpen()API调用的回调函数有疑问。

打开输出音频设备进行播放:

 MMRESULT mRes = waveOutOpen(m_hWO,WAVE_MAPPER,&wFmt,(DWORD)&waveOutProc,(DWORD)this, CALLBACK_FUNCTION);

回调函数的实现:

void CPlayWave::waveOutProc(HWAVEOUT m_hWO,UINT uMsg,DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
    MMRESULT mmRes;
    CPlayWave *pPW = (CPlayWave*)dwInstance;
    switch(uMsg)
    {
    case MM_WOM_DONE:       //playback finished
        mmRes = waveOutUnprepareHeader(m_hWO, &pPW->m_WHdr, sizeof(WAVEHDR));
        if(mmRes!=MMSYSERR_NOERROR)
        {
            //error handling
            .....
        }
        mmRes = waveOutClose(m_hWO);
        if(mmRes!=MMSYSERR_NOERROR)
        {
            //error handling
            .....
        }
        AfxMessageBox("Finished playing the file");
        m_bPlay = FALSE;      //boolean flag used for pausing
        break;
    case WIM_DATA:
        //for recording completion
        break;
    }
}

问题是MM_WOM_DONE永远不会发生,并且在文件播放完成后永远不会调用回调函数。如果必须使用线程而不是回调函数,有人可以给我一个关于如何使用回调线程的简单示例(在网上找不到)。

waveOutReset()文档还建议它关闭所有缓冲区并返回系统,因此为了处理我的应用程序中的Stop按钮,我使用了waveOutReset()函数,但这会导致应用程序冻结。为什么会这样?当缓冲区仍在队列中进行播放时,是否有其他方法可以停止播放。

2 个答案:

答案 0 :(得分:1)

回调函数可能不是您的类CPlayWave本身的方法。它必须是一个简单的功能,而不是你的原型。

void CALLBACK waveOutProc(HWAVEOUT m_hWO, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
  ...
}

当然,在调用waveOutOpen()之前,必须声明/定义它。另外,函数名称是指针本身和&符号。不需要。因此,调用waveOutOpen()应该是:

MMRESULT mRes = waveOutOpen(m_hWO, WAVE_MAPPER, &wFmt, (DWORD_PTR) waveOutProc, (DWORD_PTR) this, CALLBACK_FUNCTION | WAVE_ALLOWSYNC);

答案 1 :(得分:0)

另外,您只能从waveOutProc调用系统功能:

“应用程序不应从回调函数内部调用任何系统定义的函数,但EnterCriticalSection,LeaveCriticalSection,midiOutLongMsg,midiOutShortMsg,OutputDebugString,PostMessage,PostThreadMessage,SetEvent,timeGetSystemTime,timeGetTime,timeKillEvent和timeSetEvent除外。调用其他wave函数会导致死锁。”

因此,调用诸如AfxMessageBox或waveOutUnprepareHeader之类的功能可能会引起严重的问题。