Fix T86728: Blender freezes when playhead is dragged in this .blend

Porting the deadlock bugfix in WASAPI from upstream Audaspace.
This commit is contained in:
Jörg Müller 2021-03-19 21:42:55 +01:00
parent 00215692d1
commit 250a69ee82
2 changed files with 53 additions and 12 deletions

View File

@ -35,7 +35,11 @@ void WASAPIDevice::start()
{
lock();
if(!m_playing)
// thread is still running, we can abort stopping it
if(m_stop)
m_stop = false;
// thread is not running, let's start it
else if(!m_playing)
{
if(m_thread.joinable())
m_thread.join();
@ -53,20 +57,35 @@ void WASAPIDevice::updateStream()
UINT32 buffer_size;
data_t* buffer;
lock();
if(FAILED(m_audio_client->GetBufferSize(&buffer_size)))
{
m_playing = false;
m_stop = false;
unlock();
return;
}
IAudioRenderClient* render_client = nullptr;
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client))))
{
m_playing = false;
m_stop = false;
unlock();
return;
}
UINT32 padding;
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
{
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
@ -75,31 +94,40 @@ void WASAPIDevice::updateStream()
if(FAILED(render_client->GetBuffer(length, &buffer)))
{
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
lock();
mix((data_t*)buffer, length);
unlock();
if(FAILED(render_client->ReleaseBuffer(length, 0)))
{
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
unlock();
m_audio_client->Start();
auto sleepDuration = std::chrono::milliseconds(buffer_size * 1000 / int(m_specs.rate) / 2);
for(;;)
{
lock();
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
{
m_audio_client->Stop();
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
@ -109,44 +137,52 @@ void WASAPIDevice::updateStream()
{
m_audio_client->Stop();
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
lock();
mix((data_t*)buffer, length);
unlock();
if(FAILED(render_client->ReleaseBuffer(length, 0)))
{
m_audio_client->Stop();
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
// stop thread
if(!m_playing)
if(m_stop)
{
m_audio_client->Stop();
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
unlock();
std::this_thread::sleep_for(sleepDuration);
}
}
void WASAPIDevice::playing(bool playing)
{
if(!m_playing && playing)
if((!m_playing || m_stop) && playing)
start();
else
m_playing = playing;
m_stop = true;
}
WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) :
m_playing(false),
m_stop(false),
m_imm_device_enumerator(nullptr),
m_imm_device(nullptr),

View File

@ -48,6 +48,11 @@ private:
*/
bool m_playing;
/**
* Whether the current playback should stop.
*/
bool m_stop;
IMMDeviceEnumerator* m_imm_device_enumerator;
IMMDevice* m_imm_device;
IAudioClient* m_audio_client;