From 660e0f16145167a966e9b8387e9a8e08274a8f7c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 14 Dec 2007 15:25:46 +0100 Subject: PulseAudio plugin: report XRUN state back to application From: Lennart Poettering It adds support to report back XRUN to the application if one happens. This is required to make some applications work on top of the pulse plugin. One being XMMS, which checks if a song finished to play by waiting for an XRUN (yes, I don't argue that XMMS shouldn't do that, but nonetheless it is a good thing if XRUNs are reported properly.) --- pulse/pcm_pulse.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/pulse/pcm_pulse.c b/pulse/pcm_pulse.c index da15792..b6d5b46 100644 --- a/pulse/pcm_pulse.c +++ b/pulse/pcm_pulse.c @@ -36,6 +36,7 @@ typedef struct snd_pcm_pulse { /* Since ALSA expects a ring buffer we must do some voodoo. */ size_t last_size; size_t ptr; + int underrun; size_t offset; @@ -90,7 +91,9 @@ static int pulse_start(snd_pcm_ioplug_t *io) if (err < 0) { err = -EIO; goto finish; - } + } else + pcm->underrun = 0; + finish: pa_threaded_mainloop_unlock(pcm->p->mainloop); @@ -200,6 +203,9 @@ static snd_pcm_sframes_t pulse_pointer(snd_pcm_ioplug_t *io) err = snd_pcm_bytes_to_frames(io->pcm, pcm->ptr); + if (pcm->underrun) + err = -EPIPE; + finish: pa_threaded_mainloop_unlock(pcm->p->mainloop); @@ -231,6 +237,9 @@ static int pulse_delay(snd_pcm_ioplug_t *io, *delayp = snd_pcm_bytes_to_frames(io->pcm, pa_usec_to_bytes(lat, &pcm->ss)); + if (pcm->underrun && pcm->io.state == SND_PCM_STATE_RUNNING) + snd_pcm_ioplug_set_state(io, SND_PCM_STATE_XRUN); + finish: pa_threaded_mainloop_unlock(pcm->p->mainloop); @@ -273,6 +282,7 @@ static snd_pcm_sframes_t pulse_write(snd_pcm_ioplug_t *io, pulse_poll_deactivate(pcm->p); err = size; + pcm->underrun = 0; finish: pa_threaded_mainloop_unlock(pcm->p->mainloop); @@ -354,6 +364,15 @@ static void stream_request_cb(pa_stream *p, size_t length, void *userdata) pulse_poll_activate(pcm->p); } +static void stream_underrun_cb(pa_stream *p, void *userdata) { + snd_pcm_pulse_t *pcm = userdata; + + assert(pcm); + assert(pcm->p); + + pcm->underrun = 1; +} + static int pulse_pcm_poll_descriptors_count(snd_pcm_ioplug_t *io) { snd_pcm_pulse_t *pcm = io->private_data; @@ -461,6 +480,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); + pa_stream_set_underflow_callback(pcm->stream, stream_underrun_cb, pcm); pa_stream_connect_playback(pcm->stream, pcm->device, &pcm->buffer_attr, PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING, NULL, NULL); } else { @@ -480,6 +500,7 @@ static int pulse_prepare(snd_pcm_ioplug_t *io) pcm->last_size = 0; pcm->ptr = 0; pcm->offset = 0; + pcm->underrun = 0; finish: pa_threaded_mainloop_unlock(pcm->p->mainloop); -- cgit