aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2014-03-02 11:12:09 +0100
committerMax Kellermann <max@duempel.org>2014-03-02 11:12:25 +0100
commita884e37de16fba2dddbe61e34520860f8b88c15d (patch)
treefe31e7ab622fd132cf3f83052a5c3baa6c6d1c40
parent0102a8665ae23f3e7807f711abbe461e58359f61 (diff)
downloadmpd-a884e37de16fba2dddbe61e34520860f8b88c15d.tar.gz
mpd-a884e37de16fba2dddbe61e34520860f8b88c15d.tar.xz
mpd-a884e37de16fba2dddbe61e34520860f8b88c15d.zip
output/alsa: call snd_pcm_prepare() after snd_pcm_drop()
Don't wait for an optimistic write to fail. This is an improved workaround for the infamous Raspberry Pi bug (see commit af991765). It works much better and comes without the negative side effects. The old workaround is now obsolete.
-rw-r--r--NEWS2
-rw-r--r--src/output/AlsaOutputPlugin.cxx25
2 files changed, 27 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 52b999a3a..6d7d13de1 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
ver 0.18.9 (not yet released)
* protocol
- "findadd" requires the "add" permission
+* output
+ - alsa: improved workaround for noise after manual song change
* decoder
- vorbis: fix linker failure when libvorbis/libogg are static
* encoder
diff --git a/src/output/AlsaOutputPlugin.cxx b/src/output/AlsaOutputPlugin.cxx
index 4877d3a46..c5db2320d 100644
--- a/src/output/AlsaOutputPlugin.cxx
+++ b/src/output/AlsaOutputPlugin.cxx
@@ -114,6 +114,18 @@ struct AlsaOutput {
unsigned pi_workaround;
/**
+ * Do we need to call snd_pcm_prepare() before the next write?
+ * It means that we put the device to SND_PCM_STATE_SETUP by
+ * calling snd_pcm_drop().
+ *
+ * Without this flag, we could easily recover after a failed
+ * optimistic write (returning -EBADFD), but the Raspberry Pi
+ * audio driver is infamous for generating ugly artefacts from
+ * this.
+ */
+ bool must_prepare;
+
+ /**
* This buffer gets allocated after opening the ALSA device.
* It contains silence samples, enough to fill one period (see
* #period_frames).
@@ -699,6 +711,8 @@ alsa_open(struct audio_output *ao, AudioFormat &audio_format, Error &error)
ad->in_frame_size = audio_format.GetFrameSize();
ad->out_frame_size = ad->pcm_export->GetFrameSize(audio_format);
+ ad->must_prepare = false;
+
return true;
}
@@ -801,6 +815,7 @@ alsa_cancel(struct audio_output *ao)
AlsaOutput *ad = (AlsaOutput *)ao;
ad->period_position = 0;
+ ad->must_prepare = true;
snd_pcm_drop(ad->pcm);
}
@@ -822,6 +837,16 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size,
assert(size % ad->in_frame_size == 0);
+ if (ad->must_prepare) {
+ ad->must_prepare = false;
+
+ int err = snd_pcm_prepare(ad->pcm);
+ if (err < 0) {
+ error.Set(alsa_output_domain, err, snd_strerror(-err));
+ return 0;
+ }
+ }
+
chunk = ad->pcm_export->Export(chunk, size, size);
assert(size % ad->out_frame_size == 0);