summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2013-11-04 23:26:24 +0100
committerMax Kellermann <max@duempel.org>2013-11-04 23:40:34 +0100
commit62baec1841af26106752cccdbc9da6811dc24949 (patch)
tree358b090b09cc142c63e3c456e8b449bf05ee6255
parent7bca61f5bbacfdf19c9e143f3829aa157d22e003 (diff)
output/alsa: avoid endless loop in Raspberry Pi workaround
See code comment.
-rw-r--r--NEWS2
-rw-r--r--src/output/AlsaOutputPlugin.cxx18
2 files changed, 19 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index 914a3449a..60f002e19 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ ver 0.18.1 (2013/11/??)
- log UNIX domain path names instead of "localhost"
- open listener sockets in the order they were configured
- don't abort if IPv6 is not available
+* output:
+ - alsa: avoid endless loop in Raspberry Pi workaround
* filter:
- autoconvert: fix "volume_normalization" with mp3 files
* add missing files to source tarball
diff --git a/src/output/AlsaOutputPlugin.cxx b/src/output/AlsaOutputPlugin.cxx
index 149ca507d..4877d3a46 100644
--- a/src/output/AlsaOutputPlugin.cxx
+++ b/src/output/AlsaOutputPlugin.cxx
@@ -106,6 +106,14 @@ struct AlsaOutput {
snd_pcm_uframes_t period_position;
/**
+ * Set to non-zero when the Raspberry Pi workaround has been
+ * activated in alsa_recover(); decremented by each write.
+ * This will avoid activating it again, leading to an endless
+ * loop. This problem was observed with a "RME Digi9636/52".
+ */
+ unsigned pi_workaround;
+
+ /**
* This buffer gets allocated after opening the ALSA device.
* It contains silence samples, enough to fill one period (see
* #period_frames).
@@ -668,6 +676,8 @@ alsa_open(struct audio_output *ao, AudioFormat &audio_format, Error &error)
{
AlsaOutput *ad = (AlsaOutput *)ao;
+ ad->pi_workaround = 0;
+
int err = snd_pcm_open(&ad->pcm, alsa_device(ad),
SND_PCM_STREAM_PLAYBACK, ad->mode);
if (err < 0) {
@@ -727,7 +737,7 @@ alsa_recover(AlsaOutput *ad, int err)
ad->period_position = 0;
err = snd_pcm_prepare(ad->pcm);
- if (err == 0) {
+ if (err == 0 && ad->pi_workaround == 0) {
/* this works around a driver bug observed on
the Raspberry Pi: after snd_pcm_drop(), the
whole ring buffer must be invalidated, but
@@ -744,6 +754,9 @@ alsa_recover(AlsaOutput *ad, int err)
silence, the driver seems to avoid the
bug */
snd_pcm_reset(ad->pcm);
+
+ /* disable the workaround for some time */
+ ad->pi_workaround = 8;
}
break;
@@ -821,6 +834,9 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size,
ad->period_position = (ad->period_position + ret)
% ad->period_frames;
+ if (ad->pi_workaround > 0)
+ --ad->pi_workaround;
+
size_t bytes_written = ret * ad->out_frame_size;
return ad->pcm_export->CalcSourceSize(bytes_written);
}