This is update audacious to "recent" sndio changes, and few other
tweaks:

 - stop audio during pause to consume less cpu (accounted as sndio
   and interrupt cpu usage).

 - use sio_onvol() callback so get the volume, this way audacious can
   see volume changes from other programs.

 - remove checks for negative values passed to sio_onmove()
   callback. The api was simplified so this isn't needed anymore

 - make sndio backend the default pluggin on openbsd

 - add 24-bit encondings

Above bring new problems though. Audacious is multi-threaded with
respect to audio, write_audio() is called in the "audio thread", while
pause(), flush() and set_volume() are called from another
thread. Sndio requires calls to all sio_xxx functions to be
serialized. AFAICS the easier is to postpone execution of pause(),
flush() and set_volume() to the end of write_audio(), unless the later
in not running.

Comments? Ok?

-- Alexandre
Index: Makefile
===================================================================
RCS file: /cvs/ports/audio/audacious-plugins/Makefile,v
retrieving revision 1.39
diff -u -p -r1.39 Makefile
--- Makefile    17 Oct 2011 10:38:41 -0000      1.39
+++ Makefile    31 Jan 2012 08:59:27 -0000
@@ -8,7 +8,7 @@ COMMENT-jack =          jack plugin for audaciou
 V =                    2.4.5
 DISTNAME =             audacious-plugins-$V
 PKGNAME-main =         ${DISTNAME}
-REVISION-main =                3
+REVISION-main =                4
 PKGNAME-jack =         audacious-jack-$V
 REVISION-jack =                2
 
Index: files/sndio.c
===================================================================
RCS file: /cvs/ports/audio/audacious-plugins/files/sndio.c,v
retrieving revision 1.2
diff -u -p -r1.2 sndio.c
--- files/sndio.c       19 Dec 2010 18:19:56 -0000      1.2
+++ files/sndio.c       31 Jan 2012 08:59:27 -0000
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2008,2009 Thomas Pfaff <tpf...@tp76.info>
+ * Copyright (c) 2008, 2009 Thomas Pfaff <tpf...@tp76.info>
+ * Copyright (c) 2012 Alexandre Ratchov <a...@caoua.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -14,22 +15,24 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <sndio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-
+#include <pthread.h>
 #include <gtk/gtk.h>
 #include <libmcs/mcs.h>
-#include <sndio.h>
+#include <libaudgui/libaudgui.h>
+#include <libaudgui/libaudgui-gtk.h>
+#include <audacious/audconfig.h>
 #include <audacious/configdb.h>
 #include <audacious/i18n.h>
 #include <audacious/plugin.h>
-#include <libaudgui/libaudgui.h>
-#include <libaudgui/libaudgui-gtk.h>
 
 #include "config.h"
 
 OutputPluginInitStatus sndio_init(void);
+void   sndio_cleanup(void);
 void   sndio_about(void);
 void   sndio_configure(void);
 void   sndio_get_volume(gint *, gint *);
@@ -39,12 +42,12 @@ void        sndio_write(gpointer, gint);
 void   sndio_close(void);
 void   sndio_flush(gint);
 void   sndio_pause(gshort);
-gint   sndio_free(void);
-gint   sndio_playing(void);
 gint   sndio_output_time(void);
 gint   sndio_written_time(void);
+void   sndio_drain(void);
 
 void   onmove_cb(void *, int);
+void   onvol_cb(void *, unsigned);
 
 void   configure_win_ok_cb(GtkWidget *, gpointer);
 
@@ -52,9 +55,11 @@ static struct sio_par par;
 static struct sio_hdl *hdl;
 static long long rdpos;
 static long long wrpos;
-static int paused;
-static int volume;
-static long bytes_per_sec;
+static int paused, flushed, volume;
+static int flush_time, pause_flag, volume_target;
+static int writing, pause_pending, flush_pending, volume_pending;
+static int bytes_per_sec;
+static pthread_mutex_t mtx;
 
 static GtkWidget *configure_win;
 static GtkWidget *adevice_entry;
@@ -63,9 +68,10 @@ static gchar *audiodev;
 OutputPlugin sndio_op = {
        .description = "Sndio Output Plugin",
        .init = sndio_init,
-       .cleanup = NULL,
+       .cleanup = sndio_cleanup,
        .about = sndio_about,
        .configure = sndio_configure,
+       .probe_priority = 2,
        .get_volume = sndio_get_volume,
        .set_volume = sndio_set_volume,
        .open_audio = sndio_open,
@@ -73,16 +79,74 @@ OutputPlugin sndio_op = {
        .close_audio = sndio_close,
        .flush = sndio_flush,
        .pause = sndio_pause,
-       .buffer_free = sndio_free,
-       .buffer_playing = sndio_playing,
        .output_time = sndio_output_time,
-       .written_time = sndio_written_time
+       .written_time = sndio_written_time,
+       .drain = sndio_drain
 };
 
 OutputPlugin *sndio_oplist[] = { &sndio_op, NULL };
 
 SIMPLE_OUTPUT_PLUGIN(sndio, sndio_oplist);
 
+static struct fmt_to_par {
+       int fmt, bits, sig, le;
+} fmt_to_par[] = {
+       {FMT_S8,      8, 1, 0}, {FMT_U8,      8, 1, 0},
+       {FMT_S16_LE, 16, 1, 1}, {FMT_S16_BE, 16, 1, 0},
+       {FMT_U16_LE, 16, 0, 1}, {FMT_U16_BE, 16, 0, 0},
+       {FMT_S24_LE, 24, 1, 1}, {FMT_S24_BE, 24, 1, 0},
+       {FMT_U24_LE, 24, 0, 1}, {FMT_U24_BE, 24, 0, 0},
+       {FMT_S32_LE, 32, 1, 1}, {FMT_S32_BE, 32, 1, 0},
+       {FMT_U32_LE, 32, 0, 1}, {FMT_U32_BE, 32, 0, 0}
+};
+
+static void
+volume_do(int v)
+{
+       if (writing) {
+               volume_target = v;
+               volume_pending = 1;
+       } else {
+               if (hdl)
+                       sio_setvol(hdl, v * SIO_MAXVOL / 100);
+               volume_pending = 0;
+       }
+}
+
+static void
+pause_do(int flag)
+{
+       if (writing) {
+               pause_flag = flag;
+               pause_pending = 1;
+       } else {
+               if (flag && !paused && !flushed) {
+                       sio_stop(hdl);
+                       sio_start(hdl);
+                       rdpos = wrpos;
+               }
+               paused = flag;
+               pause_pending = 0;
+       }
+}
+
+static void
+flush_do(int time)
+{
+       if (writing) {
+               flush_time = time;
+               flush_pending = 1;
+       } else {
+               if (!paused && !flushed) {
+                       sio_stop(hdl);
+                       sio_start(hdl);
+               }
+               rdpos = wrpos = (long long)time * bytes_per_sec / 1000;
+               flush_pending = 0;
+               flushed = 1;
+       }
+}
+
 void
 sndio_about(void)
 {
@@ -99,144 +163,151 @@ sndio_init(void)
 {
        mcs_handle_t *cfgfile;
 
-       cfgfile = aud_cfg_db_open();
-       aud_cfg_db_get_int(cfgfile, "sndio", "volume", &volume);
-       aud_cfg_db_get_string(cfgfile, "sndio", "audiodev", &audiodev);
-       aud_cfg_db_close(cfgfile);
+       pthread_mutex_init(&mtx, NULL);
 
-       if (!volume)
+       cfgfile = aud_cfg_db_open();
+       if (!aud_cfg_db_get_int(cfgfile, "sndio", "volume", &volume))
                volume = 100;
-       if (!audiodev)
+       if (!aud_cfg_db_get_string(cfgfile, "sndio", "audiodev", &audiodev))
                audiodev = g_strdup("");
+       aud_cfg_db_close(cfgfile);
 
        return (OUTPUT_PLUGIN_INIT_FOUND_DEVICES);
 }
 
 void
+sndio_cleanup(void)
+{
+       mcs_handle_t *cfgfile;
+
+       cfgfile = aud_cfg_db_open();
+       aud_cfg_db_set_int(cfgfile, "sndio", "volume", volume);
+       aud_cfg_db_set_string(cfgfile, "sndio", "audiodev", audiodev);
+       aud_cfg_db_close(cfgfile);
+       pthread_mutex_destroy(&mtx);
+}
+
+void
 sndio_get_volume(gint *l, gint *r)
 {
+       pthread_mutex_lock(&mtx);
        *l = *r = volume;
+       pthread_mutex_unlock(&mtx);
 }
 
 void
 sndio_set_volume(gint l, gint r)
 {
        /* Ignore balance control, so use unattenuated channel. */
+       pthread_mutex_lock(&mtx);
        volume = l > r ? l : r;
-       if (hdl)
-               sio_setvol(hdl, volume * SIO_MAXVOL / 100);
+       volume_do(volume);
+       pthread_mutex_unlock(&mtx);
 }
 
 gint
 sndio_open(gint fmt, gint rate, gint nch)
 {
+       int i;
        struct sio_par askpar;
+       GtkWidget *dialog = NULL;
 
        hdl = sio_open(strlen(audiodev) > 0 ? audiodev : NULL, SIO_PLAY, 0);
        if (!hdl) {
                g_warning("failed to open audio device %s", audiodev);
                return (0);
        }
-
-       sio_initpar(&par);
-       switch (fmt) {
-       case FMT_U8:
-               par.bits = 8;
-               par.sig = 0;
-               break;
-       case FMT_S8:
-               par.bits = 8;
-               par.sig = 1;
-               break;
-       case FMT_U16_LE:
-               par.bits = 16;
-               par.sig = 0;
-               par.le = 1;
-               break;
-       case FMT_U16_BE:
-               par.bits = 16;
-               par.sig = 0;
-               par.le = 0;
-               break;
-       case FMT_S16_LE:
-               par.bits = 16;
-               par.sig = 1;
-               par.le = 1;
-               break;
-       case FMT_S16_BE:
-               par.bits = 16;
-               par.sig = 1;
-               par.le = 0;
-       default:
-               g_warning("unknown format %d requested", fmt);
-               sndio_close();
-               return (0);
+       sio_initpar(&askpar);
+       for (i = 0; ; i++) {
+               if (i == sizeof(fmt_to_par) / sizeof(struct fmt_to_par)) {
+                       g_warning("unknown format %d requested", fmt);
+                       sndio_close();
+                       return 0;
+               }
+               if (fmt_to_par[i].fmt == fmt)
+                       break;
        }
-       par.pchan = nch;
-       par.rate = rate;
-
-       /* 250 ms buffer */
-       par.appbufsz = par.rate / 4;
-
-       askpar = par;
-       if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par)) {
+       askpar.bits = fmt_to_par[i].bits;
+       askpar.bps = SIO_BPS(askpar.bits);
+       askpar.sig = fmt_to_par[i].sig;
+       if (askpar.bits > 8)
+               askpar.le = fmt_to_par[i].le;
+       askpar.pchan = nch;
+       askpar.rate = rate;
+       askpar.appbufsz = aud_cfg->output_buffer_size;
+       if (!sio_setpar(hdl, &askpar) || !sio_getpar(hdl, &par)) {
                g_warning("failed to set parameters");
                sndio_close();
                return (0);
        }
-
-       if ((par.bits == 16 && par.le != askpar.le) ||
-           par.bits != askpar.bits ||
+       if ((par.bps > 1 && par.le != askpar.le) ||
+           (par.bits < par.bps * 8 && !par.msb) ||
+           par.bps != askpar.bps ||
            par.sig != askpar.sig ||
            par.pchan != askpar.pchan ||
             par.rate != askpar.rate) {
-               GtkWidget *dialog = NULL;
-               g_warning("parameters not supported");
+               g_warning("parameters not supported by the audio device");
                audgui_simple_message(&dialog, GTK_MESSAGE_INFO,
                    _("Unsupported format"),
                    _("A format not supported by the audio device "
                    "was requested.\n\n"
-                   "Please try again with the aucat(1) server running."));
+                   "Please try again with the sndiod(1) server running."));
                sndio_close();
                return (0);
        }
-
        rdpos = 0;
        wrpos = 0;
        sio_onmove(hdl, onmove_cb, NULL);
-
-       paused = 0;
+       sio_onvol(hdl, onvol_cb, NULL);
+       volume_do(volume);
        if (!sio_start(hdl)) {
                g_warning("failed to start audio device");
                sndio_close();
                return (0);
        }
-
+       pause_pending = flush_pending = volume_pending = 0;
        bytes_per_sec = par.bps * par.pchan * par.rate;
-
-       sndio_set_volume(volume, volume);
+       flushed = 1;
+       paused = 0;
        return (1);
 }
 
 void
 sndio_write(gpointer ptr, gint length)
 {
-       if (!paused)
-               wrpos += sio_write(hdl, ptr, length);
+       unsigned n;
+
+       pthread_mutex_lock(&mtx);
+       flushed = 0;
+       if (!paused) {  
+               writing = 1;
+               pthread_mutex_unlock(&mtx);
+               n = sio_write(hdl, ptr, length);
+               pthread_mutex_lock(&mtx);
+               writing = 0;
+               wrpos += n;
+       }
+       for (;;) {
+               if (volume_pending)
+                       volume_do(volume);
+               if (flush_pending)
+                       flush_do(flush_time);
+               if (pause_pending)
+                       pause_do(pause_flag);
+               if (flushed || !paused)
+                       break;
+               pthread_mutex_unlock(&mtx);
+               usleep(10000);
+               pthread_mutex_lock(&mtx);
+       }
+       pthread_mutex_unlock(&mtx);
 }
 
 void
 sndio_close(void)
 {
-       mcs_handle_t *cfgfile;
-
        if (!hdl)
                return;
-
-       cfgfile = aud_cfg_db_open();
-       aud_cfg_db_set_int(cfgfile, "sndio", "volume", volume);
-       aud_cfg_db_close(cfgfile);
-
        sio_close(hdl);
        hdl = NULL;
 }
@@ -244,45 +315,63 @@ sndio_close(void)
 void
 sndio_flush(gint time)
 {
-       int bufused = (rdpos < 0) ? wrpos : wrpos - rdpos;
-       rdpos = time / 1000 * bytes_per_sec;
-       wrpos = rdpos + bufused;
+       pthread_mutex_lock(&mtx);
+       flush_do(time);
+       pthread_mutex_unlock(&mtx);
 }
 
 void
 sndio_pause(gshort flag)
-{
-       paused = flag;
-}
-
-gint
-sndio_free(void)
-{
-       return (paused ? 0 : 1000000);
+{      
+       pthread_mutex_lock(&mtx);
+       pause_do(flag);
+       pthread_mutex_unlock(&mtx);
 }
 
-gint
-sndio_playing(void)
+void
+sndio_drain(void)
 {
-       return (paused ? TRUE : FALSE);
+       /* sndio always drains */
 }
 
 gint
 sndio_output_time(void)
 {
-       return (hdl ? rdpos * 1000 / bytes_per_sec : 0);
+       int time;
+
+       pthread_mutex_lock(&mtx);
+       time = rdpos * 1000 / bytes_per_sec;
+       pthread_mutex_unlock(&mtx);
+       return time;
 }
 
 gint
 sndio_written_time(void)
 {
-       return (hdl ? wrpos * 1000 / bytes_per_sec : 0);
+       int time;
+
+       pthread_mutex_lock(&mtx);
+       time = wrpos * 1000 / bytes_per_sec;
+       pthread_mutex_unlock(&mtx);
+       return time;
 }
 
 void
 onmove_cb(void *addr, int delta)
 {
-       rdpos += delta *(int)(par.bps * par.pchan);
+       pthread_mutex_lock(&mtx);
+       rdpos += delta * (int)(par.bps * par.pchan);
+       pthread_mutex_unlock(&mtx);
+}
+
+void
+onvol_cb(void *addr, unsigned ctl)
+{
+       /* Update volume only if it actually changed */
+       pthread_mutex_lock(&mtx);
+       if (ctl != volume * SIO_MAXVOL / 100)
+               volume = ctl * 100 / SIO_MAXVOL;
+       pthread_mutex_unlock(&mtx);
 }
 
 void

Reply via email to