If more data has already been written after the underrun, the underrun will automatically end and therefore we should not report it or restart the stream.
Signed-off-by: David Henningsson david.henningsson@canonical.com --- pulse/pcm_pulse.c | 36 ++++++++++++++++++++++++++++++++++-- 1 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/pulse/pcm_pulse.c b/pulse/pcm_pulse.c index d6c6792..92f4777 100644 --- a/pulse/pcm_pulse.c +++ b/pulse/pcm_pulse.c @@ -40,8 +40,10 @@ typedef struct snd_pcm_pulse { size_t ptr; int underrun; int handle_underrun; + int handle_underrun_detect;
size_t offset; + int64_t written;
pa_stream *stream;
@@ -460,6 +462,7 @@ static snd_pcm_sframes_t pulse_write(snd_pcm_ioplug_t * io,
/* Make sure the buffer pointer is in sync */ pcm->last_size -= writebytes; + pcm->written += writebytes; ret = update_ptr(pcm); if (ret < 0) goto finish; @@ -585,6 +588,23 @@ static void stream_request_cb(pa_stream * p, size_t length, void *userdata) update_active(pcm); }
+#if defined(PA_CHECK_VERSION) && PA_CHECK_VERSION(0,99,0) + +#define has_underrun_detect 1 + +static inline int do_underrun_detect(snd_pcm_pulse_t *pcm, pa_stream *p) +{ + return pcm->handle_underrun_detect && + pcm->written <= pa_stream_get_underflow_index(p); +} + +#else + +#define has_underrun_detect 0 +#define do_underrun_detect(pcm, p) 0 + +#endif + static void stream_underrun_cb(pa_stream * p, void *userdata) { snd_pcm_pulse_t *pcm = userdata; @@ -594,7 +614,8 @@ static void stream_underrun_cb(pa_stream * p, void *userdata) if (!pcm->p) return;
- pcm->underrun = 1; + if (pcm->handle_underrun || do_underrun_detect(pcm, p)) + pcm->underrun = 1; }
static void stream_latency_cb(pa_stream *p, void *userdata) { @@ -697,7 +718,7 @@ static int pulse_prepare(snd_pcm_ioplug_t * io) if (io->stream == SND_PCM_STREAM_PLAYBACK) { pa_stream_set_write_callback(pcm->stream, stream_request_cb, pcm); - if (pcm->handle_underrun) + if (pcm->handle_underrun_detect || pcm->handle_underrun) pa_stream_set_underflow_callback(pcm->stream, stream_underrun_cb, pcm); r = pa_stream_connect_playback(pcm->stream, pcm->device, @@ -739,6 +760,7 @@ static int pulse_prepare(snd_pcm_ioplug_t * io)
pcm->offset = 0; pcm->underrun = 0; + pcm->written = 0;
/* Reset fake ringbuffer */ pcm->last_size = 0; @@ -984,6 +1006,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(pulse) const char *device = NULL; const char *fallback_name = NULL; int handle_underrun = 0; + int handle_underrun_detect = 1; int err; snd_pcm_pulse_t *pcm;
@@ -1017,6 +1040,14 @@ SND_PCM_PLUGIN_DEFINE_FUNC(pulse) handle_underrun = err; continue; } + if (strcmp(id, "handle_underrun_detect") == 0) { + if ((err = snd_config_get_bool(n)) < 0) { + SNDERR("Invalid value for %s", id); + return -EINVAL; + } + handle_underrun_detect = err; + continue; + } if (strcmp(id, "fallback") == 0) { if (snd_config_get_string(n, &fallback_name) < 0) { SNDERR("Invalid value for %s", id); @@ -1051,6 +1082,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(pulse) }
pcm->handle_underrun = handle_underrun; + pcm->handle_underrun_detect = has_underrun_detect && handle_underrun_detect;
err = pulse_connect(pcm->p, server, fallback_name != NULL); if (err < 0)