我正在构建一个播放'.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()函数,但这会导致应用程序冻结。为什么会这样?当缓冲区仍在队列中进行播放时,是否有其他方法可以停止播放。
答案 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之类的功能可能会引起严重的问题。