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)
1  2 
NEWS
alsa_write.c

diff --combined NEWS
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -1,30 -1,14 +1,34 @@@
  NEWS
  ====
  
 +---------------------------------------------------
 +0.4.0 (to be announced) "simultaneous independence"
 +---------------------------------------------------
 +
 +Two significant changes which require the new version number: The
 +improved authentication dialog and the fact that the database code
 +has been moved to a library, libosl. To use the new version, you have
 +to generate new RSA keys, see INSTALL for details. A shell script is
 +provided for conversion of the 0.3 database to the new 0.4 format.
 +
 +      - stronger crypto for client authentication
 +      - the database code has been moved to a library
 +      - improved status item handling
 +      - the new parser-friendly listing mode for the ls and stat commands
 +      - mandatory rc4 encryption
 +      - major audio format handler cleanups
 +      - (id3,...) tags are no longer stored as a combined string in the database
 +      - new mood methods: artist_matches, title_matches, comment_matches,
 +        album_matches, year_maches, year.
 +
  -------------------------------------------------
  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
diff --combined alsa_write.c
@@@ -12,7 -12,6 +12,7 @@@
   * based on the vplay program by Michael Beck.
   */
  
 +#include <regex.h>
  #include <sys/types.h>
  #include <dirent.h>
  #include <alsa/asoundlib.h>
@@@ -36,10 -35,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 -119,8 +120,8 @@@ static int alsa_init(struct private_als
        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 -141,6 +142,6 @@@ static int alsa_open(struct writer_nod
        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 -148,34 +149,34 @@@ static int alsa_write_pre_select(struc
  {
        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 -186,6 +187,6 @@@ static int alsa_write_post_select(__a_u
        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)) {
        }
        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)
                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)