我对 Microsoft 的 WaveOut API 有疑问:
编辑1:添加到示例项目的链接:编辑2:删除链接,它不代表问题
播放一些音频后,当我想终止给定的播放流时,我调用该函数:
waveOutClose(hWaveOut_);
然而,即使在调用了 waveOutClose() 之后,有时库仍然会访问之前由 waveOutWrite() 传递给它的内存,从而导致无效的内存访问。
然后,我尝试确保在释放缓冲区之前将所有缓冲区标记为已完成:
PcmPlayback::~PcmPlayback()
{
if(hWaveOut_ == nullptr)
return;
waveOutReset(hWaveOut_); // infinite-loops, never returns
for(auto it = buffers_.begin(); it != buffers_.end(); ++it)
waveOutUnprepareHeader(hWaveOut_, &it->wavehdr_, sizeof(WAVEHDR));
while( buffers_.empty() == false ) // infinite loops
removeCompletedBuffers();
waveOutClose(hWaveOut_);
//Unhandled exception at 0x75629E80 (msvcrt.dll) in app.exe:
// 0xC0000005: Access violation reading location 0xFEEEFEEE.
}
void PcmPlayback::removeCompletedBuffers()
{
for(auto it = buffers_.begin(); it != buffers_.end();)
{
if( it->wavehdr_.dwFlags & WHDR_DONE )
{
waveOutUnprepareHeader(hWaveOut_, &it->wavehdr_, sizeof(WAVEHDR));
it = buffers_.erase(it);
}
else
++it;
}
}
但是,这种情况永远不会发生 - 缓冲区永远不会变空。wavehdr_.dwFlags == 18 将剩余 4-5 个块(我相信这意味着这些块仍被标记为正在播放)
我该如何解决这个问题?
@ Martin Schlott(“你能提供将缓冲区写入waveOutWrite的循环吗?”)它不是一个循环,而是我有一个函数,每当我通过网络接收到音频数据包时都会调用它:
void PcmPlayback::addData(const std::vector<short> &rhs)
{
removeCompletedBuffers();
if(rhs.empty())
return;
// add new data
buffers_.push_back(Buffer());
Buffer & buffer = buffers_.back();
buffer.data_ = rhs;
ZeroMemory(&buffers_.back().wavehdr_, sizeof(WAVEHDR));
buffer.wavehdr_.dwBufferLength = buffer.data_.size() * sizeof(short);
buffer.wavehdr_.lpData = (char *)(buffer.data_.data());
waveOutPrepareHeader(hWaveOut_, &buffer.wavehdr_, sizeof(WAVEHDR)); // prepare block for playback
waveOutWrite(hWaveOut_, &buffer.wavehdr_, sizeof(WAVEHDR));
}