summaryrefslogtreecommitdiff
path: root/src/output
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2018-11-14 11:06:59 +0100
committerMax Kellermann <max@musicpd.org>2018-11-14 11:17:59 +0100
commitccafe3f3cf361ff1c2862c0eb45d96501d67d6a7 (patch)
treeb1f98cf637535ac30a43e14d406990c7fafad520 /src/output
parent3830748de5d44b5f895c3ebadd576a915737fba8 (diff)
output/alsa: don't generate silence if ALSA-PCM buffer has enough data
If our `ring_buffer` is smaller than the ALSA-PCM buffer (if the latter has more than the 4 periods we allocate), it can happen that the start threshold is crossed and ALSA switches to `SND_PCM_STATE_RUNNING`, but the `ring_buffer` is empty. In this case, MPDD will generate silence, even though the ALSA-PCM buffer has enough data. This causes stuttering (#420). This commit amends an older workaround for a similar problem (commit e08598e7e2526b65fd8790a49794c1d4d00945d0) by adding a snd_pcm_avail() check, and only generate silence if there is less than one period of data in the ALSA-PCM buffer. Fixes #420
Diffstat (limited to 'src/output')
-rw-r--r--src/output/plugins/AlsaOutputPlugin.cxx19
1 files changed, 18 insertions, 1 deletions
diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx
index c72cf4ea2..ee1487fb0 100644
--- a/src/output/plugins/AlsaOutputPlugin.cxx
+++ b/src/output/plugins/AlsaOutputPlugin.cxx
@@ -110,6 +110,13 @@ class AlsaOutput final
snd_pcm_uframes_t period_frames;
/**
+ * If snd_pcm_avail() goes above this value and no more data
+ * is available in the #ring_buffer, we need to play some
+ * silence.
+ */
+ snd_pcm_sframes_t max_avail_frames;
+
+ /**
* Is this a buggy alsa-lib version, which needs a workaround
* for the snd_pcm_drain() bug always returning -EAGAIN? See
* alsa-lib commits fdc898d41135 and e4377b16454f for details.
@@ -482,6 +489,10 @@ AlsaOutput::Setup(AudioFormat &audio_format,
period_frames = alsa_period_size;
+ /* generate silence if there's less than once period of data
+ in the ALSA-PCM buffer */
+ max_avail_frames = hw_result.buffer_size - hw_result.period_size;
+
silence = new uint8_t[snd_pcm_frames_to_bytes(pcm, alsa_period_size)];
snd_pcm_format_set_silence(hw_result.format, silence,
alsa_period_size * audio_format.channels);
@@ -933,7 +944,8 @@ try {
CopyRingToPeriodBuffer();
if (period_buffer.IsEmpty()) {
- if (snd_pcm_state(pcm) == SND_PCM_STATE_PREPARED) {
+ if (snd_pcm_state(pcm) == SND_PCM_STATE_PREPARED ||
+ snd_pcm_avail(pcm) <= max_avail_frames) {
/* at SND_PCM_STATE_PREPARED (not yet switched
to SND_PCM_STATE_RUNNING), we have no
pressure to fill the ALSA buffer, because
@@ -943,6 +955,11 @@ try {
monitoring the ALSA file descriptor, and
let it be reactivated by Play()/Activate()
whenever more data arrives */
+ /* the same applies when there is still enough
+ data in the ALSA-PCM buffer (determined by
+ snd_pcm_avail()); this can happend at the
+ start of playback, when our ring_buffer is
+ smaller than the ALSA-PCM buffer */
{
const std::lock_guard<Mutex> lock(mutex);