The pulse ALSA plugin has been known, for a while, to not work properly, causing underruns, hangs etc. I sat down yesterday trying to figure it out, and I'm pretty certain this patch improves the situation, but I don't mind getting some help testing it before it is committed upstream.
Related bug: https://bugs.launchpad.net/bugs/485488 The patch is for the alsa-plugins tree at git.alsa-projects.org. // David
>From 2e9f8fa4d6f7a0cabe5aea1cbfa98980cdfb6d84 Mon Sep 17 00:00:00 2001 From: David Henningsson <[email protected]> Date: Sat, 9 Jan 2010 09:09:14 +0100 Subject: [PATCH] pulse: Fix invalid buffer pointer return value This patch improves recovering from underruns, and prevents hangs inside snd_pcm_write* and snd_pcm_read* due to snd_pcm_avail* returning too low values. It especially helps low latency situations. Signed-off-by: David Henningsson <[email protected]> --- pulse/pcm_pulse.c | 15 ++++++++++++++- 1 files changed, 14 insertions(+), 1 deletions(-) diff --git a/pulse/pcm_pulse.c b/pulse/pcm_pulse.c index 02a837e..3776af5 100644 --- a/pulse/pcm_pulse.c +++ b/pulse/pcm_pulse.c @@ -90,6 +90,10 @@ static int update_ptr(snd_pcm_pulse_t *pcm) if (pcm->io.stream == SND_PCM_STREAM_CAPTURE) size -= pcm->offset; + /* Prevent accidental overrun of the fake ringbuffer */ + if (size >= pcm->buffer_attr.tlength) + size = pcm->buffer_attr.tlength-1; + if (size > pcm->last_size) { pcm->ptr += size - pcm->last_size; pcm->ptr %= pcm->buffer_attr.tlength; @@ -424,6 +428,7 @@ static snd_pcm_sframes_t pulse_write(snd_pcm_ioplug_t * io, snd_pcm_pulse_t *pcm = io->private_data; const char *buf; snd_pcm_sframes_t ret = 0; + size_t writebytes; assert(pcm); @@ -445,13 +450,15 @@ static snd_pcm_sframes_t pulse_write(snd_pcm_ioplug_t * io, (char *) areas->addr + (areas->first + areas->step * offset) / 8; - ret = pa_stream_write(pcm->stream, buf, size * pcm->frame_size, NULL, 0, 0); + writebytes = size * pcm->frame_size; + ret = pa_stream_write(pcm->stream, buf, writebytes, NULL, 0, 0); if (ret < 0) { ret = -EIO; goto finish; } /* Make sure the buffer pointer is in sync */ + pcm->last_size -= writebytes; ret = update_ptr(pcm); if (ret < 0) goto finish; @@ -528,6 +535,7 @@ static snd_pcm_sframes_t pulse_read(snd_pcm_ioplug_t * io, dst_buf = (char *) dst_buf + frag_length; remain_size -= frag_length; + pcm->last_size -= frag_length; } /* Make sure the buffer pointer is in sync */ @@ -730,6 +738,11 @@ static int pulse_prepare(snd_pcm_ioplug_t * io) pcm->offset = 0; pcm->underrun = 0; + /* Reset fake ringbuffer */ + pcm->last_size = 0; + pcm->ptr = 0; + update_ptr(pcm); + finish: pa_threaded_mainloop_unlock(pcm->p->mainloop); -- 1.6.5
_______________________________________________ pulseaudio-discuss mailing list [email protected] https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss
