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 @@ -105,6 +105,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 @@ -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); }