Date: Friday, November 19, 2010 @ 11:25:41 Author: heftig Revision: 99957
Oops, forgot patches Added: alsa-plugins/trunk/Add_handle_underrun_option.patch alsa-plugins/trunk/Fix_invalid_buffer_pointer_return_value.patch -----------------------------------------------+ Add_handle_underrun_option.patch | 86 ++++++++++++++++++++++++ Fix_invalid_buffer_pointer_return_value.patch | 75 ++++++++++++++++++++ 2 files changed, 161 insertions(+) Added: Add_handle_underrun_option.patch =================================================================== --- Add_handle_underrun_option.patch (rev 0) +++ Add_handle_underrun_option.patch 2010-11-19 16:25:41 UTC (rev 99957) @@ -0,0 +1,86 @@ +From: Takashi Iwai <ti...@suse.de> +Date: Fri, 9 Jul 2010 12:05:03 +0000 (+0200) +Subject: pulse: Add handle_underrun option +X-Git-Url: http://git.alsa-project.org/?p=alsa-plugins.git;a=commitdiff_plain;h=c20d516e229620129ee20175d8fee8511cc3a4bd + +pulse: Add handle_underrun option + +Added a config option "handle_underrun" to specify whether pulse plugin +handles the underrun reported from PA. The default value is now set to +false, i.e. it will ignore underruns in PA (for good reasons below). +You can take back to the old behavior by setting handle_underrun true. + +The original idea was brought by David Henningsson <di...@ubuntu.com>, +while this patch is simplified and makes the behavior configurable. + +The reasons for avoiding underruns (cited from David's original patch): + + Reporting underruns to ALSA seems to do more bad than good, for these reasons: + * If pulseaudio gets an underrun, the normal way to end that underrun is to + feed it with more buffers. This is different from the ALSA way of dealing + with underruns, which requires hardware buffer pointers to be reset. + * In addition, underrun signals are delivered asynchronously from pulseaudio. + This means that there might be more buffers on the way to pulseaudio when + the underrun is reported, making the underrun obsolete. Unfortunately, + there is currently no known way to determine whether this is the case or + not. + +Signed-off-by: Takashi Iwai <ti...@suse.de> +--- + +diff --git a/pulse/pcm_pulse.c b/pulse/pcm_pulse.c +index b322898..2df0a80 100644 +--- a/pulse/pcm_pulse.c ++++ b/pulse/pcm_pulse.c +@@ -39,6 +39,7 @@ typedef struct snd_pcm_pulse { + size_t last_size; + size_t ptr; + int underrun; ++ int handle_underrun; + + size_t offset; + +@@ -696,8 +697,9 @@ 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); ++ if (pcm->handle_underrun) ++ pa_stream_set_underflow_callback(pcm->stream, ++ stream_underrun_cb, pcm); + r = pa_stream_connect_playback(pcm->stream, pcm->device, + &pcm->buffer_attr, + PA_STREAM_AUTO_TIMING_UPDATE | +@@ -980,6 +982,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(pulse) + snd_config_iterator_t i, next; + const char *server = NULL; + const char *device = NULL; ++ int handle_underrun = 0; + int err; + snd_pcm_pulse_t *pcm; + +@@ -1005,6 +1008,14 @@ SND_PCM_PLUGIN_DEFINE_FUNC(pulse) + } + continue; + } ++ if (strcmp(id, "handle_underrun") == 0) { ++ if ((err = snd_config_get_bool(n)) < 0) { ++ SNDERR("Invalid value for %s", id); ++ return -EINVAL; ++ } ++ handle_underrun = err; ++ continue; ++ } + SNDERR("Unknown field %s", id); + return -EINVAL; + } +@@ -1028,6 +1039,8 @@ SND_PCM_PLUGIN_DEFINE_FUNC(pulse) + goto error; + } + ++ pcm->handle_underrun = handle_underrun; ++ + err = pulse_connect(pcm->p, server); + if (err < 0) + goto error; Added: Fix_invalid_buffer_pointer_return_value.patch =================================================================== --- Fix_invalid_buffer_pointer_return_value.patch (rev 0) +++ Fix_invalid_buffer_pointer_return_value.patch 2010-11-19 16:25:41 UTC (rev 99957) @@ -0,0 +1,75 @@ +From: David Henningsson <di...@ubuntu.com> +Date: Sat, 9 Jan 2010 08:09:14 +0000 (+0100) +Subject: pulse: Fix invalid buffer pointer return value +X-Git-Url: http://git.alsa-project.org/?p=alsa-plugins.git;a=commitdiff_plain;h=1675414eca06dcfc20899adf104ace05acfe26a0 + +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 <di...@ubuntu.com> +Signed-off-by: Takashi Iwai <ti...@suse.de> +--- + +diff --git a/pulse/pcm_pulse.c b/pulse/pcm_pulse.c +index 02a837e..b322898 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); +