summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2007-12-14 15:25:46 +0100
committerTakashi Iwai <tiwai@suse.de>2007-12-14 15:25:46 +0100
commit660e0f16145167a966e9b8387e9a8e08274a8f7c (patch)
treed2e80b28d113fca9c1fd1ca2e7b7530d8f6a6848
parent327e169964b0a5bdcffb46eb49a305f3aabaeab4 (diff)
PulseAudio plugin: report XRUN state back to application
From: Lennart Poettering <mznyfn@0pointer.de> 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.)
-rw-r--r--pulse/pcm_pulse.c23
1 files changed, 22 insertions, 1 deletions
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);