From e5122f17b4877374471932478c903248a6832625 Mon Sep 17 00:00:00 2001 From: mio Date: Sun, 17 Nov 2024 18:58:30 +1000 Subject: [PATCH] ALSASink: Set a buffer time of 100ms A delay is introduced when using ALSA under PulseAudio. This particular fix helps when, for example, adjusting the volume. Signed-off-by: mio --- akode/plugins/alsa_sink/alsa_sink.cpp | 54 ++++++++++++++++++++------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/akode/plugins/alsa_sink/alsa_sink.cpp b/akode/plugins/alsa_sink/alsa_sink.cpp index 501b8ca..c226519 100644 --- a/akode/plugins/alsa_sink/alsa_sink.cpp +++ b/akode/plugins/alsa_sink/alsa_sink.cpp @@ -18,7 +18,8 @@ Boston, MA 02110-1301, USA. */ -// #define DEBUG +#define DEBUG +#define AKODE_MODULE "alsa_sink" #include "akode_debug.h" @@ -172,6 +173,9 @@ found_format: else return -1; + // Disable ALSA resampling, since we do that. + snd_pcm_hw_params_set_rate_resample(m_data->pcm_playback, hw, 0); + unsigned int rate = config->sample_rate; snd_pcm_hw_params_set_rate_near(m_data->pcm_playback, hw, &rate, 0); if (m_data->config.sample_rate != rate) { @@ -181,25 +185,49 @@ found_format: snd_pcm_hw_params_set_channels(m_data->pcm_playback, hw, config->channels); + // Set up buffer parameters. + // This mainly fixes a delay with PulseAudio. + unsigned bufferTime = 100'000; // us (100ms) + unsigned periods = 4; - m_data->fragmentSize = 1024; - snd_pcm_uframes_t period_size = m_data->fragmentSize / (wid*config->channels); - snd_pcm_hw_params_set_period_size_near(m_data->pcm_playback, hw, &period_size, 0); + int err = snd_pcm_hw_params_set_buffer_time_near(m_data->pcm_playback, hw, &bufferTime, nullptr); + if (err < 0) + { + AKODE_WARN("unable to set buffer time: " << snd_strerror(err)); + } + if (err >= 0) + { + err = snd_pcm_hw_params_set_periods_near(m_data->pcm_playback, hw, &periods, nullptr); + if (err < 0) + { + AKODE_WARN("unable to set periods near: " << snd_strerror(err)); + } + } - m_data->fragmentSize = period_size * (wid*config->channels); -// std::cerr << "akode: ALSA fragment-size: " << m_data->fragmentSize << "\n"; + err = snd_pcm_hw_params(m_data->pcm_playback, hw); + if (err < 0) + { + AKODE_WARN("unable to set hw params: " << snd_strerror(err)); + m_data->error = true; + return -1; + } + + snd_pcm_uframes_t bufferSize; + snd_pcm_hw_params_get_buffer_size(hw, &bufferSize); + m_data->fragmentSize = snd_pcm_frames_to_bytes(m_data->pcm_playback, bufferSize) * 2; delete m_data->buffer; m_data->buffer = new char [m_data->fragmentSize]; m_data->filled = 0; - if (snd_pcm_hw_params(m_data->pcm_playback, hw) < 0) { - return -1; - } - else { - m_data->can_pause = (snd_pcm_hw_params_can_pause(hw) == 1); - return res; - } + m_data->can_pause = (snd_pcm_hw_params_can_pause(hw) == 1); + + AKODE_DEBUG("hw can-pause: " << (m_data->can_pause ? "true" : "false")); + AKODE_DEBUG("buffer-size: " << bufferSize << " frames"); + AKODE_DEBUG("fragment-size: " << + snd_pcm_bytes_to_frames(m_data->pcm_playback, m_data->fragmentSize) << " frames"); + + return res; } const AudioConfiguration* ALSASink::audioConfiguration() const