]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 'master' into next
authorAndre Noll <maan@systemlinux.org>
Sat, 29 Aug 2009 20:29:17 +0000 (22:29 +0200)
committerAndre Noll <maan@systemlinux.org>
Sat, 29 Aug 2009 20:29:17 +0000 (22:29 +0200)
NEWS
alsa_write.c

diff --git a/NEWS b/NEWS
index 19f181c0753e10f293be0c5a0957a108a53e9b6a..dd9d2d120f4aaf6a7096bddb300bf5715bcbff2c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,10 @@ provided for conversion of the 0.3 database to the new 0.4 format.
 0.3.5 (to be announced) "symplectic separability"
 -------------------------------------------------
 
+Full client support for *BSD Unixes, various improvements and the
+usual mix of bugfixes. This release marks the end of the 0.3 series
+if no serious problems show up.
+
        - the new oss writer (supported on *BSD and Linux)
        - support for netmask subsets (Gerrit Renker)
        - the new prebuffer filter
index ae8bed6d339724563e86eb899d9aa96a46f6f8e7..679962e0e00f276700138bb83517e7fbd7ab8bb7 100644 (file)
@@ -36,10 +36,10 @@ struct private_alsa_write_data {
        snd_pcm_t *handle;
        /** Determined and set by alsa_open(). */
        int bytes_per_frame;
-       /** Don't write anything until this time. */
-       struct timeval next_chunk;
        /** The approximate maximum buffer duration in us. */
        unsigned buffer_time;
+       /* Number of frames that fit into the buffer. */
+       unsigned buffer_frames;
        /**
         * The samplerate given by command line option or the decoder
         * of the writer node group.
@@ -120,6 +120,8 @@ static int alsa_init(struct private_alsa_write_data *pad,
        PARA_INFO_LOG("bytes per frame: %d\n", pad->bytes_per_frame);
        if (snd_pcm_nonblock(pad->handle, 1))
                PARA_ERROR_LOG("failed to set nonblock mode\n");
+       pad->buffer_frames = 1000 * pad->buffer_time / pad->samplerate;
+       PARA_INFO_LOG("max buffered frames: %d\n", pad->buffer_frames);
        return 1;
 }
 
@@ -140,7 +142,6 @@ static int alsa_open(struct writer_node *wn)
        else
                pad->channels = conf->channels_arg;
        PARA_INFO_LOG("%d channel(s), %dHz\n", pad->channels, pad->samplerate);
-       tv_add(now, &(struct timeval){0, 100 * 1000}, &pad->next_chunk);
        return 1;
 }
 
@@ -148,17 +149,34 @@ static int alsa_write_pre_select(struct sched *s, struct writer_node *wn)
 {
        struct private_alsa_write_data *pad = wn->private_data;
        struct writer_node_group *wng = wn->wng;
-       struct timeval diff;
+       struct timeval tv;
+       snd_pcm_sframes_t avail, underrun;
 
-       if (!*wng->loaded)
+       if (!pad->handle)
                return 1;
-       if (tv_diff(now, &pad->next_chunk, &diff) < 0) {
-               if (tv_diff(&s->timeout, &diff, NULL) > 0)
-                       s->timeout = diff;
-       } else {
-               s->timeout.tv_sec = 0;
-               s->timeout.tv_usec = 1;
-       }
+       if (*wng->loaded - wn->written < pad->bytes_per_frame)
+               return 1;
+       /*
+        * Data is available to be written to the alsa handle.  Compute number
+        * of milliseconds until next buffer underrun would occur.
+        *
+        * snd_pcm_avail_update() updates the current available count of
+        * samples for writing.  It is a light method to obtain current stream
+        * position, because it does not require the user <-> kernel context
+        * switch, but the value is less accurate, because ring buffer pointers
+        * are updated in kernel drivers only when an interrupt occurs.
+        */
+       avail = snd_pcm_avail_update(pad->handle);
+       if (avail < 0)
+               avail = 0;
+       underrun = (pad->buffer_frames - avail) * pad->buffer_time
+               / pad->buffer_frames / 1000;
+       if (underrun < 50)
+               underrun = 50;
+       underrun -= 50;
+       ms2tv(underrun, &tv);
+       if (tv_diff(&s->timeout, &tv, NULL) > 0)
+               s->timeout = tv;
        return 1;
 }
 
@@ -169,7 +187,6 @@ static int alsa_write_post_select(__a_unused struct sched *s,
        struct writer_node_group *wng = wn->wng;
        size_t bytes = *wng->loaded - wn->written;
        unsigned char *data = (unsigned char*)*wng->bufp + wn->written;
-       struct timeval tv;
        snd_pcm_sframes_t ret, frames, avail;
 
        if (*wng->input_error < 0 && (!pad->handle || bytes < pad->bytes_per_frame)) {
@@ -178,8 +195,6 @@ static int alsa_write_post_select(__a_unused struct sched *s,
        }
        if (!bytes) /* no data available */
                return 0;
-       if (tv_diff(now, &pad->next_chunk, NULL) < 0)
-               return 0;
        if (!pad->handle) {
                int err = alsa_init(pad, wn->conf);
                if (err < 0)
@@ -190,26 +205,21 @@ static int alsa_write_post_select(__a_unused struct sched *s,
                return 0;
        avail = snd_pcm_avail_update(pad->handle);
        if (avail <= 0)
-               goto delay;
+               return 0;
        frames = PARA_MIN(frames, avail);
        ret = snd_pcm_writei(pad->handle, data, frames);
-       if (ret < 0) {
-               PARA_WARNING_LOG("%s\n", snd_strerror(-ret));
-               if (ret == -EPIPE) {
-                       snd_pcm_prepare(pad->handle);
-                       return 0;
-               }
-               if (ret == -EAGAIN)
-                       goto delay;
-               return -E_ALSA_WRITE;
+       if (ret >= 0) {
+               wn->written += ret * pad->bytes_per_frame;
+               return 1;
        }
-       wn->written += ret * pad->bytes_per_frame;
-       return 1;
-delay:
-       /* wait until 50% buffer space is available */
-       ms2tv(pad->buffer_time / 2000, &tv);
-       tv_add(now, &tv, &pad->next_chunk);
-       return 0;
+       PARA_WARNING_LOG("%s\n", snd_strerror(-ret));
+       if (ret == -EPIPE) {
+               snd_pcm_prepare(pad->handle);
+               return 0;
+       }
+       if (ret == -EAGAIN)
+               return 0;
+       return -E_ALSA_WRITE;
 }
 
 static void alsa_close(struct writer_node *wn)