ALSA: Don't block on Clear() call.
snd_pcm_writei() is meant to block block until all samples are written, but apparently in some situations it can block for much longer, prehaps even a infinite time, in the case of virtual machine FifoCI runs in. Because it grabed a mutex before blocking, it could also block the Clear() call for an infinite length of time, blocking dolphin's emu thread. snd_pcm_writei() also takes 10-15 seconds if you run dolphin under GDB and can randomly take 5 or so seconds during normal usage. By moving all the pause code to the ALSA thread, Clear() no-longer blocks and everyone keeps their sanity.
This commit is contained in:
parent
6658d21215
commit
a10a3ecbac
|
@ -48,21 +48,31 @@ void AlsaSound::Update()
|
|||
void AlsaSound::SoundLoop()
|
||||
{
|
||||
Common::SetCurrentThreadName("Audio thread - alsa");
|
||||
while (m_thread_status.load() == ALSAThreadStatus::RUNNING)
|
||||
while (m_thread_status.load() != ALSAThreadStatus::STOPPING)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(cv_m);
|
||||
cv.wait(lock, [this]{return !m_muted || m_thread_status.load() != ALSAThreadStatus::RUNNING;});
|
||||
|
||||
m_mixer->Mix(mix_buffer, frames_to_deliver);
|
||||
int rc = snd_pcm_writei(handle, mix_buffer, frames_to_deliver);
|
||||
if (rc == -EPIPE)
|
||||
while (m_thread_status.load() == ALSAThreadStatus::RUNNING)
|
||||
{
|
||||
// Underrun
|
||||
snd_pcm_prepare(handle);
|
||||
m_mixer->Mix(mix_buffer, frames_to_deliver);
|
||||
int rc = snd_pcm_writei(handle, mix_buffer, frames_to_deliver);
|
||||
if (rc == -EPIPE)
|
||||
{
|
||||
// Underrun
|
||||
snd_pcm_prepare(handle);
|
||||
}
|
||||
else if (rc < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "writei fail: %s", snd_strerror(rc));
|
||||
}
|
||||
}
|
||||
else if (rc < 0)
|
||||
if (m_thread_status.load() == ALSAThreadStatus::PAUSED)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "writei fail: %s", snd_strerror(rc));
|
||||
snd_pcm_drop(handle); // Stop sound output
|
||||
|
||||
// Block until thread status changes.
|
||||
std::unique_lock<std::mutex> lock(cv_m);
|
||||
cv.wait(lock, [this]{ return m_thread_status.load() != ALSAThreadStatus::PAUSED; });
|
||||
|
||||
snd_pcm_prepare(handle); // resume sound output
|
||||
}
|
||||
}
|
||||
AlsaShutdown();
|
||||
|
@ -73,18 +83,8 @@ void AlsaSound::SoundLoop()
|
|||
void AlsaSound::Clear(bool muted)
|
||||
{
|
||||
m_muted = muted;
|
||||
if (m_muted)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(cv_m);
|
||||
snd_pcm_drop(handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(cv_m);
|
||||
snd_pcm_prepare(handle);
|
||||
lock.unlock();
|
||||
cv.notify_one();
|
||||
}
|
||||
m_thread_status.store(muted ? ALSAThreadStatus::PAUSED : ALSAThreadStatus::RUNNING);
|
||||
cv.notify_one(); // Notify thread that status has changed
|
||||
}
|
||||
|
||||
bool AlsaSound::AlsaInit()
|
||||
|
|
|
@ -46,6 +46,7 @@ private:
|
|||
enum class ALSAThreadStatus
|
||||
{
|
||||
RUNNING,
|
||||
PAUSED,
|
||||
STOPPING,
|
||||
STOPPED,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue