lundi 2 février 2015

Using XAudio2 in Windows Store App causes a deadlock in any timed wait call in UI thread

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:




  1. This bug does not affect background threads




  2. Non-timed wait works well (i.e. std::condition_variable::wait()).




Any ideas?


Aucun commentaire:

Enregistrer un commentaire