I'm porting a cross-platform code, mostly written in C++ to support Windows (Phone) 8.1. With C++11 features, it was quite an easy task to far, but recently I've stumbled upon a very strange bug. I'm using XAudio2 API to output PCM streaming sound on Windows platform, but after that any call to timed wait methods (std::condition_variable::wait_for(), std::condition_variable::wait_until(), std::this_thread::sleep_for()
) in UI thread causes a deadlock: not only such call never returns, calling std::condition_variable::notify_all
does not wake the waiting thread.
Here's a code example:
// this should be called from UI thread and returns normally
std::this_thread::sleep_for(std::chrono::seconds(1));
// this could be called from any thread
IXAudio2* pXAudio2;
IXAudio2MasteringVoice * pMasteringVoice;
IXAudio2SourceVoice * pSourceVoice;
byte soundData[2 * 5 * 44100];
if (FAILED(XAudio2Create(&pXAudio2))) {
return;
}
if (FAILED(pXAudio2->CreateMasteringVoice(&pMasteringVoice))) {
return;
}
WAVEFORMATEX waveformat;
waveformat.wFormatTag = WAVE_FORMAT_PCM;
waveformat.nChannels = 1;
waveformat.nSamplesPerSec = 44100;
waveformat.nAvgBytesPerSec = 44100 * 2;
waveformat.nBlockAlign = 2;
waveformat.wBitsPerSample = 16;
waveformat.cbSize = 0;
if (FAILED(pXAudio2->CreateSourceVoice(&pSourceVoice, &waveformat))) {
return;
}
if (FAILED(pSourceVoice->Start())) {
return;
}
// Fill the array with sound data
for (int index = 0, second = 0; second < 5; second++) {
for (int cycle = 0; cycle < 441; cycle++) {
for (int sample = 0; sample < 100; sample++) {
short value = sample < 50 ? 32767 : -32768;
soundData[index++] = value & 0xFF;
soundData[index++] = (value >> 8) & 0xFF;
}
}
}
XAUDIO2_BUFFER buffer = { 0 };
buffer.AudioBytes = 2 * 1 * 44100;
buffer.pAudioData = soundData;
buffer.Flags = XAUDIO2_END_OF_STREAM;
buffer.PlayBegin = 0;
buffer.PlayLength = 1 * 44100;
HRESULT hr = pSourceVoice->SubmitSourceBuffer(&buffer);
while (true) {
XAUDIO2_VOICE_STATE state;
pSourceVoice->GetState(&state);
if (state.BuffersQueued > 0) {
//this will cause deadlock if called from UI thread
std::this_thread::sleep_for(std::chrono::seconds(1));
} else {
break;
}
}
pSourceVoice->Stop();
pSourceVoice->FlushSourceBuffers();
pSourceVoice->DestroyVoice();
pMasteringVoice->DestroyVoice();
pXAudio2->StopEngine();
pXAudio2->Release();
// this should be called from UI thread after the above and causes deadlock
std::this_thread::sleep_for(std::chrono::seconds(1));
Other observations:
This bug does not affect background threads
Non-timed wait works well (i.e.
std::condition_variable::wait()
).
Any ideas?
Aucun commentaire:
Enregistrer un commentaire