output/alsa: avoid endless loop in Raspberry Pi workaround

See code comment.
This commit is contained in:
Max Kellermann 2013-11-04 23:26:24 +01:00
parent 7bca61f5bb
commit 62baec1841
2 changed files with 19 additions and 1 deletions

2
NEWS
View File

@ -5,6 +5,8 @@ ver 0.18.1 (2013/11/??)
- log UNIX domain path names instead of "localhost" - log UNIX domain path names instead of "localhost"
- open listener sockets in the order they were configured - open listener sockets in the order they were configured
- don't abort if IPv6 is not available - don't abort if IPv6 is not available
* output:
- alsa: avoid endless loop in Raspberry Pi workaround
* filter: * filter:
- autoconvert: fix "volume_normalization" with mp3 files - autoconvert: fix "volume_normalization" with mp3 files
* add missing files to source tarball * add missing files to source tarball

View File

@ -105,6 +105,14 @@ struct AlsaOutput {
*/ */
snd_pcm_uframes_t period_position; 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. * This buffer gets allocated after opening the ALSA device.
* It contains silence samples, enough to fill one period (see * 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; AlsaOutput *ad = (AlsaOutput *)ao;
ad->pi_workaround = 0;
int err = snd_pcm_open(&ad->pcm, alsa_device(ad), int err = snd_pcm_open(&ad->pcm, alsa_device(ad),
SND_PCM_STREAM_PLAYBACK, ad->mode); SND_PCM_STREAM_PLAYBACK, ad->mode);
if (err < 0) { if (err < 0) {
@ -727,7 +737,7 @@ alsa_recover(AlsaOutput *ad, int err)
ad->period_position = 0; ad->period_position = 0;
err = snd_pcm_prepare(ad->pcm); err = snd_pcm_prepare(ad->pcm);
if (err == 0) { if (err == 0 && ad->pi_workaround == 0) {
/* this works around a driver bug observed on /* this works around a driver bug observed on
the Raspberry Pi: after snd_pcm_drop(), the the Raspberry Pi: after snd_pcm_drop(), the
whole ring buffer must be invalidated, but whole ring buffer must be invalidated, but
@ -744,6 +754,9 @@ alsa_recover(AlsaOutput *ad, int err)
silence, the driver seems to avoid the silence, the driver seems to avoid the
bug */ bug */
snd_pcm_reset(ad->pcm); snd_pcm_reset(ad->pcm);
/* disable the workaround for some time */
ad->pi_workaround = 8;
} }
break; 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_position = (ad->period_position + ret)
% ad->period_frames; % ad->period_frames;
if (ad->pi_workaround > 0)
--ad->pi_workaround;
size_t bytes_written = ret * ad->out_frame_size; size_t bytes_written = ret * ad->out_frame_size;
return ad->pcm_export->CalcSourceSize(bytes_written); return ad->pcm_export->CalcSourceSize(bytes_written);
} }