From f2980d57a12fec55714eeb1eb7a51e204b7e9b07 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 7 Nov 2017 19:45:10 +0300 Subject: [PATCH] ALSA audio backend fixes --- rpcs3/Emu/Audio/ALSA/ALSAThread.cpp | 107 ++++++++++++++++++---------- 1 file changed, 70 insertions(+), 37 deletions(-) diff --git a/rpcs3/Emu/Audio/ALSA/ALSAThread.cpp b/rpcs3/Emu/Audio/ALSA/ALSAThread.cpp index 12e6d0045b..0562bdba83 100644 --- a/rpcs3/Emu/Audio/ALSA/ALSAThread.cpp +++ b/rpcs3/Emu/Audio/ALSA/ALSAThread.cpp @@ -1,5 +1,4 @@ #include "stdafx.h" -#include "Utilities/GSL.h" #include "Emu/System.h" #include "ALSAThread.h" @@ -9,10 +8,12 @@ #include static thread_local snd_pcm_t* s_tls_handle{nullptr}; +static thread_local snd_pcm_hw_params_t* s_tls_hw_params{nullptr}; +static thread_local snd_pcm_sw_params_t* s_tls_sw_params{nullptr}; static void error(int err, const char* reason) { - fprintf(stderr, "ALSA: %s failed: %s\n", reason, snd_strerror(err)); + LOG_ERROR(GENERAL, "ALSA: %s failed: %s\n", reason, snd_strerror(err)); } static bool check(int err, const char* reason) @@ -28,55 +29,86 @@ static bool check(int err, const char* reason) ALSAThread::ALSAThread() { - snd_pcm_hw_params_t* hw_params{nullptr}; - - auto at_ret = gsl::finally([&]() - { - if (hw_params) - { - snd_pcm_hw_params_free(hw_params); - } - }); - if (!check(snd_pcm_open(&s_tls_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK), "snd_pcm_open")) return; - if (!check(snd_pcm_hw_params_malloc(&hw_params), "snd_pcm_hw_params_malloc")) + if (!check(snd_pcm_hw_params_malloc(&s_tls_hw_params), "snd_pcm_hw_params_malloc")) return; - if (!check(snd_pcm_hw_params_any(s_tls_handle, hw_params), "snd_pcm_hw_params_any")) + if (!check(snd_pcm_hw_params_any(s_tls_handle, s_tls_hw_params), "snd_pcm_hw_params_any")) return; - if (!check(snd_pcm_hw_params_set_access(s_tls_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "snd_pcm_hw_params_set_access")) + if (!check(snd_pcm_hw_params_set_access(s_tls_handle, s_tls_hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "snd_pcm_hw_params_set_access")) return; - if (!check(snd_pcm_hw_params_set_format(s_tls_handle, hw_params, g_cfg.audio.convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format")) + if (!check(snd_pcm_hw_params_set_format(s_tls_handle, s_tls_hw_params, g_cfg.audio.convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format")) return; - if (!check(snd_pcm_hw_params_set_rate(s_tls_handle, hw_params, 48000, 0), "snd_pcm_hw_params_set_rate_near")) + uint rate = 48000; + if (!check(snd_pcm_hw_params_set_rate_near(s_tls_handle, s_tls_hw_params, &rate, nullptr), "snd_pcm_hw_params_set_rate_near")) return; - if (!check(snd_pcm_hw_params_set_channels(s_tls_handle, hw_params, g_cfg.audio.downmix_to_2ch ? 2 : 8), "snd_pcm_hw_params_set_channels")) + if (!check(snd_pcm_hw_params_set_channels(s_tls_handle, s_tls_hw_params, g_cfg.audio.downmix_to_2ch ? 2 : 8), "snd_pcm_hw_params_set_channels")) return; - if (!check(snd_pcm_hw_params_set_buffer_size(s_tls_handle, hw_params, g_cfg.audio.frames * 256), "snd_pcm_hw_params_set_buffer_size")) + //uint period = 5333; + //if (!check(snd_pcm_hw_params_set_period_time_near(s_tls_handle, s_tls_hw_params, &period, nullptr), "snd_pcm_hw_params_set_period_time_near")) + // return; + + //if (!check(snd_pcm_hw_params_set_periods(s_tls_handle, s_tls_hw_params, 4, 0), "snd_pcm_hw_params_set_periods")) + // return; + + snd_pcm_uframes_t bufsize_frames = g_cfg.audio.frames * 256; + snd_pcm_uframes_t period_frames = 256; + + if (!check(snd_pcm_hw_params_set_buffer_size_near(s_tls_handle, s_tls_hw_params, &bufsize_frames), "snd_pcm_hw_params_set_buffer_size_near")) return; - if (!check(snd_pcm_hw_params_set_period_size(s_tls_handle, hw_params, 256, 0), "snd_pcm_hw_params_set_period_size")) + if (!check(snd_pcm_hw_params_set_period_size_near(s_tls_handle, s_tls_hw_params, &period_frames, 0), "snd_pcm_hw_params_set_period_size")) return; - //if (!check(snd_pcm_hw_params_set_periods(s_tls_handle, hw_params, 2, 0), "snd_pcm_hw_params_set_periods")) - // return; + if (!check(snd_pcm_hw_params(s_tls_handle, s_tls_hw_params), "snd_pcm_hw_params")) + return; - if (!check(snd_pcm_hw_params(s_tls_handle, hw_params), "snd_pcm_hw_params")) + if (!check(snd_pcm_hw_params_get_buffer_size(s_tls_hw_params, &bufsize_frames), "snd_pcm_hw_params_get_buffer_size")) + return; + + if (!check(snd_pcm_hw_params_get_period_size(s_tls_hw_params, &period_frames, nullptr), "snd_pcm_hw_params_get_period_size")) + return; + + if (!check(snd_pcm_sw_params_malloc(&s_tls_sw_params), "snd_pcm_sw_params_malloc")) + return; + + if (!check(snd_pcm_sw_params_current(s_tls_handle, s_tls_sw_params), "snd_pcm_sw_params_current")) + return; + + if (!check(snd_pcm_sw_params_set_start_threshold(s_tls_handle, s_tls_sw_params, period_frames), "snd_pcm_sw_params_set_start_threshold")) + return; + + if (!check(snd_pcm_sw_params_set_stop_threshold(s_tls_handle, s_tls_sw_params, bufsize_frames), "snd_pcm_sw_params_set_stop_threshold")) + return; + + if (!check(snd_pcm_sw_params(s_tls_handle, s_tls_sw_params), "snd_pcm_sw_params")) return; if (!check(snd_pcm_prepare(s_tls_handle), "snd_pcm_prepare")) return; + + LOG_NOTICE(GENERAL, "ALSA: bufsize_frames=%u, period_frames=%u", bufsize_frames, period_frames); } ALSAThread::~ALSAThread() { + if (s_tls_sw_params) + { + snd_pcm_sw_params_free(s_tls_sw_params); + } + + if (s_tls_hw_params) + { + snd_pcm_hw_params_free(s_tls_hw_params); + } + if (s_tls_handle) { snd_pcm_close(s_tls_handle); @@ -105,29 +137,30 @@ void ALSAThread::AddData(const void* src, int size) size /= g_cfg.audio.convert_to_u16 ? 2 : 4; size /= g_cfg.audio.downmix_to_2ch ? 2 : 8; - int res; + int res = snd_pcm_writei(s_tls_handle, src, size); - while (true) + if (res == -EAGAIN) { - res = snd_pcm_writei(s_tls_handle, src, size); + LOG_WARNING(GENERAL, "ALSA: EAGAIN"); + return; + } - if (res == -EAGAIN) + if (res < 0) + { + res = snd_pcm_recover(s_tls_handle, res, 0); + + if (res < 0) { - continue; - } - else if (res == -EPIPE) - { - snd_pcm_prepare(s_tls_handle); - } - else - { - break; + LOG_WARNING(GENERAL, "ALSA: failed to recover (%d)", res); + return; } + + res = snd_pcm_writei(s_tls_handle, src, size); } if (res != size) { - error(res, "snd_pcm_writei"); + LOG_WARNING(GENERAL, "ALSA: error (%d)", res); } }