From a0c524774386c4543c710958bf1c607a91d6f28c Mon Sep 17 00:00:00 2001 From: Moncef Mechri Date: Sun, 9 Aug 2015 00:37:48 +0200 Subject: [PATCH 1/2] Initialize ALSA before starting the audio thread This fixes a race condition: Before this commit, there was a race condition when starting a game: Core::EmuThread(), after having started (but not necessarily completed) the initialization of the audio thread, calls Core::SetState() which calls CCPU::EnableStepping(), which in turns calls AudioCommon::ClearAudioBuffer(). This means that SoundStream::Clear() can be called before AlsaSound::AlsaInit() has completed. --- Source/Core/AudioCommon/AlsaSoundStream.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Source/Core/AudioCommon/AlsaSoundStream.cpp b/Source/Core/AudioCommon/AlsaSoundStream.cpp index 5902edba94..ae888564b3 100644 --- a/Source/Core/AudioCommon/AlsaSoundStream.cpp +++ b/Source/Core/AudioCommon/AlsaSoundStream.cpp @@ -26,6 +26,12 @@ AlsaSound::~AlsaSound() bool AlsaSound::Start() { m_thread_status.store(ALSAThreadStatus::RUNNING); + if (!AlsaInit()) + { + m_thread_status.store(ALSAThreadStatus::STOPPED); + return false; + } + thread = std::thread(&AlsaSound::SoundLoop, this); return true; } @@ -44,10 +50,6 @@ void AlsaSound::Update() // Called on audio thread. void AlsaSound::SoundLoop() { - if (!AlsaInit()) { - m_thread_status.store(ALSAThreadStatus::STOPPED); - return; - } Common::SetCurrentThreadName("Audio thread - alsa"); while (m_thread_status.load() == ALSAThreadStatus::RUNNING) { From 333f998123f617c6e643103184142d67c090c7fd Mon Sep 17 00:00:00 2001 From: Moncef Mechri Date: Tue, 7 Jul 2015 15:30:27 +0200 Subject: [PATCH 2/2] Don't busy wait in the audio thread (ALSA) When the emulation is paused and the ALSA backend is used, make the audio thread wait on a condition variable instead of busy-waiting. This commit fixes bug #7729 Since the ALSA API is not thread-safe, calls to snd_pcm_drop() and snd_pcm_prepare() in AlsaSound::Clear() are protected by the same mutex as the condition variable in AlsaSound::SoundLoop() to make sure that we do not call these functions while a call to snd_pcm_writei() is ongoing. --- Source/Core/AudioCommon/AlsaSoundStream.cpp | 29 ++++++++++++++++++++- Source/Core/AudioCommon/AlsaSoundStream.h | 5 ++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Source/Core/AudioCommon/AlsaSoundStream.cpp b/Source/Core/AudioCommon/AlsaSoundStream.cpp index ae888564b3..3a1f460133 100644 --- a/Source/Core/AudioCommon/AlsaSoundStream.cpp +++ b/Source/Core/AudioCommon/AlsaSoundStream.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include + #include "AudioCommon/AlsaSoundStream.h" #include "Common/CommonTypes.h" #include "Common/Thread.h" @@ -39,6 +41,10 @@ bool AlsaSound::Start() void AlsaSound::Stop() { m_thread_status.store(ALSAThreadStatus::STOPPING); + + //Give the opportunity to the audio thread + //to realize we are stopping the emulation + cv.notify_one(); thread.join(); } @@ -53,8 +59,11 @@ void AlsaSound::SoundLoop() Common::SetCurrentThreadName("Audio thread - alsa"); while (m_thread_status.load() == ALSAThreadStatus::RUNNING) { + std::unique_lock lock(cv_m); + cv.wait(lock, [this]{return !m_muted || m_thread_status.load() != ALSAThreadStatus::RUNNING;}); + m_mixer->Mix(reinterpret_cast(mix_buffer), frames_to_deliver); - int rc = m_muted ? 1337 : snd_pcm_writei(handle, mix_buffer, frames_to_deliver); + int rc = snd_pcm_writei(handle, mix_buffer, frames_to_deliver); if (rc == -EPIPE) { // Underrun @@ -69,6 +78,24 @@ void AlsaSound::SoundLoop() m_thread_status.store(ALSAThreadStatus::STOPPED); } + +void AlsaSound::Clear(bool muted) +{ + m_muted = muted; + if (m_muted) + { + std::lock_guard lock(cv_m); + snd_pcm_drop(handle); + } + else + { + std::unique_lock lock(cv_m); + snd_pcm_prepare(handle); + lock.unlock(); + cv.notify_one(); + } +} + bool AlsaSound::AlsaInit() { unsigned int sample_rate = m_mixer->GetSampleRate(); diff --git a/Source/Core/AudioCommon/AlsaSoundStream.h b/Source/Core/AudioCommon/AlsaSoundStream.h index 186e4871bb..3654f4b8a5 100644 --- a/Source/Core/AudioCommon/AlsaSoundStream.h +++ b/Source/Core/AudioCommon/AlsaSoundStream.h @@ -5,6 +5,8 @@ #pragma once #include +#include +#include #include #if defined(HAVE_ALSA) && HAVE_ALSA @@ -25,6 +27,7 @@ public: void SoundLoop() override; void Stop() override; void Update() override; + void Clear(bool) override; static bool isValid() { @@ -45,6 +48,8 @@ private: u8 *mix_buffer; std::thread thread; std::atomic m_thread_status; + std::condition_variable cv; + std::mutex cv_m; snd_pcm_t *handle; int frames_to_deliver;