]> git.alsa-project.org Git - alsa-plugins.git/commitdiff
pulse: Fix invalid buffer pointer return value
authorDavid Henningsson <diwic@ubuntu.com>
Sat, 9 Jan 2010 08:09:14 +0000 (09:09 +0100)
committerTakashi Iwai <tiwai@suse.de>
Thu, 24 Jun 2010 06:41:33 +0000 (08:41 +0200)
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 <diwic@ubuntu.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
pulse/pcm_pulse.c

index 02a837e6cd263c3a7b692e43742615b564c9f23c..b322898e0255aebf5dc6e94e1f19d45fcdb41bb2 100644 (file)
@@ -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);