aboutsummaryrefslogtreecommitdiffstats
path: root/src/output/plugins/AlsaOutputPlugin.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/output/plugins/AlsaOutputPlugin.cxx55
1 files changed, 22 insertions, 33 deletions
diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx
index bea96d09f..f798bac63 100644
--- a/src/output/plugins/AlsaOutputPlugin.cxx
+++ b/src/output/plugins/AlsaOutputPlugin.cxx
@@ -105,12 +105,16 @@ 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".
+ * 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.
*/
- unsigned pi_workaround;
+ bool must_prepare;
/**
* This buffer gets allocated after opening the ALSA device.
@@ -671,8 +675,6 @@ alsa_open(AudioOutput *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) {
@@ -694,6 +696,8 @@ alsa_open(AudioOutput *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;
}
@@ -731,29 +735,6 @@ alsa_recover(AlsaOutput *ad, int err)
case SND_PCM_STATE_XRUN:
ad->period_position = 0;
err = snd_pcm_prepare(ad->pcm);
-
- 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
- the snd_pcm_prepare() call above makes the
- driver play random data that just happens
- to be still in the buffer; by adding and
- cancelling some silence, this bug does not
- occur */
- alsa_write_silence(ad, ad->period_frames);
-
- /* cancel the silence data right away to avoid
- increasing latency; even though this
- function call invalidates the portion of
- silence, the driver seems to avoid the
- bug */
- snd_pcm_reset(ad->pcm);
-
- /* disable the workaround for some time */
- ad->pi_workaround = 8;
- }
-
break;
case SND_PCM_STATE_DISCONNECTED:
break;
@@ -796,6 +777,7 @@ alsa_cancel(AudioOutput *ao)
AlsaOutput *ad = (AlsaOutput *)ao;
ad->period_position = 0;
+ ad->must_prepare = true;
snd_pcm_drop(ad->pcm);
}
@@ -817,6 +799,16 @@ alsa_play(AudioOutput *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);
@@ -829,9 +821,6 @@ alsa_play(AudioOutput *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);
}