Microsoft の WaveOut API に問題があります。
edit1: サンプル プロジェクトへのリンクを追加しました: edit2: リンクを削除しました。これは問題の代表ではありません
オーディオを再生した後、特定の再生ストリームを終了したい場合は、次の関数を呼び出します。
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));
}