speechd-discuss
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] move audio source out of the modules directory


From: William Hubbs
Subject: [PATCH] move audio source out of the modules directory
Date: Wed, 23 Feb 2011 10:46:52 -0600

Since the audio plugins are independent of the modules now, we can move
the audio source directory outside of the modules directory.
---
 configure.ac                  |   12 +-
 src/Makefile.am               |    2 +-
 src/audio/.gitignore          |    1 +
 src/audio/Makefile.am         |   45 ++
 src/audio/alsa.c              |  883 +++++++++++++++++++++++++++++++++++++++++
 src/audio/libao.c             |  246 ++++++++++++
 src/audio/nas.c               |  263 ++++++++++++
 src/audio/oss.c               |  523 ++++++++++++++++++++++++
 src/audio/pulse.c             |  310 +++++++++++++++
 src/modules/Makefile.am       |    2 -
 src/modules/audio/.gitignore  |    1 -
 src/modules/audio/Makefile.am |   45 --
 src/modules/audio/alsa.c      |  883 -----------------------------------------
 src/modules/audio/libao.c     |  246 ------------
 src/modules/audio/nas.c       |  263 ------------
 src/modules/audio/oss.c       |  523 ------------------------
 src/modules/audio/pulse.c     |  310 ---------------
 17 files changed, 2278 insertions(+), 2280 deletions(-)
 create mode 100644 src/audio/.gitignore
 create mode 100644 src/audio/Makefile.am
 create mode 100644 src/audio/alsa.c
 create mode 100644 src/audio/libao.c
 create mode 100644 src/audio/nas.c
 create mode 100644 src/audio/oss.c
 create mode 100644 src/audio/pulse.c
 delete mode 100644 src/modules/audio/.gitignore
 delete mode 100644 src/modules/audio/Makefile.am
 delete mode 100644 src/modules/audio/alsa.c
 delete mode 100644 src/modules/audio/libao.c
 delete mode 100644 src/modules/audio/nas.c
 delete mode 100644 src/modules/audio/oss.c
 delete mode 100644 src/modules/audio/pulse.c

diff --git a/configure.ac b/configure.ac
index 079de31..7c67ef3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -212,7 +212,7 @@ AS_IF([test $with_pulse != "no"],
                [with_pulse=yes
                AS_IF([test -z "$default_audio_method"],
                        [default_audio_method=pulse])
-               audio_dlopen_modules="$audio_dlopen_modules -dlopen 
audio/spd_pulse.la"],
+               audio_dlopen_modules="$audio_dlopen_modules -dlopen 
../audio/spd_pulse.la"],
                [AS_IF([test $with_pulse = "yes"],
                        [AC_MSG_FAILURE([pulseaudio is not available])])])])
 AM_CONDITIONAL([pulse_support], [test $with_pulse = "yes"])
@@ -229,7 +229,7 @@ AS_IF([test $with_alsa != "no"],
                [with_alsa=yes
                AS_IF([test -z "$default_audio_method"],
                        [default_audio_method=alsa])
-               audio_dlopen_modules="$audio_dlopen_modules -dlopen 
audio/spd_alsa.la"],
+               audio_dlopen_modules="$audio_dlopen_modules -dlopen 
../audio/spd_alsa.la"],
                [AS_IF([test $with_alsa = "yes"],
                        [AC_MSG_FAILURE([ALSA is not available])])])])
 AM_CONDITIONAL([alsa_support], [test $with_alsa = "yes"])
@@ -246,7 +246,7 @@ AS_IF([test $with_libao != "no"],
                [with_libao=yes
                AS_IF([test -z "$default_audio_method"],
                        [default_audio_method=libao])
-               audio_dlopen_modules="$audio_dlopen_modules -dlopen 
audio/spd_libao.la"],
+               audio_dlopen_modules="$audio_dlopen_modules -dlopen 
../audio/spd_libao.la"],
                [AS_IF([test $with_libao = yes],
                        [AC_MSG_FAILURE([libao is not available])])])])
 AM_CONDITIONAL([libao_support], [test $with_libao = "yes"])
@@ -263,7 +263,7 @@ AS_IF([test $with_oss != "no"],
                [with_oss=yes
                AS_IF([test -z "$default_audio_method"],
                        [default_audio_method=oss])
-               audio_dlopen_modules="$audio_dlopen_modules -dlopen 
audio/spd_oss.la"],
+               audio_dlopen_modules="$audio_dlopen_modules -dlopen 
../audio/spd_oss.la"],
                [AS_IF([test $with_oss = "yes"],
                        [AC_MSG_FAILURE([oss is not available])])])])
 AM_CONDITIONAL([oss_support], [test $with_oss = "yes"])
@@ -278,7 +278,7 @@ AS_IF([test $with_nas != "no"],
                [with_nas=yes
                AS_IF([test -z "$default_audio_method"],
                        [default_audio_method=nas])
-               audio_dlopen_modules="$audio_dlopen_modules -dlopen 
audio/spd_nas.la";
+               audio_dlopen_modules="$audio_dlopen_modules -dlopen 
../../audio/spd_nas.la";
                NAS_LIBS="-L/usr/X11R6/lib -lXau -laudio"],
                [AS_IF([test $with_nas = "yes"],
                        [AC_MSG_FAILURE([nas is not available])])],
@@ -361,12 +361,12 @@ AC_CONFIG_FILES([Makefile
                  src/api/python/Makefile
                  src/api/python/speechd/Makefile
                  src/api/python/speechd_config/Makefile
+                 src/audio/Makefile
                  src/clients/Makefile
                  src/clients/say/Makefile
                  src/clients/spdsend/Makefile
                  src/common/Makefile
                  src/modules/Makefile
-                 src/modules/audio/Makefile
                  src/server/Makefile
                  src/tests/Makefile])
 AC_OUTPUT
diff --git a/src/Makefile.am b/src/Makefile.am
index f2da76d..81d0690 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS=common server modules api clients tests
+SUBDIRS=common server audio modules api clients tests
 
diff --git a/src/audio/.gitignore b/src/audio/.gitignore
new file mode 100644
index 0000000..f75f98e
--- /dev/null
+++ b/src/audio/.gitignore
@@ -0,0 +1 @@
+static_plugins.c
diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am
new file mode 100644
index 0000000..d84fcdb
--- /dev/null
+++ b/src/audio/Makefile.am
@@ -0,0 +1,45 @@
+## Process this file with automake to produce Makefile.in
+
+inc_local = -I$(top_srcdir)/include/
+
+audio_LTLIBRARIES =
+
+if alsa_support
+audio_LTLIBRARIES +=  spd_alsa.la
+spd_alsa_la_SOURCES = alsa.c
+spd_alsa_la_CPPFLAGS = $(GLIB_CFLAGS) $(inc_local)  $(ALSA_CFLAGS)
+spd_alsa_la_LIBADD = $(ALSA_LIBS) $(GLIB_LIBS)
+spd_alsa_la_LDFLAGS = -module -avoid-version
+endif
+
+if libao_support
+audio_LTLIBRARIES +=  spd_libao.la
+spd_libao_la_SOURCES = libao.c
+spd_libao_la_CPPFLAGS = $(GLIB_CFLAGS) $(inc_local)  $(LIBAO_CFLAGS)
+spd_libao_la_LIBADD = $(LIBAO_LIBS) $(GLIB_LIBS)
+spd_libao_la_LDFLAGS = -module -avoid-version
+endif
+
+if nas_support
+audio_LTLIBRARIES +=  spd_nas.la
+spd_nas_la_SOURCES = nas.c
+spd_nas_la_CPPFLAGS = $(GLIB_CFLAGS) $(inc_local)
+spd_nas_la_LIBADD = $(NAS_LIBS) $(GLIB_LIBS)
+spd_nas_la_LDFLAGS = -module -avoid-version
+endif
+
+if oss_support
+audio_LTLIBRARIES +=  spd_oss.la
+spd_oss_la_SOURCES = oss.c
+spd_oss_la_CPPFLAGS = $(GLIB_CFLAGS) $(inc_local)
+spd_oss_la_LIBADD = $(GLIB_LIBS)
+spd_oss_la_LDFLAGS = -module -avoid-version
+endif
+
+if pulse_support
+audio_LTLIBRARIES +=  spd_pulse.la
+spd_pulse_la_SOURCES = pulse.c
+spd_pulse_la_CPPFLAGS = $(GLIB_CFLAGS) $(inc_local)  $(PULSE_CFLAGS)
+spd_pulse_la_LIBADD = $(PULSE_LIBS) $(GLIB_LIBS)
+spd_pulse_la_LDFLAGS = -module -avoid-version
+endif
diff --git a/src/audio/alsa.c b/src/audio/alsa.c
new file mode 100644
index 0000000..4e20a54
--- /dev/null
+++ b/src/audio/alsa.c
@@ -0,0 +1,883 @@
+
+/*
+ * alsa.c -- The Advanced Linux Sound System backend for Speech Dispatcher
+ *
+ * Copyright (C) 2005,2006 Brailcom, o.p.s.
+ *
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this package; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * $Id: alsa.c,v 1.30 2008-10-15 17:27:32 hanke Exp $
+ */
+
+/* NOTE: This module uses the non-blocking write() / poll() approach to
+    alsa-lib functions.*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+#include <pthread.h>
+#include <glib.h>
+
+#include <alsa/asoundlib.h>
+
+#define SPD_AUDIO_PLUGIN_ENTRY spd_alsa_LTX_spd_audio_plugin_get
+#include <spd_audio_plugin.h>
+
+typedef struct {
+       AudioID id;
+       snd_pcm_t *alsa_pcm;    /* identifier of the ALSA device */
+       snd_pcm_hw_params_t *alsa_hw_params;    /* parameters of sound */
+       snd_pcm_sw_params_t *alsa_sw_params;    /* parameters of playback */
+       snd_pcm_uframes_t alsa_buffer_size;
+       pthread_mutex_t alsa_pcm_mutex; /* mutex to guard the state of the 
device */
+       pthread_mutex_t alsa_pipe_mutex;        /* mutex to guard the stop 
pipes */
+       int alsa_stop_pipe[2];  /* Pipe for communication about stop requests */
+       int alsa_fd_count;      /* Counter of descriptors to poll */
+       struct pollfd *alsa_poll_fds;   /* Descriptors to poll */
+       int alsa_opened;        /* 1 between snd_pcm_open and _close, 0 
otherwise */
+       char *alsa_device_name; /* the name of the device to open */
+} spd_alsa_id_t;
+
+static int _alsa_close(spd_alsa_id_t * id);
+static int _alsa_open(spd_alsa_id_t * id);
+
+static int xrun(spd_alsa_id_t * id);
+static int suspend(spd_alsa_id_t * id);
+
+static int wait_for_poll(spd_alsa_id_t * id, struct pollfd *alsa_poll_fds,
+                        unsigned int count, int draining);
+
+#ifndef timersub
+#define        timersub(a, b, result) \
+do { \
+         (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+        (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+        if ((result)->tv_usec < 0) { \
+                --(result)->tv_sec; \
+                (result)->tv_usec += 1000000; \
+        } \
+ } while (0)
+#endif
+
+/* Put a message into the logfile (stderr) */
+#define MSG(level, arg...) \
+ if(level <= alsa_log_level){ \
+     time_t t; \
+     struct timeval tv; \
+     char *tstr; \
+     t = time(NULL); \
+     tstr = g_strdup(ctime(&t)); \
+     tstr[strlen(tstr)-1] = 0; \
+     gettimeofday(&tv,NULL); \
+     fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \
+     fprintf(stderr," ALSA: "); \
+     fprintf(stderr,arg); \
+     fprintf(stderr,"\n"); \
+     fflush(stderr); \
+     g_free(tstr); \
+  }
+
+#define ERR(arg...) \
+ { \
+     time_t t; \
+     struct timeval tv; \
+     char *tstr; \
+     t = time(NULL); \
+     tstr = g_strdup(ctime(&t)); \
+     tstr[strlen(tstr)-1] = 0; \
+     gettimeofday(&tv,NULL); \
+     fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \
+     fprintf(stderr," ALSA ERROR: "); \
+     fprintf(stderr,arg); \
+     fprintf(stderr,"\n"); \
+     fflush(stderr); \
+     g_free(tstr); \
+  }
+
+static int alsa_log_level;
+static char const *alsa_play_cmd = "aplay";
+
+/* I/O error handler */
+static int xrun(spd_alsa_id_t * id)
+{
+       snd_pcm_status_t *status;
+       int res;
+
+       if (id == NULL)
+               return -1;
+
+       MSG(1, "WARNING: Entering XRUN handler");
+
+       snd_pcm_status_alloca(&status);
+       if ((res = snd_pcm_status(id->alsa_pcm, status)) < 0) {
+               ERR("status error: %s", snd_strerror(res));
+
+               return -1;
+       }
+       if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
+               struct timeval now, diff, tstamp;
+               gettimeofday(&now, 0);
+               snd_pcm_status_get_trigger_tstamp(status, &tstamp);
+               timersub(&now, &tstamp, &diff);
+               MSG(1, "underrun!!! (at least %.3f ms long)",
+                   diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
+               if ((res = snd_pcm_prepare(id->alsa_pcm)) < 0) {
+                       ERR("xrun: prepare error: %s", snd_strerror(res));
+
+                       return -1;
+               }
+
+               return 0;       /* ok, data should be accepted again */
+       }
+       ERR("read/write error, state = %s",
+           snd_pcm_state_name(snd_pcm_status_get_state(status)));
+
+       return -1;
+}
+
+/* I/O suspend handler */
+static int suspend(spd_alsa_id_t * id)
+{
+       int res;
+
+       MSG(1, "WARNING: Entering SUSPEND handler.");
+
+       if (id == NULL)
+               return -1;
+
+       while ((res = snd_pcm_resume(id->alsa_pcm)) == -EAGAIN)
+               sleep(1);       /* wait until suspend flag is released */
+
+       if (res < 0) {
+               if ((res = snd_pcm_prepare(id->alsa_pcm)) < 0) {
+                       ERR("suspend: prepare error: %s", snd_strerror(res));
+
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/* Open the device so that it's ready for playing on the default
+   device. Internal function used by the public alsa_open. */
+static int _alsa_open(spd_alsa_id_t * id)
+{
+       int err;
+
+       MSG(1, "Opening ALSA device");
+       fflush(stderr);
+
+       /* Open the device */
+       if ((err = snd_pcm_open(&id->alsa_pcm, id->alsa_device_name,
+                               SND_PCM_STREAM_PLAYBACK,
+                               SND_PCM_NONBLOCK)) < 0) {
+               ERR("Cannot open audio device %s (%s)", id->alsa_device_name,
+                   snd_strerror(err));
+               return -1;
+       }
+
+       /* Allocate space for hw_params (description of the sound parameters) */
+       /* Allocate space for sw_params (description of the sound parameters) */
+       MSG(2, "Allocating new sw_params structure");
+       if ((err = snd_pcm_sw_params_malloc(&id->alsa_sw_params)) < 0) {
+               ERR("Cannot allocate hardware parameter structure (%s)",
+                   snd_strerror(err));
+               return -1;
+       }
+
+       MSG(1, "Opening ALSA device ... success");
+
+       return 0;
+}
+
+/* 
+   Close the device. Internal function used by public alsa_close. 
+*/
+
+static int _alsa_close(spd_alsa_id_t * id)
+{
+       int err;
+
+       MSG(1, "Closing ALSA device");
+
+       if (id->alsa_opened == 0)
+               return 0;
+
+       pthread_mutex_lock(&id->alsa_pipe_mutex);
+       id->alsa_opened = 0;
+
+       if ((err = snd_pcm_close(id->alsa_pcm)) < 0) {
+               MSG(2, "Cannot close ALSA device (%s)", snd_strerror(err));
+               return -1;
+       }
+
+       snd_pcm_sw_params_free(id->alsa_sw_params);
+
+       g_free(id->alsa_poll_fds);
+       pthread_mutex_unlock(&id->alsa_pipe_mutex);
+
+       MSG(1, "Closing ALSA device ... success");
+
+       return 0;
+}
+
+/* Open ALSA for playback.
+  
+  These parameters are passed in pars:
+  (char*) pars[0] ... null-terminated string containing the name
+                      of the device to be used for sound output
+                      on ALSA
+  (void*) pars[1] ... =NULL
+*/
+static AudioID *alsa_open(void **pars)
+{
+       spd_alsa_id_t *alsa_id;
+       int ret;
+
+       if (pars[1] == NULL) {
+               ERR("Can't open ALSA sound output, missing parameters in 
argument.");
+               return NULL;
+       }
+
+       alsa_id = (spd_alsa_id_t *) g_malloc(sizeof(spd_alsa_id_t));
+
+       pthread_mutex_init(&alsa_id->alsa_pipe_mutex, NULL);
+
+       alsa_id->alsa_opened = 0;
+
+       MSG(1, "Opening ALSA sound output");
+
+       alsa_id->alsa_device_name = g_strdup(pars[1]);
+
+       ret = _alsa_open(alsa_id);
+       if (ret) {
+               ERR("Cannot initialize Alsa device '%s': Can't open.",
+                   alsa_id->alsa_device_name);
+               g_free(alsa_id);
+               return NULL;
+       }
+
+       MSG(1, "Device '%s' initialized succesfully.",
+           alsa_id->alsa_device_name);
+
+       return (AudioID *) alsa_id;
+}
+
+/* Close ALSA */
+static int alsa_close(AudioID * id)
+{
+       int err;
+       spd_alsa_id_t *alsa_id = (spd_alsa_id_t *) id;
+
+       /* Close device */
+       if ((err = _alsa_close(alsa_id)) < 0) {
+               ERR("Cannot close audio device");
+               return -1;
+       }
+       MSG(1, "ALSA closed.");
+
+       g_free(alsa_id->alsa_device_name);
+       g_free(alsa_id);
+       id = NULL;
+
+       return 0;
+}
+
+/* Wait until ALSA is readdy for more samples or alsa_stop() was called.
+
+Returns 0 if ALSA is ready for more input, +1 if a request to stop
+the sound output was received and a negative value on error.  */
+
+int wait_for_poll(spd_alsa_id_t * id, struct pollfd *alsa_poll_fds,
+                 unsigned int count, int draining)
+{
+       unsigned short revents;
+       snd_pcm_state_t state;
+       int ret;
+
+       //      MSG("Waiting for poll");
+
+       /* Wait for certain events */
+       while (1) {
+               ret = poll(id->alsa_poll_fds, count, -1);
+               //      MSG("wait_for_poll: activity on %d descriptors", ret);
+
+               /* Check for stop request from alsa_stop on the last file
+                  descriptors */
+               revents = id->alsa_poll_fds[count - 1].revents;
+               if (0 != revents) {
+                       if (revents & POLLIN) {
+                               MSG(4, "wait_for_poll: stop requested");
+                               return 1;
+                       }
+               }
+
+               /* Check the first count-1 descriptors for ALSA events */
+               snd_pcm_poll_descriptors_revents(id->alsa_pcm,
+                                                id->alsa_poll_fds, count - 1,
+                                                &revents);
+
+               /* Ensure we are in the right state */
+               state = snd_pcm_state(id->alsa_pcm);
+               //      MSG("State after poll returned is %s", 
snd_pcm_state_name(state));
+
+               if (SND_PCM_STATE_XRUN == state) {
+                       if (!draining) {
+                               MSG(1, "WARNING: Buffer underrun detected!");
+                               if (xrun(id) != 0)
+                                       return -1;
+                               return 0;
+                       } else {
+                               MSG(4, "Poll: Playback terminated");
+                               return 0;
+                       }
+               }
+
+               if (SND_PCM_STATE_SUSPENDED == state) {
+                       MSG(1, "WARNING: Suspend detected!");
+                       if (suspend(id) != 0)
+                               return -1;
+                       return 0;
+               }
+
+               /* Check for errors */
+               if (revents & POLLERR) {
+                       MSG(4, "wait_for_poll: poll revents says POLLERR");
+                       return -EIO;
+               }
+
+               /* Is ALSA ready for more input? */
+               if ((revents & POLLOUT)) {
+                       // MSG("Poll: Ready for more input");
+                       return 0;
+               }
+       }
+}
+
+#define ERROR_EXIT()\
+    g_free(track_volume.samples); \
+    ERR("alsa_play() abnormal exit"); \
+    _alsa_close(alsa_id); \
+    return -1;
+
+/* Play the track _track_ (see spd_audio.h) using the id->alsa_pcm device and
+ id-hw_params parameters. This is a blocking function, however, it's possible
+ to interrupt playing from a different thread with alsa_stop(). alsa_play
+ returns after and immediatelly after the whole sound was played on the
+ speakers.
+
+ The idea is that we get the ALSA file descriptors and we will poll() to see
+ when alsa is ready for more input while sleeping in the meantime. We will
+ additionally poll() for one more descriptor used by alsa_stop() to notify the
+ thread with alsa_play() that the stop of the playback is requested. The
+ variable can_be_stopped is used for very simple synchronization between the
+ two threads. */
+static int alsa_play(AudioID * id, AudioTrack track)
+{
+       snd_pcm_format_t format;
+       int bytes_per_sample;
+       int num_bytes;
+       spd_alsa_id_t *alsa_id = (spd_alsa_id_t *) id;
+
+       signed short *output_samples;
+
+       AudioTrack track_volume;
+       float real_volume;
+       int i;
+
+       int err;
+       int ret;
+
+       snd_pcm_uframes_t framecount;
+       snd_pcm_uframes_t period_size;
+       size_t samples_per_period;
+       size_t silent_samples;
+       size_t volume_size;
+       unsigned int sr;
+
+       snd_pcm_state_t state;
+
+       struct pollfd alsa_stop_pipe_pfd;
+
+       if (alsa_id == NULL) {
+               ERR("Invalid device passed to alsa_play()");
+               return -1;
+       }
+
+       pthread_mutex_lock(&alsa_id->alsa_pipe_mutex);
+
+       MSG(2, "Start of playback on ALSA");
+
+       /* Is it not an empty track? */
+       /* Passing an empty track is not an error */
+       if (track.samples == NULL) {
+               pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
+               return 0;
+       }
+       /* Allocate space for hw_params (description of the sound parameters) */
+       MSG(2, "Allocating new hw_params structure");
+       if ((err = snd_pcm_hw_params_malloc(&alsa_id->alsa_hw_params)) < 0) {
+               ERR("Cannot allocate hardware parameter structure (%s)",
+                   snd_strerror(err));
+               pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
+               return -1;
+       }
+
+       /* Initialize hw_params on our pcm */
+       if ((err =
+            snd_pcm_hw_params_any(alsa_id->alsa_pcm,
+                                  alsa_id->alsa_hw_params)) < 0) {
+               ERR("Cannot initialize hardware parameter structure (%s)",
+                   snd_strerror(err));
+               pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
+               return -1;
+       }
+
+       /* Create the pipe for communication about stop requests */
+       if (pipe(alsa_id->alsa_stop_pipe)) {
+               ERR("Stop pipe creation failed (%s)", strerror(errno));
+               pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
+               return -1;
+       }
+
+       /* Find how many descriptors we will get for poll() */
+       alsa_id->alsa_fd_count =
+           snd_pcm_poll_descriptors_count(alsa_id->alsa_pcm);
+       if (alsa_id->alsa_fd_count <= 0) {
+               ERR("Invalid poll descriptors count returned from ALSA.");
+               pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
+               return -1;
+       }
+
+       /* Create and fill in struct pollfd *alsa_poll_fds with ALSA 
descriptors */
+       alsa_id->alsa_poll_fds =
+           g_malloc((alsa_id->alsa_fd_count + 1) * sizeof(struct pollfd));
+       assert(alsa_id->alsa_poll_fds);
+       if ((err =
+            snd_pcm_poll_descriptors(alsa_id->alsa_pcm, alsa_id->alsa_poll_fds,
+                                     alsa_id->alsa_fd_count)) < 0) {
+               ERR("Unable to obtain poll descriptors for playback: %s\n",
+                   snd_strerror(err));
+               pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
+               return -1;
+       }
+
+       /* Create a new pollfd structure for requests by alsa_stop() */
+       alsa_stop_pipe_pfd.fd = alsa_id->alsa_stop_pipe[0];
+       alsa_stop_pipe_pfd.events = POLLIN;
+       alsa_stop_pipe_pfd.revents = 0;
+
+       /* Join this our own pollfd to the ALSAs ones */
+       alsa_id->alsa_poll_fds[alsa_id->alsa_fd_count] = alsa_stop_pipe_pfd;
+       alsa_id->alsa_fd_count++;
+
+       alsa_id->alsa_opened = 1;
+       pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
+
+       /* Report current state */
+       state = snd_pcm_state(alsa_id->alsa_pcm);
+       MSG(4, "PCM state before setting audio parameters: %s",
+           snd_pcm_state_name(state));
+
+       /* Choose the correct format */
+       if (track.bits == 16) {
+               switch (alsa_id->id.format) {
+               case SPD_AUDIO_LE:
+                       format = SND_PCM_FORMAT_S16_LE;
+                       break;
+               case SPD_AUDIO_BE:
+                       format = SND_PCM_FORMAT_S16_BE;
+                       break;
+               default:
+                       ERR("unknown audio format (%d)", alsa_id->id.format);
+                       return -1;
+               }
+               bytes_per_sample = 2;
+       } else if (track.bits == 8) {
+               bytes_per_sample = 1;
+               format = SND_PCM_FORMAT_S8;
+       } else {
+               ERR("Unsupported sound data format, track.bits = %d",
+                   track.bits);
+               return -1;
+       }
+
+       /* Set access mode, bitrate, sample rate and channels */
+       MSG(4, "Setting access type to INTERLEAVED");
+       if ((err = snd_pcm_hw_params_set_access(alsa_id->alsa_pcm,
+                                               alsa_id->alsa_hw_params,
+                                               SND_PCM_ACCESS_RW_INTERLEAVED)
+           ) < 0) {
+               ERR("Cannot set access type (%s)", snd_strerror(err));
+               return -1;
+       }
+
+       MSG(4, "Setting sample format to %s", snd_pcm_format_name(format));
+       if ((err =
+            snd_pcm_hw_params_set_format(alsa_id->alsa_pcm,
+                                         alsa_id->alsa_hw_params,
+                                         format)) < 0) {
+               ERR("Cannot set sample format (%s)", snd_strerror(err));
+               return -1;
+       }
+
+       MSG(4, "Setting sample rate to %i", track.sample_rate);
+       sr = track.sample_rate;
+       if ((err =
+            snd_pcm_hw_params_set_rate_near(alsa_id->alsa_pcm,
+                                            alsa_id->alsa_hw_params, &sr,
+                                            0)) < 0) {
+               ERR("Cannot set sample rate (%s)", snd_strerror(err));
+
+               return -1;
+       }
+
+       MSG(4, "Setting channel count to %i", track.num_channels);
+       if ((err =
+            snd_pcm_hw_params_set_channels(alsa_id->alsa_pcm,
+                                           alsa_id->alsa_hw_params,
+                                           track.num_channels)) < 0) {
+               MSG(4, "cannot set channel count (%s)", snd_strerror(err));
+               return -1;
+       }
+
+       MSG(4, "Setting hardware parameters on the ALSA device");
+       if ((err =
+            snd_pcm_hw_params(alsa_id->alsa_pcm,
+                              alsa_id->alsa_hw_params)) < 0) {
+               MSG(4, "cannot set parameters (%s) state=%s", snd_strerror(err),
+                   snd_pcm_state_name(snd_pcm_state(alsa_id->alsa_pcm)));
+               return -1;
+       }
+
+       /* Get the current swparams */
+       if ((err =
+            snd_pcm_sw_params_current(alsa_id->alsa_pcm,
+                                      alsa_id->alsa_sw_params)) < 0) {
+               ERR("Unable to determine current swparams for playback: %s\n",
+                   snd_strerror(err));
+               return -1;
+       }
+       //    MSG("Checking buffer size");
+       if ((err =
+            snd_pcm_hw_params_get_buffer_size(alsa_id->alsa_hw_params,
+                                              &(alsa_id->alsa_buffer_size))) <
+           0) {
+               ERR("Unable to get buffer size for playback: %s\n",
+                   snd_strerror(err));
+               return -1;
+       }
+       MSG(4, "Buffer size on ALSA device is %d bytes",
+           (int)alsa_id->alsa_buffer_size);
+
+       /* This is probably better left for the device driver to decide */
+       /* allow the transfer when at least period_size samples can be 
processed */
+       /*    err = snd_pcm_sw_params_set_avail_min(id->alsa_pcm, 
id->alsa_sw_params, id->alsa_buffer_size/4);
+          if (err < 0) {
+          ERR("Unable to set avail min for playback: %s\n", snd_strerror(err));
+          return err;
+          } */
+
+       /* Get period size. */
+       snd_pcm_hw_params_get_period_size(alsa_id->alsa_hw_params, &period_size,
+                                         0);
+
+       /* Calculate size of silence at end of buffer. */
+       samples_per_period = period_size * track.num_channels;
+       //    MSG("samples per period = %i", samples_per_period);
+       //    MSG("num_samples = %i", track.num_samples);
+       silent_samples =
+           samples_per_period - (track.num_samples % samples_per_period);
+       //    MSG("silent samples = %i", silent_samples);
+
+       MSG(4, "Preparing device for playback");
+       if ((err = snd_pcm_prepare(alsa_id->alsa_pcm)) < 0) {
+               ERR("Cannot prepare audio interface for playback (%s)",
+                   snd_strerror(err));
+
+               return -1;
+       }
+
+       /* Calculate space needed to round up to nearest period size. */
+       volume_size = bytes_per_sample * (track.num_samples + silent_samples);
+       MSG(4, "volume size = %i", (int)volume_size);
+
+       /* Create a copy of track with adjusted volume. */
+       MSG(4, "Making copy of track and adjusting volume");
+       track_volume = track;
+       track_volume.samples = (short *)g_malloc(volume_size);
+       real_volume = ((float)alsa_id->id.volume + 100) / (float)200;
+       for (i = 0; i <= track.num_samples - 1; i++)
+               track_volume.samples[i] = track.samples[i] * real_volume;
+
+       if (silent_samples > 0) {
+               u_int16_t silent16;
+               u_int8_t silent8;
+
+               /* Fill remaining space with silence */
+               MSG(4,
+                   "Filling with silence up to the period size, 
silent_samples=%d",
+                   (int)silent_samples);
+               /* TODO: This hangs.  Why?
+                  snd_pcm_format_set_silence(format,
+                  track_volume.samples + (track.num_samples * 
bytes_per_sample), silent_samples);
+                */
+               switch (bytes_per_sample) {
+               case 2:
+                       silent16 = snd_pcm_format_silence_16(format);
+                       for (i = 0; i < silent_samples; i++)
+                               track_volume.samples[track.num_samples + i] =
+                                   silent16;
+                       break;
+               case 1:
+                       silent8 = snd_pcm_format_silence(format);
+                       for (i = 0; i < silent_samples; i++)
+                               track_volume.samples[track.num_samples + i] =
+                                   silent8;
+                       break;
+               }
+       }
+
+       /* Loop until all samples are played on the device. */
+       output_samples = track_volume.samples;
+       num_bytes = (track.num_samples + silent_samples) * bytes_per_sample;
+       //    MSG("Still %d bytes left to be played", num_bytes);
+       while (num_bytes > 0) {
+
+               /* Write as much samples as possible */
+               framecount = num_bytes / bytes_per_sample / track.num_channels;
+               if (framecount < period_size)
+                       framecount = period_size;
+
+               /* Report current state state */
+               state = snd_pcm_state(alsa_id->alsa_pcm);
+               //      MSG("PCM state before writei: %s",
+               //          snd_pcm_state_name(state));
+
+               /* MSG("snd_pcm_writei() called") */
+               ret =
+                   snd_pcm_writei(alsa_id->alsa_pcm, output_samples,
+                                  framecount);
+               //        MSG("Sent %d of %d remaining bytes", 
ret*bytes_per_sample, num_bytes);
+
+               if (ret == -EAGAIN) {
+                       MSG(4, "Warning: Forced wait!");
+                       snd_pcm_wait(alsa_id->alsa_pcm, 100);
+               } else if (ret == -EPIPE) {
+                       if (xrun(alsa_id) != 0)
+                               ERROR_EXIT();
+               } else if (ret == -ESTRPIPE) {
+                       if (suspend(alsa_id) != 0)
+                               ERROR_EXIT();
+               } else if (ret == -EBUSY) {
+                       MSG(4, "WARNING: sleeping while PCM BUSY");
+                       usleep(100);
+                       continue;
+               } else if (ret < 0) {
+                       ERR("Write to audio interface failed (%s)",
+                           snd_strerror(ret));
+                       ERROR_EXIT();
+               }
+
+               if (ret > 0) {
+                       /* Update counter of bytes left and move the data 
pointer */
+                       num_bytes -=
+                           ret * bytes_per_sample * track.num_channels;
+                       output_samples +=
+                           ret * bytes_per_sample * track.num_channels / 2;
+               }
+
+               /* Report current state */
+               state = snd_pcm_state(alsa_id->alsa_pcm);
+               //      MSG("PCM state before polling: %s",
+               //          snd_pcm_state_name(state));
+
+               err =
+                   wait_for_poll(alsa_id, alsa_id->alsa_poll_fds,
+                                 alsa_id->alsa_fd_count, 0);
+               if (err < 0) {
+                       ERR("Wait for poll() failed\n");
+                       ERROR_EXIT();
+               } else if (err == 1) {
+                       MSG(4, "Playback stopped");
+
+                       /* Drop the playback on the sound device (probably
+                          still in progress up till now) */
+                       err = snd_pcm_drop(alsa_id->alsa_pcm);
+                       if (err < 0) {
+                               ERR("snd_pcm_drop() failed: %s",
+                                   snd_strerror(err));
+                               return -1;
+                       }
+
+                       goto terminate;
+               }
+
+               if (num_bytes <= 0)
+                       break;
+//      MSG("ALSA ready for more samples");
+
+               /* Stop requests can be issued again */
+       }
+
+       MSG(4, "Draining...");
+
+       /* We want to next "device ready" notification only after the buffer is
+          already empty */
+       err =
+           snd_pcm_sw_params_set_avail_min(alsa_id->alsa_pcm,
+                                           alsa_id->alsa_sw_params,
+                                           alsa_id->alsa_buffer_size);
+       if (err < 0) {
+               ERR("Unable to set avail min for playback: %s\n",
+                   snd_strerror(err));
+               return err;
+       }
+       /* write the parameters to the playback device */
+       err = snd_pcm_sw_params(alsa_id->alsa_pcm, alsa_id->alsa_sw_params);
+       if (err < 0) {
+               ERR("Unable to set sw params for playback: %s\n",
+                   snd_strerror(err));
+               return -1;
+       }
+
+       err =
+           wait_for_poll(alsa_id, alsa_id->alsa_poll_fds,
+                         alsa_id->alsa_fd_count, 1);
+       if (err < 0) {
+               ERR("Wait for poll() failed\n");
+               return -1;
+       } else if (err == 1) {
+               MSG(4, "Playback stopped while draining");
+
+               /* Drop the playback on the sound device (probably
+                  still in progress up till now) */
+               err = snd_pcm_drop(alsa_id->alsa_pcm);
+               if (err < 0) {
+                       ERR("snd_pcm_drop() failed: %s", snd_strerror(err));
+                       return -1;
+               }
+       }
+       MSG(4, "Draining terminated");
+
+terminate:
+       /* Terminating (successfully or after a stop) */
+       if (track_volume.samples != NULL)
+               g_free(track_volume.samples);
+
+       err = snd_pcm_drop(alsa_id->alsa_pcm);
+       if (err < 0) {
+               ERR("snd_pcm_drop() failed: %s", snd_strerror(err));
+               return -1;
+       }
+
+       MSG(2, "Freeing HW parameters");
+       snd_pcm_hw_params_free(alsa_id->alsa_hw_params);
+
+       pthread_mutex_lock(&alsa_id->alsa_pipe_mutex);
+       alsa_id->alsa_opened = 0;
+       close(alsa_id->alsa_stop_pipe[0]);
+       close(alsa_id->alsa_stop_pipe[1]);
+
+       g_free(alsa_id->alsa_poll_fds);
+       pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
+
+       MSG(1, "End of playback on ALSA");
+
+       return 0;
+}
+
+#undef ERROR_EXIT
+
+/*
+ Stop the playback on the device and interrupt alsa_play()
+*/
+static int alsa_stop(AudioID * id)
+{
+       char buf;
+       int ret;
+       spd_alsa_id_t *alsa_id = (spd_alsa_id_t *) id;
+
+       MSG(1, "STOP!");
+
+       if (alsa_id == NULL)
+               return 0;
+
+       pthread_mutex_lock(&alsa_id->alsa_pipe_mutex);
+       if (alsa_id->alsa_opened) {
+               /* This constant is arbitrary */
+               buf = 42;
+
+               ret = write(alsa_id->alsa_stop_pipe[1], &buf, 1);
+               if (ret <= 0) {
+                       ERR("Can't write stop request to pipe, err %d: %s",
+                           errno, strerror(errno));
+               }
+       }
+       pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
+
+       return 0;
+}
+
+/* 
+  Set volume
+
+  Comments: It's not possible to set individual track volume with Alsa, so we
+   handle volume in alsa_play() by multiplication of each sample.
+*/
+static int alsa_set_volume(AudioID * id, int volume)
+{
+       return 0;
+}
+
+static void alsa_set_loglevel(int level)
+{
+       if (level) {
+               alsa_log_level = level;
+       }
+}
+
+static char const *alsa_get_playcmd(void)
+{
+       return alsa_play_cmd;
+}
+
+/* Provide the Alsa backend. */
+static spd_audio_plugin_t alsa_functions = {
+       "alsa",
+       alsa_open,
+       alsa_play,
+       alsa_stop,
+       alsa_close,
+       alsa_set_volume,
+       alsa_set_loglevel,
+       alsa_get_playcmd
+};
+
+spd_audio_plugin_t *alsa_plugin_get(void)
+{
+       return &alsa_functions;
+}
+
+spd_audio_plugin_t *SPD_AUDIO_PLUGIN_ENTRY(void)
+    __attribute__ ((weak, alias("alsa_plugin_get")));
+#undef MSG
+#undef ERR
diff --git a/src/audio/libao.c b/src/audio/libao.c
new file mode 100644
index 0000000..e82be2b
--- /dev/null
+++ b/src/audio/libao.c
@@ -0,0 +1,246 @@
+/*
+ * libao.c -- The libao backend for the spd_audio library.
+ *
+ * Author: Marco Skambraks <marco at openblinux.de>
+ * Date:  2009-12-15
+ *
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Leser General Public License as published by the Free
+ * Software Foundation; either version 2.1, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this package; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+#include <glib.h>
+#include <ao/ao.h>
+
+#define SPD_AUDIO_PLUGIN_ENTRY spd_libao_LTX_spd_audio_plugin_get
+#include <spd_audio_plugin.h>
+
+/* send a packet of XXX bytes to the sound device */
+#define AO_SEND_BYTES 256
+/* Put a message into the logfile (stderr) */
+#define MSG(level, arg...) \
+ if(level <= libao_log_level){ \
+     time_t t; \
+     struct timeval tv; \
+     char *tstr; \
+     t = time(NULL); \
+     tstr = g_strdup(ctime(&t)); \
+     tstr[strlen(tstr)-1] = 0; \
+     gettimeofday(&tv,NULL); \
+     fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \
+     fprintf(stderr," libao:: "); \
+     fprintf(stderr,arg); \
+     fprintf(stderr,"\n"); \
+     fflush(stderr); \
+     g_free(tstr); \
+  }
+
+#define ERR(arg...) \
+ { \
+     time_t t; \
+     struct timeval tv; \
+     char *tstr; \
+     t = time(NULL); \
+     tstr = g_strdup(ctime(&t)); \
+     tstr[strlen(tstr)-1] = 0; \
+     gettimeofday(&tv,NULL); \
+     fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \
+     fprintf(stderr," libao ERROR: "); \
+     fprintf(stderr,arg); \
+     fprintf(stderr,"\n"); \
+     fflush(stderr); \
+     g_free(tstr); \
+  }
+
+/* AO_FORMAT_INITIALIZER is an ao_sample_format structure with zero values
+   in all of its fields.  We can guarantee that the fields of a
+   stack-allocated ao_sample_format are zeroed by assigning
+   AO_FORMAT_INITIALIZER to it.
+   This is the most portable way to initialize a stack-allocated struct to
+   zero. */
+static ao_sample_format AO_FORMAT_INITIALIZER;
+static ao_sample_format current_ao_parameters;
+
+static volatile int ao_stop_playback = 0;
+
+static int default_driver;
+static int libao_log_level;
+
+ao_device *device = NULL;
+
+static inline void libao_open_handle(int rate, int channels, int bits)
+{
+       ao_sample_format format = AO_FORMAT_INITIALIZER;
+
+       format.channels = channels;
+       format.rate = rate;
+       format.bits = bits;
+       format.byte_format = AO_FMT_NATIVE;
+       device = ao_open_live(default_driver, &format, NULL);
+
+       if (device != NULL)
+               current_ao_parameters = format;
+}
+
+static inline void libao_close_handle(void)
+{
+       if (device != NULL) {
+               ao_close(device);
+               device = NULL;
+       }
+}
+
+static AudioID *libao_open(void **pars)
+{
+       AudioID *id;
+
+       id = (AudioID *) g_malloc(sizeof(AudioID));
+
+       ao_initialize();
+       default_driver = ao_default_driver_id();
+       return id;
+}
+
+static int libao_play(AudioID * id, AudioTrack track)
+{
+       int bytes_per_sample;
+
+       int num_bytes;
+
+       int outcnt = 0;
+
+       signed short *output_samples;
+
+       int i;
+
+       if (id == NULL)
+               return -1;
+       if (track.samples == NULL || track.num_samples <= 0)
+               return 0;
+
+       /* Choose the correct format */
+       if (track.bits == 16)
+               bytes_per_sample = 2;
+       else if (track.bits == 8)
+               bytes_per_sample = 1;
+       else {
+               ERR("Audio: Unrecognized sound data format.\n");
+               return -10;
+       }
+       MSG(3, "Starting playback");
+       output_samples = track.samples;
+       num_bytes = track.num_samples * bytes_per_sample;
+
+       if ((device == NULL)
+           || (track.num_channels != current_ao_parameters.channels)
+           || (track.sample_rate != current_ao_parameters.rate)
+           || (track.bits != current_ao_parameters.bits)) {
+               libao_close_handle();
+               libao_open_handle(track.sample_rate, track.num_channels,
+                                 track.bits);
+       }
+
+       if (device == NULL) {
+               ERR("error opening libao dev");
+               return -2;
+       }
+       MSG(3, "bytes to play: %d, (%f secs)", num_bytes,
+           (((float)(num_bytes) / 2) / (float)track.sample_rate));
+
+       ao_stop_playback = 0;
+       outcnt = 0;
+       i = 0;
+
+       while ((outcnt < num_bytes) && !ao_stop_playback) {
+               if ((num_bytes - outcnt) > AO_SEND_BYTES)
+                       i = AO_SEND_BYTES;
+               else
+                       i = (num_bytes - outcnt);
+
+               if (!ao_play(device, (char *)output_samples + outcnt, i)) {
+                       libao_close_handle();
+                       ERR("Audio: ao_play() - closing device - re-open it in 
next run\n");
+                       return -1;
+               }
+               outcnt += i;
+       }
+
+       return 0;
+
+}
+
+/* stop the libao_play() loop */
+static int libao_stop(AudioID * id)
+{
+
+       ao_stop_playback = 1;
+       return 0;
+}
+
+static int libao_close(AudioID * id)
+{
+       libao_close_handle();
+       ao_shutdown();
+
+       g_free(id);
+       id = NULL;
+       return 0;
+}
+
+static int libao_set_volume(AudioID * id, int volume)
+{
+       return 0;
+}
+
+static void libao_set_loglevel(int level)
+{
+       if (level) {
+               libao_log_level = level;
+       }
+}
+
+static char const *libao_get_playcmd(void)
+{
+       return NULL;
+}
+
+/* Provide the libao backend. */
+static spd_audio_plugin_t libao_functions = {
+       "libao",
+       libao_open,
+       libao_play,
+       libao_stop,
+       libao_close,
+       libao_set_volume,
+       libao_set_loglevel,
+       libao_get_playcmd
+};
+
+spd_audio_plugin_t *libao_plugin_get(void)
+{
+       return &libao_functions;
+}
+
+spd_audio_plugin_t *SPD_AUDIO_PLUGIN_ENTRY(void)
+    __attribute__ ((weak, alias("libao_plugin_get")));
+#undef MSG
+#undef ERR
diff --git a/src/audio/nas.c b/src/audio/nas.c
new file mode 100644
index 0000000..ca76127
--- /dev/null
+++ b/src/audio/nas.c
@@ -0,0 +1,263 @@
+/*
+ * nas.c -- The Network Audio System backend for the spd_audio library.
+ *
+ * Copyright (C) 2004,2006 Brailcom, o.p.s.
+ *
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this package; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * $Id: nas.c,v 1.8 2006-07-11 16:12:26 hanke Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <audio/audiolib.h>
+#include <audio/soundlib.h>
+
+#include <pthread.h>
+
+#define SPD_AUDIO_PLUGIN_ENTRY spd_nas_LTX_spd_audio_plugin_get
+#include <spd_audio_plugin.h>
+
+typedef struct {
+       AudioID id;
+       AuServer *aud;
+       AuFlowID flow;
+       pthread_mutex_t flow_mutex;
+       pthread_t nas_event_handler;
+       pthread_cond_t pt_cond;
+       pthread_mutex_t pt_mutex;
+} spd_nas_id_t;
+
+static int nas_log_level;
+
+/* Internal event handler */
+static void *_nas_handle_events(void *par)
+{
+       spd_nas_id_t *nas_id = (spd_nas_id_t *) par;
+       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+       while (1)
+               AuHandleEvents(nas_id->aud);
+
+}
+
+/* NAS Server error handler */
+/* Unfortunatelly we can't return these errors to the caller
+   since this handler gets called in the event handler thread. */
+static AuBool _nas_handle_server_error(AuServer * server, AuErrorEvent * event)
+{
+       fprintf(stderr, "ERROR: Non-fatal server error in NAS\n");
+
+       if (event->type != 0) {
+               fprintf(stderr,
+                       "Event of a different type received in NAS error 
handler.");
+               return -1;
+       }
+
+       /* It's a pain but we can't ask for string return code
+          since it's not allowed to talk to the server inside error handlers
+          because of possible deadlocks. */
+       fprintf(stderr, "NAS: Serial number of failed request: %d\n",
+               event->serial);
+       fprintf(stderr, "NAS: Error code: %d\n", event->error_code);
+       fprintf(stderr, "NAS: Resource id: %d\n", event->resourceid);
+       fprintf(stderr, "NAS: Request code: %d\n", event->request_code);
+       fprintf(stderr, "NAS: Minor code: %d\n\n", event->minor_code);
+
+       return 0;
+}
+
+static AudioID *nas_open(void **pars)
+{
+       spd_nas_id_t *nas_id;
+       int ret;
+       AuBool r;
+
+       nas_id = (spd_nas_id_t *) g_malloc(sizeof(spd_nas_id_t));
+
+       nas_id->aud = AuOpenServer(pars[2], 0, NULL, 0, NULL, NULL);
+       if (!nas_id->aud) {
+               fprintf(stderr, "Can't connect to NAS audio server\n");
+               return NULL;
+       }
+
+       AuSetErrorHandler(nas_id->aud, _nas_handle_server_error);
+       /* return value incompatible with documentation here */
+       /*    if (!r){
+          fprintf(stderr, "Can't set default NAS event handler\n");
+          return -1;
+          } */
+
+       nas_id->flow = 0;
+
+       pthread_cond_init(&nas_id->pt_cond, NULL);
+       pthread_mutex_init(&nas_id->pt_mutex, NULL);
+       pthread_mutex_init(&nas_id->flow_mutex, NULL);
+
+       ret =
+           pthread_create(&nas_id->nas_event_handler, NULL, _nas_handle_events,
+                          (void *)nas_id);
+       if (ret != 0) {
+               fprintf(stderr,
+                       "ERROR: NAS Audio module: thread creation failed\n");
+               return NULL;
+       }
+
+       return (AudioID *) nas_id;
+}
+
+static int nas_play(AudioID * id, AudioTrack track)
+{
+       char *buf;
+       Sound s;
+       AuEventHandlerRec *event_handler;
+       int ret;
+       float lenght;
+       struct timeval now;
+       struct timespec timeout;
+       spd_nas_id_t *nas_id = (spd_nas_id_t *) id;
+
+       if (nas_id == NULL)
+               return -2;
+
+       s = SoundCreate(SoundFileFormatNone,
+                       AuFormatLinearSigned16LSB,
+                       track.num_channels,
+                       track.sample_rate, track.num_samples, NULL);
+
+       buf = (char *)track.samples;
+
+       pthread_mutex_lock(&nas_id->flow_mutex);
+
+       event_handler = AuSoundPlayFromData(nas_id->aud,
+                                           s,
+                                           buf,
+                                           AuNone,
+                                           ((nas_id->id.volume +
+                                             100) / 2) * 1500, NULL, NULL,
+                                           &nas_id->flow, NULL, NULL, NULL);
+
+       if (event_handler == NULL) {
+               fprintf(stderr,
+                       "AuSoundPlayFromData failed for unknown resons.\n");
+               return -1;
+       }
+
+       if (nas_id->flow == 0) {
+               fprintf(stderr, "Couldn't start data flow");
+       }
+       pthread_mutex_unlock(&nas_id->flow_mutex);
+
+       /* Another timing magic */
+       pthread_mutex_lock(&nas_id->pt_mutex);
+       lenght = (((float)track.num_samples) / (float)track.sample_rate);
+       gettimeofday(&now, NULL);
+       timeout.tv_sec = now.tv_sec + (int)lenght;
+       timeout.tv_nsec =
+           now.tv_usec * 1000 + (lenght - (int)lenght) * 1000000000;
+       pthread_cond_timedwait(&nas_id->pt_cond, &nas_id->pt_mutex, &timeout);
+       pthread_mutex_unlock(&nas_id->pt_mutex);
+
+       pthread_mutex_lock(&nas_id->flow_mutex);
+       nas_id->flow = 0;
+       pthread_mutex_unlock(&nas_id->flow_mutex);
+
+       return 0;
+}
+
+static int nas_stop(AudioID * id)
+{
+       int ret;
+       spd_nas_id_t *nas_id = (spd_nas_id_t *) id;
+
+       if (nas_id == NULL)
+               return -2;
+
+       pthread_mutex_lock(&nas_id->flow_mutex);
+       if (nas_id->flow != 0)
+               AuStopFlow(nas_id->aud, nas_id->flow, NULL);
+       nas_id->flow = 0;
+       pthread_mutex_unlock(&nas_id->flow_mutex);
+
+       pthread_mutex_lock(&nas_id->pt_mutex);
+       pthread_cond_signal(&nas_id->pt_cond);
+       pthread_mutex_unlock(&nas_id->pt_mutex);
+
+       return 0;
+}
+
+static int nas_close(AudioID * id)
+{
+       spd_nas_id_t *nas_id = (spd_nas_id_t *) id;
+
+       if (nas_id == NULL)
+               return -2;
+
+       pthread_cancel(nas_id->nas_event_handler);
+       pthread_join(nas_id->nas_event_handler, NULL);
+
+       pthread_mutex_destroy(&nas_id->pt_mutex);
+       pthread_mutex_destroy(&nas_id->flow_mutex);
+
+       AuCloseServer(nas_id->aud);
+
+       g_free(nas_id);
+       id = NULL;
+
+       return 0;
+}
+
+static int nas_set_volume(AudioID * id, int volume)
+{
+       return 0;
+}
+
+static void nas_set_loglevel(int level)
+{
+       if (level) {
+               nas_log_level = level;
+       }
+}
+
+static char const *nas_get_playcmd(void)
+{
+       return NULL;
+}
+
+/* Provide the NAS backend */
+static spd_audio_plugin_t nas_functions = {
+       "nas",
+       nas_open,
+       nas_play,
+       nas_stop,
+       nas_close,
+       nas_set_volume,
+       nas_set_loglevel,
+       nas_get_playcmd
+};
+
+spd_audio_plugin_t *nas_plugin_get(void)
+{
+       return &nas_functions;
+}
+
+spd_audio_plugin_t *SPD_AUDIO_PLUGIN_ENTRY(void)
+    __attribute__ ((weak, alias("nas_plugin_get")));
diff --git a/src/audio/oss.c b/src/audio/oss.c
new file mode 100644
index 0000000..b7232c3
--- /dev/null
+++ b/src/audio/oss.c
@@ -0,0 +1,523 @@
+
+/*
+ * oss.c -- The Open Sound System backend for the spd_audio library.
+ *
+ * Copyright (C) 2004,2006 Brailcom, o.p.s.
+ *
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Leser General Public License as published by the Free
+ * Software Foundation; either version 2.1, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this package; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * $Id: oss.c,v 1.13 2006-07-11 16:12:26 hanke Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/soundcard.h>
+#include <errno.h>
+#include <unistd.h>            /* for open, close */
+#include <sys/ioctl.h>
+#include <pthread.h>
+#include <glib.h>
+
+#include <sys/soundcard.h>
+
+#define SPD_AUDIO_PLUGIN_ENTRY spd_oss_LTX_spd_audio_plugin_get
+#include <spd_audio_plugin.h>
+
+typedef struct {
+       AudioID id;
+       int fd;
+       char *device_name;
+       pthread_mutex_t fd_mutex;
+       pthread_cond_t pt_cond;
+       pthread_mutex_t pt_mutex;
+} spd_oss_id_t;
+
+static int _oss_open(spd_oss_id_t * id);
+static int _oss_close(spd_oss_id_t * id);
+static int _oss_sync(spd_oss_id_t * id);
+
+/* Put a message into the logfile (stderr) */
+#define MSG(level, arg...) \
+ if(level <= oss_log_level){ \
+     time_t t; \
+     struct timeval tv; \
+     char *tstr; \
+     t = time(NULL); \
+     tstr = g_strdup(ctime(&t)); \
+     tstr[strlen(tstr)-1] = 0; \
+     gettimeofday(&tv,NULL); \
+     fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \
+     fprintf(stderr," OSS: "); \
+     fprintf(stderr,arg); \
+     fprintf(stderr,"\n"); \
+     fflush(stderr); \
+     g_free(tstr); \
+  }
+
+#define ERR(arg...) \
+ { \
+     time_t t; \
+     struct timeval tv; \
+     char *tstr; \
+     t = time(NULL); \
+     tstr = g_strdup(ctime(&t)); \
+     tstr[strlen(tstr)-1] = 0; \
+     gettimeofday(&tv,NULL); \
+     fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \
+     fprintf(stderr," OSS ERROR: "); \
+     fprintf(stderr,arg); \
+     fprintf(stderr,"\n"); \
+     fflush(stderr); \
+     g_free(tstr); \
+  }
+
+static int oss_log_level;
+static char const *oss_play_cmd = "play";
+
+static int _oss_open(spd_oss_id_t * id)
+{
+       MSG(1, "_oss_open()")
+           pthread_mutex_lock(&id->fd_mutex);
+
+       id->fd = open(id->device_name, O_WRONLY, 0);
+       if (id->fd < 0) {
+               perror(id->device_name);
+               pthread_mutex_unlock(&id->fd_mutex);
+               id = NULL;
+               return -1;
+       }
+
+       pthread_mutex_unlock(&id->fd_mutex);
+
+       return 0;
+}
+
+static int _oss_close(spd_oss_id_t * id)
+{
+       MSG(1, "_oss_close()")
+           if (id == NULL)
+               return 0;
+       if (id->fd < 0)
+               return 0;
+
+       pthread_mutex_lock(&id->fd_mutex);
+       close(id->fd);
+       id->fd = -1;
+       pthread_mutex_unlock(&id->fd_mutex);
+       return 0;
+}
+
+/* Open OSS device
+   Arguments:
+     **pars:
+      (char*) pars[0] -- the name of the device (e.g. "/dev/dsp")
+      (void*) pars[1] = NULL 
+*/
+static AudioID *oss_open(void **pars)
+{
+       spd_oss_id_t *oss_id;
+       int ret;
+
+       if (pars[0] == NULL)
+               return NULL;
+
+       oss_id = (spd_oss_id_t *) g_malloc(sizeof(spd_oss_id_t));
+
+       oss_id->device_name = g_strdup((char *)pars[0]);
+
+       pthread_mutex_init(&oss_id->fd_mutex, NULL);
+
+       pthread_cond_init(&oss_id->pt_cond, NULL);
+       pthread_mutex_init(&oss_id->pt_mutex, NULL);
+
+       /* Test if it's possible to access the device */
+       ret = _oss_open(oss_id);
+       if (ret) {
+               g_free(oss_id->device_name);
+               g_free(oss_id);
+               return NULL;
+       }
+       ret = _oss_close(oss_id);
+       if (ret) {
+               g_free(oss_id->device_name);
+               g_free(oss_id);
+               return NULL;
+       }
+
+       return (AudioID *) oss_id;
+}
+
+/* Internal function. */
+static int _oss_sync(spd_oss_id_t * id)
+{
+       int ret;
+
+       ret = ioctl(id->fd, SNDCTL_DSP_POST, 0);
+       if (ret == -1) {
+               perror("reset");
+               return -1;
+       }
+       return 0;
+}
+
+static int oss_play(AudioID * id, AudioTrack track)
+{
+       int ret, ret2;
+       struct timeval now;
+       struct timespec timeout;
+       float lenght;
+       int r = 0;
+       int format, oformat, channels, speed;
+       int bytes_per_sample;
+       int num_bytes;
+       signed short *output_samples;
+       float delay = 0;
+       float DELAY = 0.1;      /* in seconds */
+       audio_buf_info info;
+       int bytes;
+       float real_volume;
+       int i;
+       int re;
+       spd_oss_id_t *oss_id = (spd_oss_id_t *) id;
+
+       AudioTrack track_volume;
+
+       if (oss_id == NULL)
+               return -1;
+
+       /* Open the sound device. This is necessary for OSS so that the
+          application doesn't prevent others from accessing /dev/dsp when
+          it doesn't play anything. */
+       ret = _oss_open(oss_id);
+       if (ret)
+               return -2;
+
+       /* Create a copy of track with the adjusted volume */
+       track_volume = track;
+       track_volume.samples =
+           (short *)g_malloc(sizeof(short) * track.num_samples);
+       real_volume = ((float)id->volume + 100) / (float)200;
+       for (i = 0; i <= track.num_samples - 1; i++)
+               track_volume.samples[i] = track.samples[i] * real_volume;
+
+       /* Choose the correct format */
+       if (track.bits == 16) {
+               format = AFMT_S16_NE;
+               bytes_per_sample = 2;
+       } else if (track.bits == 8) {
+               bytes_per_sample = 1;
+               format = AFMT_S8;
+       } else {
+               ERR("Audio: Unrecognized sound data format.\n");
+               _oss_close(oss_id);
+               return -10;
+       }
+
+       oformat = format;
+       ret = ioctl(oss_id->fd, SNDCTL_DSP_SETFMT, &format);
+       if (ret == -1) {
+               perror("OSS ERROR: format");
+               _oss_close(oss_id);
+               return -1;
+       }
+       if (format != oformat) {
+               ERR("Device doesn't support 16-bit sound format.\n");
+               _oss_close(oss_id);
+               return -2;
+       }
+
+       /* Choose the correct number of channels */
+       channels = track.num_channels;
+       ret = ioctl(oss_id->fd, SNDCTL_DSP_CHANNELS, &channels);
+       if (ret == -1) {
+               perror("OSS ERROR: channels");
+               _oss_close(oss_id);
+               return -3;
+       }
+       if (channels != track.num_channels) {
+               MSG(1, "Device doesn't support stereo sound.\n");
+               _oss_close(oss_id);
+               return -4;
+       }
+
+       /* Choose the correct sample rate */
+       speed = track.sample_rate;
+       ret = ioctl(oss_id->fd, SNDCTL_DSP_SPEED, &speed);
+       if (ret == -1) {
+               ERR("OSS ERROR: Can't set sample rate %d nor any similar.",
+                   track.sample_rate);
+               _oss_close(oss_id);
+               return -5;
+       }
+       if (speed != track.sample_rate) {
+               ERR("Device doesn't support bitrate %d, using %d instead.\n",
+                   track.sample_rate, speed);
+       }
+
+       /* Is it not an empty track? */
+       if (track.samples == NULL) {
+               _oss_close(oss_id);
+               return 0;
+       }
+
+       /* Loop until all samples are played on the device.
+          In the meantime, wait in pthread_cond_timedwait for more data
+          or for interruption. */
+       MSG(4, "Starting playback");
+       output_samples = track_volume.samples;
+       num_bytes = track.num_samples * bytes_per_sample;
+       MSG(4, "bytes to play: %d, (%f secs)", num_bytes,
+           (((float)(num_bytes) / 2) / (float)track.sample_rate));
+       while (num_bytes > 0) {
+
+               /* OSS doesn't support non-blocking write, so lets check how 
much data
+                  can we write so that write() returns immediatelly */
+               re = ioctl(oss_id->fd, SNDCTL_DSP_GETOSPACE, &info);
+               if (re == -1) {
+                       perror("OSS ERROR: GETOSPACE");
+                       _oss_close(oss_id);
+                       return -5;
+               }
+
+               /* If there is not enough space for a single fragment, try 
later.
+                  (This shouldn't happen, it has very bad effect on 
synchronization!) */
+               if (info.fragments == 0) {
+                       MSG(4,
+                           "WARNING: There is not enough space for a single 
fragment, looping");
+                       usleep(100);
+                       continue;
+               }
+
+               MSG(4,
+                   "There is space for %d more fragments, fragment size is %d 
bytes",
+                   info.fragments, info.fragsize);
+
+               bytes = info.fragments * info.fragsize;
+               ret =
+                   write(oss_id->fd, output_samples,
+                         num_bytes > bytes ? bytes : num_bytes);
+
+               /* Handle write() errors */
+               if (ret <= 0) {
+                       perror("audio");
+                       _oss_close(oss_id);
+                       return -6;
+               }
+
+               num_bytes -= ret;
+               output_samples += ret / 2;
+
+               MSG(4, "%d bytes written to OSS, %d remaining", ret, num_bytes);
+
+               /* If there is some more data that is less than a
+                  full fragment, we need to write it immediatelly so
+                  that it doesn't cause buffer underruns later. */
+               if ((num_bytes > 0)
+                   && (num_bytes < info.fragsize)
+                   && (bytes + num_bytes < info.bytes)) {
+
+                       MSG(4,
+                           "Writing the rest of the data (%d bytes) to OSS, 
not a full fragment",
+                           num_bytes);
+
+                       ret2 = write(oss_id->fd, output_samples, num_bytes);
+                       num_bytes -= ret2;
+                       output_samples += ret2 / 2;
+                       ret += ret2;
+               }
+
+               /* Handle write() errors */
+               if (ret <= 0) {
+                       perror("audio");
+                       _oss_close(oss_id);
+                       return -6;
+               }
+
+               /* Some timing magic... 
+                  We need to wait for the time computed from the number of
+                  samples written. But this wait needs to be interruptible
+                  by oss_stop(). Furthermore, there need to be no buffer
+                  underrruns, so we actually wait a bit (DELAY) less
+                  in the first pass through the while() loop. Then our timer
+                  will be DELAY nsecs backwards.
+                */
+               MSG(4, "Now we will try to wait");
+               pthread_mutex_lock(&oss_id->pt_mutex);
+               lenght = (((float)(ret) / 2) / (float)track.sample_rate);
+               if (!delay) {
+                       delay = lenght > DELAY ? DELAY : lenght;
+                       lenght -= delay;
+               }
+               MSG(4, "Wait for %f secs (begin: %f, delay: %f)", lenght,
+                   lenght + delay, delay)
+                   gettimeofday(&now, NULL);
+               timeout.tv_sec = now.tv_sec + (int)lenght;
+               timeout.tv_nsec =
+                   now.tv_usec * 1000 + (lenght - (int)lenght) * 1000000000;
+               //MSG("5, waiting till %d:%d (%d:%d | %d:%d)", timeout.tv_sec, 
timeout.tv_nsec,
+               //    now.tv_sec, now.tv_usec*1000, timeout.tv_sec - 
now.tv_sec, timeout.tv_nsec-now.tv_usec*1000);
+
+               timeout.tv_sec += timeout.tv_nsec / 1000000000;
+               timeout.tv_nsec = timeout.tv_nsec % 1000000000;
+               //      MSG("6, waiting till %d:%d (%d:%d | %d:%d)", 
timeout.tv_sec, timeout.tv_nsec,
+               //  now.tv_sec, now.tv_usec*1000, timeout.tv_sec - now.tv_sec, 
timeout.tv_nsec-now.tv_usec*1000);
+               r = pthread_cond_timedwait(&oss_id->pt_cond, &oss_id->pt_mutex,
+                                          &timeout);
+               pthread_mutex_unlock(&oss_id->pt_mutex);
+               MSG(4, "End of wait");
+
+               /* The pthread_cond_timedwait was interrupted by change in the
+                  condition variable? if so, terminate. */
+               if (r != ETIMEDOUT) {
+                       MSG(4, "Playback stopped, %d", r);
+                       break;
+               }
+       }
+
+       /* ...one more excersise in timing magic. 
+          Wait for the resting delay secs. */
+
+       /* Ugly hack: correct for the time we spend outside timing segments */
+       delay -= 0.05;
+
+       MSG(4, "Wait for the resting delay = %f secs", delay)
+           if ((delay > 0) && (r == ETIMEDOUT)) {
+               pthread_mutex_lock(&oss_id->pt_mutex);
+               gettimeofday(&now, NULL);
+               timeout.tv_sec = now.tv_sec;
+               timeout.tv_nsec = now.tv_usec * 1000 + delay * 1000000000;
+               // MSG("6, waiting till %d:%d (%d:%d | %d:%d)", timeout.tv_sec, 
timeout.tv_nsec,
+               //          now.tv_sec, now.tv_usec*1000, timeout.tv_sec - 
now.tv_sec, timeout.tv_nsec-now.tv_usec*1000);
+               timeout.tv_sec += timeout.tv_nsec / 1000000000;
+               timeout.tv_nsec = timeout.tv_nsec % 1000000000;
+               // MSG("6, waiting till %d:%d (%d:%d | %d:%d)", timeout.tv_sec, 
timeout.tv_nsec,
+               //          now.tv_sec, now.tv_usec*1000, timeout.tv_sec - 
now.tv_sec, timeout.tv_nsec-now.tv_usec*1000);
+               r = pthread_cond_timedwait(&oss_id->pt_cond, &oss_id->pt_mutex,
+                                          &timeout);
+               pthread_mutex_unlock(&oss_id->pt_mutex);
+       }
+       MSG(4, "End of wait");
+
+       if (track_volume.samples != NULL)
+               g_free(track_volume.samples);
+
+       /* Flush all the buffers */
+       _oss_sync(oss_id);
+
+       /* Close the device so that we don't block other apps trying to
+          access the device. */
+       _oss_close(oss_id);
+
+       MSG(4, "Device closed");
+
+       return 0;
+}
+
+/* Stop the playback on the device and interrupt oss_play */
+static int oss_stop(AudioID * id)
+{
+       int ret = 0;
+       spd_oss_id_t *oss_id = (spd_oss_id_t *) id;
+
+       if (oss_id == NULL)
+               return 0;
+
+       MSG(4, "stop() called");
+
+       /* Stop the playback on /dev/dsp */
+       pthread_mutex_lock(&oss_id->fd_mutex);
+       if (oss_id->fd >= 0)
+               ret = ioctl(oss_id->fd, SNDCTL_DSP_RESET, 0);
+       pthread_mutex_unlock(&oss_id->fd_mutex);
+       if (ret == -1) {
+               perror("reset");
+               return -1;
+       }
+
+       /* Interrupt oss_play by setting the condition variable */
+       pthread_mutex_lock(&oss_id->pt_mutex);
+       pthread_cond_signal(&oss_id->pt_cond);
+       pthread_mutex_unlock(&oss_id->pt_mutex);
+       return 0;
+}
+
+/* Close the device */
+static int oss_close(AudioID * id)
+{
+       spd_oss_id_t *oss_id = (spd_oss_id_t *) id;
+
+       /* Does nothing because the device is being automatically openned and
+          closed in oss_play before and after playing each sample. */
+
+       g_free(oss_id->device_name);
+       g_free(oss_id);
+       id = NULL;
+
+       return 0;
+}
+
+/* Set volume
+
+Comments:
+  /dev/dsp can't set volume. We just multiply the track samples by
+  a constant in oss_play (see oss_play() for more information).
+*/
+static int oss_set_volume(AudioID * id, int volume)
+{
+       return 0;
+}
+
+static void oss_set_loglevel(int level)
+{
+       if (level) {
+               oss_log_level = level;
+       }
+}
+
+static char const *oss_get_playcmd(void)
+{
+       return oss_play_cmd;
+}
+
+/* Provide the OSS backend. */
+static spd_audio_plugin_t oss_functions = {
+       "oss",
+       oss_open,
+       oss_play,
+       oss_stop,
+       oss_close,
+       oss_set_volume,
+       oss_set_loglevel,
+       oss_get_playcmd
+};
+
+spd_audio_plugin_t *oss_plugin_get(void)
+{
+       return &oss_functions;
+}
+
+spd_audio_plugin_t *SPD_AUDIO_PLUGIN_ENTRY(void)
+    __attribute__ ((weak, alias("oss_plugin_get")));
+#undef MSG
+#undef ERR
diff --git a/src/audio/pulse.c b/src/audio/pulse.c
new file mode 100644
index 0000000..a4137e5
--- /dev/null
+++ b/src/audio/pulse.c
@@ -0,0 +1,310 @@
+
+/*
+ * pulse.c -- The simple pulseaudio backend for the spd_audio library.
+ *
+ * Based on libao.c from Marco Skambraks <marco at openblinux.de>
+ * Date:  2009-12-15
+ *
+ * Copied from Luke Yelavich's libao.c driver, and merged with code from
+ * Marco's ao_pulse.c driver, by Bill Cox, Dec 21, 2009.
+ *
+ * Minor changes be Rui Batista <rui.batista at ist.utl.pt> to configure 
settings through speech-dispatcher configuration files
+ * Date: Dec 22, 2009
+ *
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Leser General Public License as published by the Free
+ * Software Foundation; either version 2.1, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this package; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+#include <stdarg.h>
+#include <glib.h>
+
+#include <pulse/simple.h>
+#include <pulse/error.h>
+
+#define SPD_AUDIO_PLUGIN_ENTRY spd_pulse_LTX_spd_audio_plugin_get
+#include <spd_audio_plugin.h>
+
+/* Switch this on to debug, see output log location in MSG() */
+//#define DEBUG_PULSE
+typedef struct {
+       AudioID id;
+       pa_simple *pa_simple;
+       char *pa_server;
+       int pa_min_audio_length;
+       volatile int pa_stop_playback;
+       int pa_current_rate;    // Sample rate for currently PA connection
+       int pa_current_bps;     // Bits per sample rate for currently PA 
connection
+       int pa_current_channels;        // Number of channels for currently PA 
connection
+} spd_pulse_id_t;
+
+/* send a packet of XXX bytes to the sound device */
+#define PULSE_SEND_BYTES 256
+
+/* This is the smallest audio sound we are expected to play immediately 
without buffering. */
+/* Changed to define on config file. Default is the same. */
+#define DEFAULT_PA_MIN_AUDIO_LENgTH 100
+
+static int pulse_log_level;
+static char const *pulse_play_cmd = "paplay";
+
+/* Write to /tmp/speech-dispatcher-pulse.log */
+#ifdef DEBUG_PULSE
+static FILE *pulseDebugFile = NULL;
+static void MSG(char *message, ...)
+{
+       va_list ap;
+
+       if (pulseDebugFile == NULL) {
+               pulseDebugFile = fopen("/tmp/speech-dispatcher-pulse.log", "w");
+       }
+       va_start(ap, message);
+       vfprintf(pulseDebugFile, message, ap);
+       va_end(ap);
+       fflush(pulseDebugFile);
+}
+#else
+static void MSG(char *message, ...)
+{
+}
+#endif
+
+static int _pulse_open(spd_pulse_id_t * id, int sample_rate,
+                      int num_channels, int bytes_per_sample)
+{
+       pa_buffer_attr buffAttr;
+       pa_sample_spec ss;
+       int error;
+
+       ss.rate = sample_rate;
+       ss.channels = num_channels;
+       if (bytes_per_sample == 2) {
+               switch (id->id.format) {
+               case SPD_AUDIO_LE:
+                       ss.format = PA_SAMPLE_S16LE;
+                       break;
+               case SPD_AUDIO_BE:
+                       ss.format = PA_SAMPLE_S16BE;
+                       break;
+               }
+       } else {
+               ss.format = PA_SAMPLE_U8;
+       }
+
+       /* Set prebuf to one sample so that keys are spoken as soon as typed 
rather than delayed until the next key pressed */
+       buffAttr.maxlength = (uint32_t) - 1;
+       //buffAttr.tlength = (uint32_t)-1; - this is the default, which causes 
key echo to not work properly.
+       buffAttr.tlength = id->pa_min_audio_length;
+       buffAttr.prebuf = (uint32_t) - 1;
+       buffAttr.minreq = (uint32_t) - 1;
+       buffAttr.fragsize = (uint32_t) - 1;
+       /* Open new connection */
+       if (!
+           (id->pa_simple =
+            pa_simple_new(id->pa_server, "speech-dispatcher",
+                          PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL,
+                          &buffAttr, &error))) {
+               fprintf(stderr, __FILE__ ": pa_simple_new() failed: %s\n",
+                       pa_strerror(error));
+               return 1;
+       }
+       return 0;
+}
+
+/* Close the connection to the server.  Does not free the AudioID struct. */
+/* Usable in pulse_play, which closes connections on failure or */
+/* changes in audio parameters. */
+static void pulse_connection_close(spd_pulse_id_t * pulse_id)
+{
+       if (pulse_id->pa_simple != NULL) {
+               pa_simple_free(pulse_id->pa_simple);
+               pulse_id->pa_simple = NULL;
+       }
+}
+
+static AudioID *pulse_open(void **pars)
+{
+       spd_pulse_id_t *pulse_id;
+       int ret;
+
+       pulse_id = (spd_pulse_id_t *) g_malloc(sizeof(spd_pulse_id_t));
+
+       /* Select an Endianness for the initial connection. */
+#if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
+       pulse_id->id.format = SPD_AUDIO_BE;
+#else
+       pulse_id->id.format = SPD_AUDIO_LE;
+#endif
+       pulse_id->pa_simple = NULL;
+       pulse_id->pa_server = (char *)pars[3];
+       pulse_id->pa_min_audio_length = DEFAULT_PA_MIN_AUDIO_LENgTH;
+
+       pulse_id->pa_current_rate = -1;
+       pulse_id->pa_current_bps = -1;
+       pulse_id->pa_current_channels = -1;
+
+       if (!strcmp(pulse_id->pa_server, "default")) {
+               pulse_id->pa_server = NULL;
+       }
+
+       if (pars[4] != NULL && atoi(pars[4]) != 0)
+               pulse_id->pa_min_audio_length = atoi(pars[4]);
+
+       pulse_id->pa_stop_playback = 0;
+
+       ret = _pulse_open(pulse_id, 44100, 1, 2);
+       if (ret) {
+               g_free(pulse_id);
+               pulse_id = NULL;
+       }
+
+       return (AudioID *) pulse_id;
+}
+
+static int pulse_play(AudioID * id, AudioTrack track)
+{
+       int bytes_per_sample;
+       int num_bytes;
+       int outcnt = 0;
+       signed short *output_samples;
+       int i;
+       int error;
+       spd_pulse_id_t *pulse_id = (spd_pulse_id_t *) id;
+
+       if (id == NULL) {
+               return -1;
+       }
+       if (track.samples == NULL || track.num_samples <= 0) {
+               return 0;
+       }
+       MSG("Starting playback\n");
+       /* Choose the correct format */
+       if (track.bits == 16) {
+               bytes_per_sample = 2;
+       } else if (track.bits == 8) {
+               bytes_per_sample = 1;
+       } else {
+               MSG("ERROR: Unsupported sound data format, track.bits = %d\n",
+                   track.bits);
+               return -1;
+       }
+       output_samples = track.samples;
+       num_bytes = track.num_samples * bytes_per_sample;
+
+       /* Check if the current connection has suitable parameters for this 
track */
+       if (pulse_id->pa_current_rate != track.sample_rate
+           || pulse_id->pa_current_bps != track.bits
+           || pulse_id->pa_current_channels != track.num_channels) {
+               MSG("Reopenning connection due to change in track parameters 
sample_rate:%d bps:%d channels:%d\n", track.sample_rate, track.bits, 
track.num_channels);
+               /* Close old connection if any */
+               pulse_connection_close(pulse_id);
+               /* Open a new connection */
+               _pulse_open(pulse_id, track.sample_rate, track.num_channels,
+                           bytes_per_sample);
+               /* Keep track of current connection parameters */
+               pulse_id->pa_current_rate = track.sample_rate;
+               pulse_id->pa_current_bps = track.bits;
+               pulse_id->pa_current_channels = track.num_channels;
+       }
+       MSG("bytes to play: %d, (%f secs)\n", num_bytes,
+           (((float)(num_bytes) / 2) / (float)track.sample_rate));
+       pulse_id->pa_stop_playback = 0;
+       outcnt = 0;
+       i = 0;
+       while ((outcnt < num_bytes) && !pulse_id->pa_stop_playback) {
+               if ((num_bytes - outcnt) > PULSE_SEND_BYTES) {
+                       i = PULSE_SEND_BYTES;
+               } else {
+                       i = (num_bytes - outcnt);
+               }
+               if (pa_simple_write
+                   (pulse_id->pa_simple, ((char *)output_samples) + outcnt, i,
+                    &error) < 0) {
+                       pa_simple_drain(pulse_id->pa_simple, NULL);
+                       pulse_connection_close(pulse_id);
+                       MSG("ERROR: Audio: pulse_play(): %s - closing device - 
re-open it in next run\n", pa_strerror(error));
+                       break;
+               } else {
+                       MSG("Pulse: wrote %u bytes\n", i);
+               }
+               outcnt += i;
+       }
+       return 0;
+}
+
+/* stop the pulse_play() loop */
+static int pulse_stop(AudioID * id)
+{
+       spd_pulse_id_t *pulse_id = (spd_pulse_id_t *) id;
+
+       pulse_id->pa_stop_playback = 1;
+       return 0;
+}
+
+static int pulse_close(AudioID * id)
+{
+       spd_pulse_id_t *pulse_id = (spd_pulse_id_t *) id;
+       pulse_connection_close(pulse_id);
+       g_free(pulse_id);
+       id = NULL;
+
+       return 0;
+}
+
+static int pulse_set_volume(AudioID * id, int volume)
+{
+       return 0;
+}
+
+static void pulse_set_loglevel(int level)
+{
+       if (level) {
+               pulse_log_level = level;
+       }
+}
+
+static char const *pulse_get_playcmd(void)
+{
+       return pulse_play_cmd;
+}
+
+/* Provide the pulse backend. */
+static spd_audio_plugin_t pulse_functions = {
+       "pulse",
+       pulse_open,
+       pulse_play,
+       pulse_stop,
+       pulse_close,
+       pulse_set_volume,
+       pulse_set_loglevel,
+       pulse_get_playcmd
+};
+
+spd_audio_plugin_t *pulse_plugin_get(void)
+{
+       return &pulse_functions;
+}
+
+spd_audio_plugin_t *SPD_AUDIO_PLUGIN_ENTRY(void)
+    __attribute__ ((weak, alias("pulse_plugin_get")));
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
index f74b0a4..3588e53 100644
--- a/src/modules/Makefile.am
+++ b/src/modules/Makefile.am
@@ -1,7 +1,5 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS = audio
-
 inc_local = -I$(top_srcdir)/include
 audio_SOURCES = spd_audio.c spd_audio.h
 common_SOURCES = module_main.c module_utils.c module_utils.h
diff --git a/src/modules/audio/.gitignore b/src/modules/audio/.gitignore
deleted file mode 100644
index f75f98e..0000000
--- a/src/modules/audio/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-static_plugins.c
diff --git a/src/modules/audio/Makefile.am b/src/modules/audio/Makefile.am
deleted file mode 100644
index d84fcdb..0000000
--- a/src/modules/audio/Makefile.am
+++ /dev/null
@@ -1,45 +0,0 @@
-## Process this file with automake to produce Makefile.in
-
-inc_local = -I$(top_srcdir)/include/
-
-audio_LTLIBRARIES =
-
-if alsa_support
-audio_LTLIBRARIES +=  spd_alsa.la
-spd_alsa_la_SOURCES = alsa.c
-spd_alsa_la_CPPFLAGS = $(GLIB_CFLAGS) $(inc_local)  $(ALSA_CFLAGS)
-spd_alsa_la_LIBADD = $(ALSA_LIBS) $(GLIB_LIBS)
-spd_alsa_la_LDFLAGS = -module -avoid-version
-endif
-
-if libao_support
-audio_LTLIBRARIES +=  spd_libao.la
-spd_libao_la_SOURCES = libao.c
-spd_libao_la_CPPFLAGS = $(GLIB_CFLAGS) $(inc_local)  $(LIBAO_CFLAGS)
-spd_libao_la_LIBADD = $(LIBAO_LIBS) $(GLIB_LIBS)
-spd_libao_la_LDFLAGS = -module -avoid-version
-endif
-
-if nas_support
-audio_LTLIBRARIES +=  spd_nas.la
-spd_nas_la_SOURCES = nas.c
-spd_nas_la_CPPFLAGS = $(GLIB_CFLAGS) $(inc_local)
-spd_nas_la_LIBADD = $(NAS_LIBS) $(GLIB_LIBS)
-spd_nas_la_LDFLAGS = -module -avoid-version
-endif
-
-if oss_support
-audio_LTLIBRARIES +=  spd_oss.la
-spd_oss_la_SOURCES = oss.c
-spd_oss_la_CPPFLAGS = $(GLIB_CFLAGS) $(inc_local)
-spd_oss_la_LIBADD = $(GLIB_LIBS)
-spd_oss_la_LDFLAGS = -module -avoid-version
-endif
-
-if pulse_support
-audio_LTLIBRARIES +=  spd_pulse.la
-spd_pulse_la_SOURCES = pulse.c
-spd_pulse_la_CPPFLAGS = $(GLIB_CFLAGS) $(inc_local)  $(PULSE_CFLAGS)
-spd_pulse_la_LIBADD = $(PULSE_LIBS) $(GLIB_LIBS)
-spd_pulse_la_LDFLAGS = -module -avoid-version
-endif
diff --git a/src/modules/audio/alsa.c b/src/modules/audio/alsa.c
deleted file mode 100644
index 4e20a54..0000000
--- a/src/modules/audio/alsa.c
+++ /dev/null
@@ -1,883 +0,0 @@
-
-/*
- * alsa.c -- The Advanced Linux Sound System backend for Speech Dispatcher
- *
- * Copyright (C) 2005,2006 Brailcom, o.p.s.
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1, or (at your option) any later
- * version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this package; see the file COPYING.  If not, write to the Free
- * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- * $Id: alsa.c,v 1.30 2008-10-15 17:27:32 hanke Exp $
- */
-
-/* NOTE: This module uses the non-blocking write() / poll() approach to
-    alsa-lib functions.*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <sys/time.h>
-#include <time.h>
-#include <pthread.h>
-#include <glib.h>
-
-#include <alsa/asoundlib.h>
-
-#define SPD_AUDIO_PLUGIN_ENTRY spd_alsa_LTX_spd_audio_plugin_get
-#include <spd_audio_plugin.h>
-
-typedef struct {
-       AudioID id;
-       snd_pcm_t *alsa_pcm;    /* identifier of the ALSA device */
-       snd_pcm_hw_params_t *alsa_hw_params;    /* parameters of sound */
-       snd_pcm_sw_params_t *alsa_sw_params;    /* parameters of playback */
-       snd_pcm_uframes_t alsa_buffer_size;
-       pthread_mutex_t alsa_pcm_mutex; /* mutex to guard the state of the 
device */
-       pthread_mutex_t alsa_pipe_mutex;        /* mutex to guard the stop 
pipes */
-       int alsa_stop_pipe[2];  /* Pipe for communication about stop requests */
-       int alsa_fd_count;      /* Counter of descriptors to poll */
-       struct pollfd *alsa_poll_fds;   /* Descriptors to poll */
-       int alsa_opened;        /* 1 between snd_pcm_open and _close, 0 
otherwise */
-       char *alsa_device_name; /* the name of the device to open */
-} spd_alsa_id_t;
-
-static int _alsa_close(spd_alsa_id_t * id);
-static int _alsa_open(spd_alsa_id_t * id);
-
-static int xrun(spd_alsa_id_t * id);
-static int suspend(spd_alsa_id_t * id);
-
-static int wait_for_poll(spd_alsa_id_t * id, struct pollfd *alsa_poll_fds,
-                        unsigned int count, int draining);
-
-#ifndef timersub
-#define        timersub(a, b, result) \
-do { \
-         (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
-        (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
-        if ((result)->tv_usec < 0) { \
-                --(result)->tv_sec; \
-                (result)->tv_usec += 1000000; \
-        } \
- } while (0)
-#endif
-
-/* Put a message into the logfile (stderr) */
-#define MSG(level, arg...) \
- if(level <= alsa_log_level){ \
-     time_t t; \
-     struct timeval tv; \
-     char *tstr; \
-     t = time(NULL); \
-     tstr = g_strdup(ctime(&t)); \
-     tstr[strlen(tstr)-1] = 0; \
-     gettimeofday(&tv,NULL); \
-     fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \
-     fprintf(stderr," ALSA: "); \
-     fprintf(stderr,arg); \
-     fprintf(stderr,"\n"); \
-     fflush(stderr); \
-     g_free(tstr); \
-  }
-
-#define ERR(arg...) \
- { \
-     time_t t; \
-     struct timeval tv; \
-     char *tstr; \
-     t = time(NULL); \
-     tstr = g_strdup(ctime(&t)); \
-     tstr[strlen(tstr)-1] = 0; \
-     gettimeofday(&tv,NULL); \
-     fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \
-     fprintf(stderr," ALSA ERROR: "); \
-     fprintf(stderr,arg); \
-     fprintf(stderr,"\n"); \
-     fflush(stderr); \
-     g_free(tstr); \
-  }
-
-static int alsa_log_level;
-static char const *alsa_play_cmd = "aplay";
-
-/* I/O error handler */
-static int xrun(spd_alsa_id_t * id)
-{
-       snd_pcm_status_t *status;
-       int res;
-
-       if (id == NULL)
-               return -1;
-
-       MSG(1, "WARNING: Entering XRUN handler");
-
-       snd_pcm_status_alloca(&status);
-       if ((res = snd_pcm_status(id->alsa_pcm, status)) < 0) {
-               ERR("status error: %s", snd_strerror(res));
-
-               return -1;
-       }
-       if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
-               struct timeval now, diff, tstamp;
-               gettimeofday(&now, 0);
-               snd_pcm_status_get_trigger_tstamp(status, &tstamp);
-               timersub(&now, &tstamp, &diff);
-               MSG(1, "underrun!!! (at least %.3f ms long)",
-                   diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
-               if ((res = snd_pcm_prepare(id->alsa_pcm)) < 0) {
-                       ERR("xrun: prepare error: %s", snd_strerror(res));
-
-                       return -1;
-               }
-
-               return 0;       /* ok, data should be accepted again */
-       }
-       ERR("read/write error, state = %s",
-           snd_pcm_state_name(snd_pcm_status_get_state(status)));
-
-       return -1;
-}
-
-/* I/O suspend handler */
-static int suspend(spd_alsa_id_t * id)
-{
-       int res;
-
-       MSG(1, "WARNING: Entering SUSPEND handler.");
-
-       if (id == NULL)
-               return -1;
-
-       while ((res = snd_pcm_resume(id->alsa_pcm)) == -EAGAIN)
-               sleep(1);       /* wait until suspend flag is released */
-
-       if (res < 0) {
-               if ((res = snd_pcm_prepare(id->alsa_pcm)) < 0) {
-                       ERR("suspend: prepare error: %s", snd_strerror(res));
-
-                       return -1;
-               }
-       }
-
-       return 0;
-}
-
-/* Open the device so that it's ready for playing on the default
-   device. Internal function used by the public alsa_open. */
-static int _alsa_open(spd_alsa_id_t * id)
-{
-       int err;
-
-       MSG(1, "Opening ALSA device");
-       fflush(stderr);
-
-       /* Open the device */
-       if ((err = snd_pcm_open(&id->alsa_pcm, id->alsa_device_name,
-                               SND_PCM_STREAM_PLAYBACK,
-                               SND_PCM_NONBLOCK)) < 0) {
-               ERR("Cannot open audio device %s (%s)", id->alsa_device_name,
-                   snd_strerror(err));
-               return -1;
-       }
-
-       /* Allocate space for hw_params (description of the sound parameters) */
-       /* Allocate space for sw_params (description of the sound parameters) */
-       MSG(2, "Allocating new sw_params structure");
-       if ((err = snd_pcm_sw_params_malloc(&id->alsa_sw_params)) < 0) {
-               ERR("Cannot allocate hardware parameter structure (%s)",
-                   snd_strerror(err));
-               return -1;
-       }
-
-       MSG(1, "Opening ALSA device ... success");
-
-       return 0;
-}
-
-/* 
-   Close the device. Internal function used by public alsa_close. 
-*/
-
-static int _alsa_close(spd_alsa_id_t * id)
-{
-       int err;
-
-       MSG(1, "Closing ALSA device");
-
-       if (id->alsa_opened == 0)
-               return 0;
-
-       pthread_mutex_lock(&id->alsa_pipe_mutex);
-       id->alsa_opened = 0;
-
-       if ((err = snd_pcm_close(id->alsa_pcm)) < 0) {
-               MSG(2, "Cannot close ALSA device (%s)", snd_strerror(err));
-               return -1;
-       }
-
-       snd_pcm_sw_params_free(id->alsa_sw_params);
-
-       g_free(id->alsa_poll_fds);
-       pthread_mutex_unlock(&id->alsa_pipe_mutex);
-
-       MSG(1, "Closing ALSA device ... success");
-
-       return 0;
-}
-
-/* Open ALSA for playback.
-  
-  These parameters are passed in pars:
-  (char*) pars[0] ... null-terminated string containing the name
-                      of the device to be used for sound output
-                      on ALSA
-  (void*) pars[1] ... =NULL
-*/
-static AudioID *alsa_open(void **pars)
-{
-       spd_alsa_id_t *alsa_id;
-       int ret;
-
-       if (pars[1] == NULL) {
-               ERR("Can't open ALSA sound output, missing parameters in 
argument.");
-               return NULL;
-       }
-
-       alsa_id = (spd_alsa_id_t *) g_malloc(sizeof(spd_alsa_id_t));
-
-       pthread_mutex_init(&alsa_id->alsa_pipe_mutex, NULL);
-
-       alsa_id->alsa_opened = 0;
-
-       MSG(1, "Opening ALSA sound output");
-
-       alsa_id->alsa_device_name = g_strdup(pars[1]);
-
-       ret = _alsa_open(alsa_id);
-       if (ret) {
-               ERR("Cannot initialize Alsa device '%s': Can't open.",
-                   alsa_id->alsa_device_name);
-               g_free(alsa_id);
-               return NULL;
-       }
-
-       MSG(1, "Device '%s' initialized succesfully.",
-           alsa_id->alsa_device_name);
-
-       return (AudioID *) alsa_id;
-}
-
-/* Close ALSA */
-static int alsa_close(AudioID * id)
-{
-       int err;
-       spd_alsa_id_t *alsa_id = (spd_alsa_id_t *) id;
-
-       /* Close device */
-       if ((err = _alsa_close(alsa_id)) < 0) {
-               ERR("Cannot close audio device");
-               return -1;
-       }
-       MSG(1, "ALSA closed.");
-
-       g_free(alsa_id->alsa_device_name);
-       g_free(alsa_id);
-       id = NULL;
-
-       return 0;
-}
-
-/* Wait until ALSA is readdy for more samples or alsa_stop() was called.
-
-Returns 0 if ALSA is ready for more input, +1 if a request to stop
-the sound output was received and a negative value on error.  */
-
-int wait_for_poll(spd_alsa_id_t * id, struct pollfd *alsa_poll_fds,
-                 unsigned int count, int draining)
-{
-       unsigned short revents;
-       snd_pcm_state_t state;
-       int ret;
-
-       //      MSG("Waiting for poll");
-
-       /* Wait for certain events */
-       while (1) {
-               ret = poll(id->alsa_poll_fds, count, -1);
-               //      MSG("wait_for_poll: activity on %d descriptors", ret);
-
-               /* Check for stop request from alsa_stop on the last file
-                  descriptors */
-               revents = id->alsa_poll_fds[count - 1].revents;
-               if (0 != revents) {
-                       if (revents & POLLIN) {
-                               MSG(4, "wait_for_poll: stop requested");
-                               return 1;
-                       }
-               }
-
-               /* Check the first count-1 descriptors for ALSA events */
-               snd_pcm_poll_descriptors_revents(id->alsa_pcm,
-                                                id->alsa_poll_fds, count - 1,
-                                                &revents);
-
-               /* Ensure we are in the right state */
-               state = snd_pcm_state(id->alsa_pcm);
-               //      MSG("State after poll returned is %s", 
snd_pcm_state_name(state));
-
-               if (SND_PCM_STATE_XRUN == state) {
-                       if (!draining) {
-                               MSG(1, "WARNING: Buffer underrun detected!");
-                               if (xrun(id) != 0)
-                                       return -1;
-                               return 0;
-                       } else {
-                               MSG(4, "Poll: Playback terminated");
-                               return 0;
-                       }
-               }
-
-               if (SND_PCM_STATE_SUSPENDED == state) {
-                       MSG(1, "WARNING: Suspend detected!");
-                       if (suspend(id) != 0)
-                               return -1;
-                       return 0;
-               }
-
-               /* Check for errors */
-               if (revents & POLLERR) {
-                       MSG(4, "wait_for_poll: poll revents says POLLERR");
-                       return -EIO;
-               }
-
-               /* Is ALSA ready for more input? */
-               if ((revents & POLLOUT)) {
-                       // MSG("Poll: Ready for more input");
-                       return 0;
-               }
-       }
-}
-
-#define ERROR_EXIT()\
-    g_free(track_volume.samples); \
-    ERR("alsa_play() abnormal exit"); \
-    _alsa_close(alsa_id); \
-    return -1;
-
-/* Play the track _track_ (see spd_audio.h) using the id->alsa_pcm device and
- id-hw_params parameters. This is a blocking function, however, it's possible
- to interrupt playing from a different thread with alsa_stop(). alsa_play
- returns after and immediatelly after the whole sound was played on the
- speakers.
-
- The idea is that we get the ALSA file descriptors and we will poll() to see
- when alsa is ready for more input while sleeping in the meantime. We will
- additionally poll() for one more descriptor used by alsa_stop() to notify the
- thread with alsa_play() that the stop of the playback is requested. The
- variable can_be_stopped is used for very simple synchronization between the
- two threads. */
-static int alsa_play(AudioID * id, AudioTrack track)
-{
-       snd_pcm_format_t format;
-       int bytes_per_sample;
-       int num_bytes;
-       spd_alsa_id_t *alsa_id = (spd_alsa_id_t *) id;
-
-       signed short *output_samples;
-
-       AudioTrack track_volume;
-       float real_volume;
-       int i;
-
-       int err;
-       int ret;
-
-       snd_pcm_uframes_t framecount;
-       snd_pcm_uframes_t period_size;
-       size_t samples_per_period;
-       size_t silent_samples;
-       size_t volume_size;
-       unsigned int sr;
-
-       snd_pcm_state_t state;
-
-       struct pollfd alsa_stop_pipe_pfd;
-
-       if (alsa_id == NULL) {
-               ERR("Invalid device passed to alsa_play()");
-               return -1;
-       }
-
-       pthread_mutex_lock(&alsa_id->alsa_pipe_mutex);
-
-       MSG(2, "Start of playback on ALSA");
-
-       /* Is it not an empty track? */
-       /* Passing an empty track is not an error */
-       if (track.samples == NULL) {
-               pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
-               return 0;
-       }
-       /* Allocate space for hw_params (description of the sound parameters) */
-       MSG(2, "Allocating new hw_params structure");
-       if ((err = snd_pcm_hw_params_malloc(&alsa_id->alsa_hw_params)) < 0) {
-               ERR("Cannot allocate hardware parameter structure (%s)",
-                   snd_strerror(err));
-               pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
-               return -1;
-       }
-
-       /* Initialize hw_params on our pcm */
-       if ((err =
-            snd_pcm_hw_params_any(alsa_id->alsa_pcm,
-                                  alsa_id->alsa_hw_params)) < 0) {
-               ERR("Cannot initialize hardware parameter structure (%s)",
-                   snd_strerror(err));
-               pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
-               return -1;
-       }
-
-       /* Create the pipe for communication about stop requests */
-       if (pipe(alsa_id->alsa_stop_pipe)) {
-               ERR("Stop pipe creation failed (%s)", strerror(errno));
-               pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
-               return -1;
-       }
-
-       /* Find how many descriptors we will get for poll() */
-       alsa_id->alsa_fd_count =
-           snd_pcm_poll_descriptors_count(alsa_id->alsa_pcm);
-       if (alsa_id->alsa_fd_count <= 0) {
-               ERR("Invalid poll descriptors count returned from ALSA.");
-               pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
-               return -1;
-       }
-
-       /* Create and fill in struct pollfd *alsa_poll_fds with ALSA 
descriptors */
-       alsa_id->alsa_poll_fds =
-           g_malloc((alsa_id->alsa_fd_count + 1) * sizeof(struct pollfd));
-       assert(alsa_id->alsa_poll_fds);
-       if ((err =
-            snd_pcm_poll_descriptors(alsa_id->alsa_pcm, alsa_id->alsa_poll_fds,
-                                     alsa_id->alsa_fd_count)) < 0) {
-               ERR("Unable to obtain poll descriptors for playback: %s\n",
-                   snd_strerror(err));
-               pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
-               return -1;
-       }
-
-       /* Create a new pollfd structure for requests by alsa_stop() */
-       alsa_stop_pipe_pfd.fd = alsa_id->alsa_stop_pipe[0];
-       alsa_stop_pipe_pfd.events = POLLIN;
-       alsa_stop_pipe_pfd.revents = 0;
-
-       /* Join this our own pollfd to the ALSAs ones */
-       alsa_id->alsa_poll_fds[alsa_id->alsa_fd_count] = alsa_stop_pipe_pfd;
-       alsa_id->alsa_fd_count++;
-
-       alsa_id->alsa_opened = 1;
-       pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
-
-       /* Report current state */
-       state = snd_pcm_state(alsa_id->alsa_pcm);
-       MSG(4, "PCM state before setting audio parameters: %s",
-           snd_pcm_state_name(state));
-
-       /* Choose the correct format */
-       if (track.bits == 16) {
-               switch (alsa_id->id.format) {
-               case SPD_AUDIO_LE:
-                       format = SND_PCM_FORMAT_S16_LE;
-                       break;
-               case SPD_AUDIO_BE:
-                       format = SND_PCM_FORMAT_S16_BE;
-                       break;
-               default:
-                       ERR("unknown audio format (%d)", alsa_id->id.format);
-                       return -1;
-               }
-               bytes_per_sample = 2;
-       } else if (track.bits == 8) {
-               bytes_per_sample = 1;
-               format = SND_PCM_FORMAT_S8;
-       } else {
-               ERR("Unsupported sound data format, track.bits = %d",
-                   track.bits);
-               return -1;
-       }
-
-       /* Set access mode, bitrate, sample rate and channels */
-       MSG(4, "Setting access type to INTERLEAVED");
-       if ((err = snd_pcm_hw_params_set_access(alsa_id->alsa_pcm,
-                                               alsa_id->alsa_hw_params,
-                                               SND_PCM_ACCESS_RW_INTERLEAVED)
-           ) < 0) {
-               ERR("Cannot set access type (%s)", snd_strerror(err));
-               return -1;
-       }
-
-       MSG(4, "Setting sample format to %s", snd_pcm_format_name(format));
-       if ((err =
-            snd_pcm_hw_params_set_format(alsa_id->alsa_pcm,
-                                         alsa_id->alsa_hw_params,
-                                         format)) < 0) {
-               ERR("Cannot set sample format (%s)", snd_strerror(err));
-               return -1;
-       }
-
-       MSG(4, "Setting sample rate to %i", track.sample_rate);
-       sr = track.sample_rate;
-       if ((err =
-            snd_pcm_hw_params_set_rate_near(alsa_id->alsa_pcm,
-                                            alsa_id->alsa_hw_params, &sr,
-                                            0)) < 0) {
-               ERR("Cannot set sample rate (%s)", snd_strerror(err));
-
-               return -1;
-       }
-
-       MSG(4, "Setting channel count to %i", track.num_channels);
-       if ((err =
-            snd_pcm_hw_params_set_channels(alsa_id->alsa_pcm,
-                                           alsa_id->alsa_hw_params,
-                                           track.num_channels)) < 0) {
-               MSG(4, "cannot set channel count (%s)", snd_strerror(err));
-               return -1;
-       }
-
-       MSG(4, "Setting hardware parameters on the ALSA device");
-       if ((err =
-            snd_pcm_hw_params(alsa_id->alsa_pcm,
-                              alsa_id->alsa_hw_params)) < 0) {
-               MSG(4, "cannot set parameters (%s) state=%s", snd_strerror(err),
-                   snd_pcm_state_name(snd_pcm_state(alsa_id->alsa_pcm)));
-               return -1;
-       }
-
-       /* Get the current swparams */
-       if ((err =
-            snd_pcm_sw_params_current(alsa_id->alsa_pcm,
-                                      alsa_id->alsa_sw_params)) < 0) {
-               ERR("Unable to determine current swparams for playback: %s\n",
-                   snd_strerror(err));
-               return -1;
-       }
-       //    MSG("Checking buffer size");
-       if ((err =
-            snd_pcm_hw_params_get_buffer_size(alsa_id->alsa_hw_params,
-                                              &(alsa_id->alsa_buffer_size))) <
-           0) {
-               ERR("Unable to get buffer size for playback: %s\n",
-                   snd_strerror(err));
-               return -1;
-       }
-       MSG(4, "Buffer size on ALSA device is %d bytes",
-           (int)alsa_id->alsa_buffer_size);
-
-       /* This is probably better left for the device driver to decide */
-       /* allow the transfer when at least period_size samples can be 
processed */
-       /*    err = snd_pcm_sw_params_set_avail_min(id->alsa_pcm, 
id->alsa_sw_params, id->alsa_buffer_size/4);
-          if (err < 0) {
-          ERR("Unable to set avail min for playback: %s\n", snd_strerror(err));
-          return err;
-          } */
-
-       /* Get period size. */
-       snd_pcm_hw_params_get_period_size(alsa_id->alsa_hw_params, &period_size,
-                                         0);
-
-       /* Calculate size of silence at end of buffer. */
-       samples_per_period = period_size * track.num_channels;
-       //    MSG("samples per period = %i", samples_per_period);
-       //    MSG("num_samples = %i", track.num_samples);
-       silent_samples =
-           samples_per_period - (track.num_samples % samples_per_period);
-       //    MSG("silent samples = %i", silent_samples);
-
-       MSG(4, "Preparing device for playback");
-       if ((err = snd_pcm_prepare(alsa_id->alsa_pcm)) < 0) {
-               ERR("Cannot prepare audio interface for playback (%s)",
-                   snd_strerror(err));
-
-               return -1;
-       }
-
-       /* Calculate space needed to round up to nearest period size. */
-       volume_size = bytes_per_sample * (track.num_samples + silent_samples);
-       MSG(4, "volume size = %i", (int)volume_size);
-
-       /* Create a copy of track with adjusted volume. */
-       MSG(4, "Making copy of track and adjusting volume");
-       track_volume = track;
-       track_volume.samples = (short *)g_malloc(volume_size);
-       real_volume = ((float)alsa_id->id.volume + 100) / (float)200;
-       for (i = 0; i <= track.num_samples - 1; i++)
-               track_volume.samples[i] = track.samples[i] * real_volume;
-
-       if (silent_samples > 0) {
-               u_int16_t silent16;
-               u_int8_t silent8;
-
-               /* Fill remaining space with silence */
-               MSG(4,
-                   "Filling with silence up to the period size, 
silent_samples=%d",
-                   (int)silent_samples);
-               /* TODO: This hangs.  Why?
-                  snd_pcm_format_set_silence(format,
-                  track_volume.samples + (track.num_samples * 
bytes_per_sample), silent_samples);
-                */
-               switch (bytes_per_sample) {
-               case 2:
-                       silent16 = snd_pcm_format_silence_16(format);
-                       for (i = 0; i < silent_samples; i++)
-                               track_volume.samples[track.num_samples + i] =
-                                   silent16;
-                       break;
-               case 1:
-                       silent8 = snd_pcm_format_silence(format);
-                       for (i = 0; i < silent_samples; i++)
-                               track_volume.samples[track.num_samples + i] =
-                                   silent8;
-                       break;
-               }
-       }
-
-       /* Loop until all samples are played on the device. */
-       output_samples = track_volume.samples;
-       num_bytes = (track.num_samples + silent_samples) * bytes_per_sample;
-       //    MSG("Still %d bytes left to be played", num_bytes);
-       while (num_bytes > 0) {
-
-               /* Write as much samples as possible */
-               framecount = num_bytes / bytes_per_sample / track.num_channels;
-               if (framecount < period_size)
-                       framecount = period_size;
-
-               /* Report current state state */
-               state = snd_pcm_state(alsa_id->alsa_pcm);
-               //      MSG("PCM state before writei: %s",
-               //          snd_pcm_state_name(state));
-
-               /* MSG("snd_pcm_writei() called") */
-               ret =
-                   snd_pcm_writei(alsa_id->alsa_pcm, output_samples,
-                                  framecount);
-               //        MSG("Sent %d of %d remaining bytes", 
ret*bytes_per_sample, num_bytes);
-
-               if (ret == -EAGAIN) {
-                       MSG(4, "Warning: Forced wait!");
-                       snd_pcm_wait(alsa_id->alsa_pcm, 100);
-               } else if (ret == -EPIPE) {
-                       if (xrun(alsa_id) != 0)
-                               ERROR_EXIT();
-               } else if (ret == -ESTRPIPE) {
-                       if (suspend(alsa_id) != 0)
-                               ERROR_EXIT();
-               } else if (ret == -EBUSY) {
-                       MSG(4, "WARNING: sleeping while PCM BUSY");
-                       usleep(100);
-                       continue;
-               } else if (ret < 0) {
-                       ERR("Write to audio interface failed (%s)",
-                           snd_strerror(ret));
-                       ERROR_EXIT();
-               }
-
-               if (ret > 0) {
-                       /* Update counter of bytes left and move the data 
pointer */
-                       num_bytes -=
-                           ret * bytes_per_sample * track.num_channels;
-                       output_samples +=
-                           ret * bytes_per_sample * track.num_channels / 2;
-               }
-
-               /* Report current state */
-               state = snd_pcm_state(alsa_id->alsa_pcm);
-               //      MSG("PCM state before polling: %s",
-               //          snd_pcm_state_name(state));
-
-               err =
-                   wait_for_poll(alsa_id, alsa_id->alsa_poll_fds,
-                                 alsa_id->alsa_fd_count, 0);
-               if (err < 0) {
-                       ERR("Wait for poll() failed\n");
-                       ERROR_EXIT();
-               } else if (err == 1) {
-                       MSG(4, "Playback stopped");
-
-                       /* Drop the playback on the sound device (probably
-                          still in progress up till now) */
-                       err = snd_pcm_drop(alsa_id->alsa_pcm);
-                       if (err < 0) {
-                               ERR("snd_pcm_drop() failed: %s",
-                                   snd_strerror(err));
-                               return -1;
-                       }
-
-                       goto terminate;
-               }
-
-               if (num_bytes <= 0)
-                       break;
-//      MSG("ALSA ready for more samples");
-
-               /* Stop requests can be issued again */
-       }
-
-       MSG(4, "Draining...");
-
-       /* We want to next "device ready" notification only after the buffer is
-          already empty */
-       err =
-           snd_pcm_sw_params_set_avail_min(alsa_id->alsa_pcm,
-                                           alsa_id->alsa_sw_params,
-                                           alsa_id->alsa_buffer_size);
-       if (err < 0) {
-               ERR("Unable to set avail min for playback: %s\n",
-                   snd_strerror(err));
-               return err;
-       }
-       /* write the parameters to the playback device */
-       err = snd_pcm_sw_params(alsa_id->alsa_pcm, alsa_id->alsa_sw_params);
-       if (err < 0) {
-               ERR("Unable to set sw params for playback: %s\n",
-                   snd_strerror(err));
-               return -1;
-       }
-
-       err =
-           wait_for_poll(alsa_id, alsa_id->alsa_poll_fds,
-                         alsa_id->alsa_fd_count, 1);
-       if (err < 0) {
-               ERR("Wait for poll() failed\n");
-               return -1;
-       } else if (err == 1) {
-               MSG(4, "Playback stopped while draining");
-
-               /* Drop the playback on the sound device (probably
-                  still in progress up till now) */
-               err = snd_pcm_drop(alsa_id->alsa_pcm);
-               if (err < 0) {
-                       ERR("snd_pcm_drop() failed: %s", snd_strerror(err));
-                       return -1;
-               }
-       }
-       MSG(4, "Draining terminated");
-
-terminate:
-       /* Terminating (successfully or after a stop) */
-       if (track_volume.samples != NULL)
-               g_free(track_volume.samples);
-
-       err = snd_pcm_drop(alsa_id->alsa_pcm);
-       if (err < 0) {
-               ERR("snd_pcm_drop() failed: %s", snd_strerror(err));
-               return -1;
-       }
-
-       MSG(2, "Freeing HW parameters");
-       snd_pcm_hw_params_free(alsa_id->alsa_hw_params);
-
-       pthread_mutex_lock(&alsa_id->alsa_pipe_mutex);
-       alsa_id->alsa_opened = 0;
-       close(alsa_id->alsa_stop_pipe[0]);
-       close(alsa_id->alsa_stop_pipe[1]);
-
-       g_free(alsa_id->alsa_poll_fds);
-       pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
-
-       MSG(1, "End of playback on ALSA");
-
-       return 0;
-}
-
-#undef ERROR_EXIT
-
-/*
- Stop the playback on the device and interrupt alsa_play()
-*/
-static int alsa_stop(AudioID * id)
-{
-       char buf;
-       int ret;
-       spd_alsa_id_t *alsa_id = (spd_alsa_id_t *) id;
-
-       MSG(1, "STOP!");
-
-       if (alsa_id == NULL)
-               return 0;
-
-       pthread_mutex_lock(&alsa_id->alsa_pipe_mutex);
-       if (alsa_id->alsa_opened) {
-               /* This constant is arbitrary */
-               buf = 42;
-
-               ret = write(alsa_id->alsa_stop_pipe[1], &buf, 1);
-               if (ret <= 0) {
-                       ERR("Can't write stop request to pipe, err %d: %s",
-                           errno, strerror(errno));
-               }
-       }
-       pthread_mutex_unlock(&alsa_id->alsa_pipe_mutex);
-
-       return 0;
-}
-
-/* 
-  Set volume
-
-  Comments: It's not possible to set individual track volume with Alsa, so we
-   handle volume in alsa_play() by multiplication of each sample.
-*/
-static int alsa_set_volume(AudioID * id, int volume)
-{
-       return 0;
-}
-
-static void alsa_set_loglevel(int level)
-{
-       if (level) {
-               alsa_log_level = level;
-       }
-}
-
-static char const *alsa_get_playcmd(void)
-{
-       return alsa_play_cmd;
-}
-
-/* Provide the Alsa backend. */
-static spd_audio_plugin_t alsa_functions = {
-       "alsa",
-       alsa_open,
-       alsa_play,
-       alsa_stop,
-       alsa_close,
-       alsa_set_volume,
-       alsa_set_loglevel,
-       alsa_get_playcmd
-};
-
-spd_audio_plugin_t *alsa_plugin_get(void)
-{
-       return &alsa_functions;
-}
-
-spd_audio_plugin_t *SPD_AUDIO_PLUGIN_ENTRY(void)
-    __attribute__ ((weak, alias("alsa_plugin_get")));
-#undef MSG
-#undef ERR
diff --git a/src/modules/audio/libao.c b/src/modules/audio/libao.c
deleted file mode 100644
index e82be2b..0000000
--- a/src/modules/audio/libao.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * libao.c -- The libao backend for the spd_audio library.
- *
- * Author: Marco Skambraks <marco at openblinux.de>
- * Date:  2009-12-15
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Leser General Public License as published by the Free
- * Software Foundation; either version 2.1, or (at your option) any later
- * version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this package; see the file COPYING.  If not, write to the Free
- * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sys/time.h>
-#include <time.h>
-#include <string.h>
-#include <glib.h>
-#include <ao/ao.h>
-
-#define SPD_AUDIO_PLUGIN_ENTRY spd_libao_LTX_spd_audio_plugin_get
-#include <spd_audio_plugin.h>
-
-/* send a packet of XXX bytes to the sound device */
-#define AO_SEND_BYTES 256
-/* Put a message into the logfile (stderr) */
-#define MSG(level, arg...) \
- if(level <= libao_log_level){ \
-     time_t t; \
-     struct timeval tv; \
-     char *tstr; \
-     t = time(NULL); \
-     tstr = g_strdup(ctime(&t)); \
-     tstr[strlen(tstr)-1] = 0; \
-     gettimeofday(&tv,NULL); \
-     fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \
-     fprintf(stderr," libao:: "); \
-     fprintf(stderr,arg); \
-     fprintf(stderr,"\n"); \
-     fflush(stderr); \
-     g_free(tstr); \
-  }
-
-#define ERR(arg...) \
- { \
-     time_t t; \
-     struct timeval tv; \
-     char *tstr; \
-     t = time(NULL); \
-     tstr = g_strdup(ctime(&t)); \
-     tstr[strlen(tstr)-1] = 0; \
-     gettimeofday(&tv,NULL); \
-     fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \
-     fprintf(stderr," libao ERROR: "); \
-     fprintf(stderr,arg); \
-     fprintf(stderr,"\n"); \
-     fflush(stderr); \
-     g_free(tstr); \
-  }
-
-/* AO_FORMAT_INITIALIZER is an ao_sample_format structure with zero values
-   in all of its fields.  We can guarantee that the fields of a
-   stack-allocated ao_sample_format are zeroed by assigning
-   AO_FORMAT_INITIALIZER to it.
-   This is the most portable way to initialize a stack-allocated struct to
-   zero. */
-static ao_sample_format AO_FORMAT_INITIALIZER;
-static ao_sample_format current_ao_parameters;
-
-static volatile int ao_stop_playback = 0;
-
-static int default_driver;
-static int libao_log_level;
-
-ao_device *device = NULL;
-
-static inline void libao_open_handle(int rate, int channels, int bits)
-{
-       ao_sample_format format = AO_FORMAT_INITIALIZER;
-
-       format.channels = channels;
-       format.rate = rate;
-       format.bits = bits;
-       format.byte_format = AO_FMT_NATIVE;
-       device = ao_open_live(default_driver, &format, NULL);
-
-       if (device != NULL)
-               current_ao_parameters = format;
-}
-
-static inline void libao_close_handle(void)
-{
-       if (device != NULL) {
-               ao_close(device);
-               device = NULL;
-       }
-}
-
-static AudioID *libao_open(void **pars)
-{
-       AudioID *id;
-
-       id = (AudioID *) g_malloc(sizeof(AudioID));
-
-       ao_initialize();
-       default_driver = ao_default_driver_id();
-       return id;
-}
-
-static int libao_play(AudioID * id, AudioTrack track)
-{
-       int bytes_per_sample;
-
-       int num_bytes;
-
-       int outcnt = 0;
-
-       signed short *output_samples;
-
-       int i;
-
-       if (id == NULL)
-               return -1;
-       if (track.samples == NULL || track.num_samples <= 0)
-               return 0;
-
-       /* Choose the correct format */
-       if (track.bits == 16)
-               bytes_per_sample = 2;
-       else if (track.bits == 8)
-               bytes_per_sample = 1;
-       else {
-               ERR("Audio: Unrecognized sound data format.\n");
-               return -10;
-       }
-       MSG(3, "Starting playback");
-       output_samples = track.samples;
-       num_bytes = track.num_samples * bytes_per_sample;
-
-       if ((device == NULL)
-           || (track.num_channels != current_ao_parameters.channels)
-           || (track.sample_rate != current_ao_parameters.rate)
-           || (track.bits != current_ao_parameters.bits)) {
-               libao_close_handle();
-               libao_open_handle(track.sample_rate, track.num_channels,
-                                 track.bits);
-       }
-
-       if (device == NULL) {
-               ERR("error opening libao dev");
-               return -2;
-       }
-       MSG(3, "bytes to play: %d, (%f secs)", num_bytes,
-           (((float)(num_bytes) / 2) / (float)track.sample_rate));
-
-       ao_stop_playback = 0;
-       outcnt = 0;
-       i = 0;
-
-       while ((outcnt < num_bytes) && !ao_stop_playback) {
-               if ((num_bytes - outcnt) > AO_SEND_BYTES)
-                       i = AO_SEND_BYTES;
-               else
-                       i = (num_bytes - outcnt);
-
-               if (!ao_play(device, (char *)output_samples + outcnt, i)) {
-                       libao_close_handle();
-                       ERR("Audio: ao_play() - closing device - re-open it in 
next run\n");
-                       return -1;
-               }
-               outcnt += i;
-       }
-
-       return 0;
-
-}
-
-/* stop the libao_play() loop */
-static int libao_stop(AudioID * id)
-{
-
-       ao_stop_playback = 1;
-       return 0;
-}
-
-static int libao_close(AudioID * id)
-{
-       libao_close_handle();
-       ao_shutdown();
-
-       g_free(id);
-       id = NULL;
-       return 0;
-}
-
-static int libao_set_volume(AudioID * id, int volume)
-{
-       return 0;
-}
-
-static void libao_set_loglevel(int level)
-{
-       if (level) {
-               libao_log_level = level;
-       }
-}
-
-static char const *libao_get_playcmd(void)
-{
-       return NULL;
-}
-
-/* Provide the libao backend. */
-static spd_audio_plugin_t libao_functions = {
-       "libao",
-       libao_open,
-       libao_play,
-       libao_stop,
-       libao_close,
-       libao_set_volume,
-       libao_set_loglevel,
-       libao_get_playcmd
-};
-
-spd_audio_plugin_t *libao_plugin_get(void)
-{
-       return &libao_functions;
-}
-
-spd_audio_plugin_t *SPD_AUDIO_PLUGIN_ENTRY(void)
-    __attribute__ ((weak, alias("libao_plugin_get")));
-#undef MSG
-#undef ERR
diff --git a/src/modules/audio/nas.c b/src/modules/audio/nas.c
deleted file mode 100644
index ca76127..0000000
--- a/src/modules/audio/nas.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * nas.c -- The Network Audio System backend for the spd_audio library.
- *
- * Copyright (C) 2004,2006 Brailcom, o.p.s.
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1, or (at your option) any later
- * version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this package; see the file COPYING.  If not, write to the Free
- * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- * $Id: nas.c,v 1.8 2006-07-11 16:12:26 hanke Exp $
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <audio/audiolib.h>
-#include <audio/soundlib.h>
-
-#include <pthread.h>
-
-#define SPD_AUDIO_PLUGIN_ENTRY spd_nas_LTX_spd_audio_plugin_get
-#include <spd_audio_plugin.h>
-
-typedef struct {
-       AudioID id;
-       AuServer *aud;
-       AuFlowID flow;
-       pthread_mutex_t flow_mutex;
-       pthread_t nas_event_handler;
-       pthread_cond_t pt_cond;
-       pthread_mutex_t pt_mutex;
-} spd_nas_id_t;
-
-static int nas_log_level;
-
-/* Internal event handler */
-static void *_nas_handle_events(void *par)
-{
-       spd_nas_id_t *nas_id = (spd_nas_id_t *) par;
-       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
-
-       while (1)
-               AuHandleEvents(nas_id->aud);
-
-}
-
-/* NAS Server error handler */
-/* Unfortunatelly we can't return these errors to the caller
-   since this handler gets called in the event handler thread. */
-static AuBool _nas_handle_server_error(AuServer * server, AuErrorEvent * event)
-{
-       fprintf(stderr, "ERROR: Non-fatal server error in NAS\n");
-
-       if (event->type != 0) {
-               fprintf(stderr,
-                       "Event of a different type received in NAS error 
handler.");
-               return -1;
-       }
-
-       /* It's a pain but we can't ask for string return code
-          since it's not allowed to talk to the server inside error handlers
-          because of possible deadlocks. */
-       fprintf(stderr, "NAS: Serial number of failed request: %d\n",
-               event->serial);
-       fprintf(stderr, "NAS: Error code: %d\n", event->error_code);
-       fprintf(stderr, "NAS: Resource id: %d\n", event->resourceid);
-       fprintf(stderr, "NAS: Request code: %d\n", event->request_code);
-       fprintf(stderr, "NAS: Minor code: %d\n\n", event->minor_code);
-
-       return 0;
-}
-
-static AudioID *nas_open(void **pars)
-{
-       spd_nas_id_t *nas_id;
-       int ret;
-       AuBool r;
-
-       nas_id = (spd_nas_id_t *) g_malloc(sizeof(spd_nas_id_t));
-
-       nas_id->aud = AuOpenServer(pars[2], 0, NULL, 0, NULL, NULL);
-       if (!nas_id->aud) {
-               fprintf(stderr, "Can't connect to NAS audio server\n");
-               return NULL;
-       }
-
-       AuSetErrorHandler(nas_id->aud, _nas_handle_server_error);
-       /* return value incompatible with documentation here */
-       /*    if (!r){
-          fprintf(stderr, "Can't set default NAS event handler\n");
-          return -1;
-          } */
-
-       nas_id->flow = 0;
-
-       pthread_cond_init(&nas_id->pt_cond, NULL);
-       pthread_mutex_init(&nas_id->pt_mutex, NULL);
-       pthread_mutex_init(&nas_id->flow_mutex, NULL);
-
-       ret =
-           pthread_create(&nas_id->nas_event_handler, NULL, _nas_handle_events,
-                          (void *)nas_id);
-       if (ret != 0) {
-               fprintf(stderr,
-                       "ERROR: NAS Audio module: thread creation failed\n");
-               return NULL;
-       }
-
-       return (AudioID *) nas_id;
-}
-
-static int nas_play(AudioID * id, AudioTrack track)
-{
-       char *buf;
-       Sound s;
-       AuEventHandlerRec *event_handler;
-       int ret;
-       float lenght;
-       struct timeval now;
-       struct timespec timeout;
-       spd_nas_id_t *nas_id = (spd_nas_id_t *) id;
-
-       if (nas_id == NULL)
-               return -2;
-
-       s = SoundCreate(SoundFileFormatNone,
-                       AuFormatLinearSigned16LSB,
-                       track.num_channels,
-                       track.sample_rate, track.num_samples, NULL);
-
-       buf = (char *)track.samples;
-
-       pthread_mutex_lock(&nas_id->flow_mutex);
-
-       event_handler = AuSoundPlayFromData(nas_id->aud,
-                                           s,
-                                           buf,
-                                           AuNone,
-                                           ((nas_id->id.volume +
-                                             100) / 2) * 1500, NULL, NULL,
-                                           &nas_id->flow, NULL, NULL, NULL);
-
-       if (event_handler == NULL) {
-               fprintf(stderr,
-                       "AuSoundPlayFromData failed for unknown resons.\n");
-               return -1;
-       }
-
-       if (nas_id->flow == 0) {
-               fprintf(stderr, "Couldn't start data flow");
-       }
-       pthread_mutex_unlock(&nas_id->flow_mutex);
-
-       /* Another timing magic */
-       pthread_mutex_lock(&nas_id->pt_mutex);
-       lenght = (((float)track.num_samples) / (float)track.sample_rate);
-       gettimeofday(&now, NULL);
-       timeout.tv_sec = now.tv_sec + (int)lenght;
-       timeout.tv_nsec =
-           now.tv_usec * 1000 + (lenght - (int)lenght) * 1000000000;
-       pthread_cond_timedwait(&nas_id->pt_cond, &nas_id->pt_mutex, &timeout);
-       pthread_mutex_unlock(&nas_id->pt_mutex);
-
-       pthread_mutex_lock(&nas_id->flow_mutex);
-       nas_id->flow = 0;
-       pthread_mutex_unlock(&nas_id->flow_mutex);
-
-       return 0;
-}
-
-static int nas_stop(AudioID * id)
-{
-       int ret;
-       spd_nas_id_t *nas_id = (spd_nas_id_t *) id;
-
-       if (nas_id == NULL)
-               return -2;
-
-       pthread_mutex_lock(&nas_id->flow_mutex);
-       if (nas_id->flow != 0)
-               AuStopFlow(nas_id->aud, nas_id->flow, NULL);
-       nas_id->flow = 0;
-       pthread_mutex_unlock(&nas_id->flow_mutex);
-
-       pthread_mutex_lock(&nas_id->pt_mutex);
-       pthread_cond_signal(&nas_id->pt_cond);
-       pthread_mutex_unlock(&nas_id->pt_mutex);
-
-       return 0;
-}
-
-static int nas_close(AudioID * id)
-{
-       spd_nas_id_t *nas_id = (spd_nas_id_t *) id;
-
-       if (nas_id == NULL)
-               return -2;
-
-       pthread_cancel(nas_id->nas_event_handler);
-       pthread_join(nas_id->nas_event_handler, NULL);
-
-       pthread_mutex_destroy(&nas_id->pt_mutex);
-       pthread_mutex_destroy(&nas_id->flow_mutex);
-
-       AuCloseServer(nas_id->aud);
-
-       g_free(nas_id);
-       id = NULL;
-
-       return 0;
-}
-
-static int nas_set_volume(AudioID * id, int volume)
-{
-       return 0;
-}
-
-static void nas_set_loglevel(int level)
-{
-       if (level) {
-               nas_log_level = level;
-       }
-}
-
-static char const *nas_get_playcmd(void)
-{
-       return NULL;
-}
-
-/* Provide the NAS backend */
-static spd_audio_plugin_t nas_functions = {
-       "nas",
-       nas_open,
-       nas_play,
-       nas_stop,
-       nas_close,
-       nas_set_volume,
-       nas_set_loglevel,
-       nas_get_playcmd
-};
-
-spd_audio_plugin_t *nas_plugin_get(void)
-{
-       return &nas_functions;
-}
-
-spd_audio_plugin_t *SPD_AUDIO_PLUGIN_ENTRY(void)
-    __attribute__ ((weak, alias("nas_plugin_get")));
diff --git a/src/modules/audio/oss.c b/src/modules/audio/oss.c
deleted file mode 100644
index b7232c3..0000000
--- a/src/modules/audio/oss.c
+++ /dev/null
@@ -1,523 +0,0 @@
-
-/*
- * oss.c -- The Open Sound System backend for the spd_audio library.
- *
- * Copyright (C) 2004,2006 Brailcom, o.p.s.
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Leser General Public License as published by the Free
- * Software Foundation; either version 2.1, or (at your option) any later
- * version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this package; see the file COPYING.  If not, write to the Free
- * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- * $Id: oss.c,v 1.13 2006-07-11 16:12:26 hanke Exp $
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <sys/time.h>
-#include <time.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/soundcard.h>
-#include <errno.h>
-#include <unistd.h>            /* for open, close */
-#include <sys/ioctl.h>
-#include <pthread.h>
-#include <glib.h>
-
-#include <sys/soundcard.h>
-
-#define SPD_AUDIO_PLUGIN_ENTRY spd_oss_LTX_spd_audio_plugin_get
-#include <spd_audio_plugin.h>
-
-typedef struct {
-       AudioID id;
-       int fd;
-       char *device_name;
-       pthread_mutex_t fd_mutex;
-       pthread_cond_t pt_cond;
-       pthread_mutex_t pt_mutex;
-} spd_oss_id_t;
-
-static int _oss_open(spd_oss_id_t * id);
-static int _oss_close(spd_oss_id_t * id);
-static int _oss_sync(spd_oss_id_t * id);
-
-/* Put a message into the logfile (stderr) */
-#define MSG(level, arg...) \
- if(level <= oss_log_level){ \
-     time_t t; \
-     struct timeval tv; \
-     char *tstr; \
-     t = time(NULL); \
-     tstr = g_strdup(ctime(&t)); \
-     tstr[strlen(tstr)-1] = 0; \
-     gettimeofday(&tv,NULL); \
-     fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \
-     fprintf(stderr," OSS: "); \
-     fprintf(stderr,arg); \
-     fprintf(stderr,"\n"); \
-     fflush(stderr); \
-     g_free(tstr); \
-  }
-
-#define ERR(arg...) \
- { \
-     time_t t; \
-     struct timeval tv; \
-     char *tstr; \
-     t = time(NULL); \
-     tstr = g_strdup(ctime(&t)); \
-     tstr[strlen(tstr)-1] = 0; \
-     gettimeofday(&tv,NULL); \
-     fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \
-     fprintf(stderr," OSS ERROR: "); \
-     fprintf(stderr,arg); \
-     fprintf(stderr,"\n"); \
-     fflush(stderr); \
-     g_free(tstr); \
-  }
-
-static int oss_log_level;
-static char const *oss_play_cmd = "play";
-
-static int _oss_open(spd_oss_id_t * id)
-{
-       MSG(1, "_oss_open()")
-           pthread_mutex_lock(&id->fd_mutex);
-
-       id->fd = open(id->device_name, O_WRONLY, 0);
-       if (id->fd < 0) {
-               perror(id->device_name);
-               pthread_mutex_unlock(&id->fd_mutex);
-               id = NULL;
-               return -1;
-       }
-
-       pthread_mutex_unlock(&id->fd_mutex);
-
-       return 0;
-}
-
-static int _oss_close(spd_oss_id_t * id)
-{
-       MSG(1, "_oss_close()")
-           if (id == NULL)
-               return 0;
-       if (id->fd < 0)
-               return 0;
-
-       pthread_mutex_lock(&id->fd_mutex);
-       close(id->fd);
-       id->fd = -1;
-       pthread_mutex_unlock(&id->fd_mutex);
-       return 0;
-}
-
-/* Open OSS device
-   Arguments:
-     **pars:
-      (char*) pars[0] -- the name of the device (e.g. "/dev/dsp")
-      (void*) pars[1] = NULL 
-*/
-static AudioID *oss_open(void **pars)
-{
-       spd_oss_id_t *oss_id;
-       int ret;
-
-       if (pars[0] == NULL)
-               return NULL;
-
-       oss_id = (spd_oss_id_t *) g_malloc(sizeof(spd_oss_id_t));
-
-       oss_id->device_name = g_strdup((char *)pars[0]);
-
-       pthread_mutex_init(&oss_id->fd_mutex, NULL);
-
-       pthread_cond_init(&oss_id->pt_cond, NULL);
-       pthread_mutex_init(&oss_id->pt_mutex, NULL);
-
-       /* Test if it's possible to access the device */
-       ret = _oss_open(oss_id);
-       if (ret) {
-               g_free(oss_id->device_name);
-               g_free(oss_id);
-               return NULL;
-       }
-       ret = _oss_close(oss_id);
-       if (ret) {
-               g_free(oss_id->device_name);
-               g_free(oss_id);
-               return NULL;
-       }
-
-       return (AudioID *) oss_id;
-}
-
-/* Internal function. */
-static int _oss_sync(spd_oss_id_t * id)
-{
-       int ret;
-
-       ret = ioctl(id->fd, SNDCTL_DSP_POST, 0);
-       if (ret == -1) {
-               perror("reset");
-               return -1;
-       }
-       return 0;
-}
-
-static int oss_play(AudioID * id, AudioTrack track)
-{
-       int ret, ret2;
-       struct timeval now;
-       struct timespec timeout;
-       float lenght;
-       int r = 0;
-       int format, oformat, channels, speed;
-       int bytes_per_sample;
-       int num_bytes;
-       signed short *output_samples;
-       float delay = 0;
-       float DELAY = 0.1;      /* in seconds */
-       audio_buf_info info;
-       int bytes;
-       float real_volume;
-       int i;
-       int re;
-       spd_oss_id_t *oss_id = (spd_oss_id_t *) id;
-
-       AudioTrack track_volume;
-
-       if (oss_id == NULL)
-               return -1;
-
-       /* Open the sound device. This is necessary for OSS so that the
-          application doesn't prevent others from accessing /dev/dsp when
-          it doesn't play anything. */
-       ret = _oss_open(oss_id);
-       if (ret)
-               return -2;
-
-       /* Create a copy of track with the adjusted volume */
-       track_volume = track;
-       track_volume.samples =
-           (short *)g_malloc(sizeof(short) * track.num_samples);
-       real_volume = ((float)id->volume + 100) / (float)200;
-       for (i = 0; i <= track.num_samples - 1; i++)
-               track_volume.samples[i] = track.samples[i] * real_volume;
-
-       /* Choose the correct format */
-       if (track.bits == 16) {
-               format = AFMT_S16_NE;
-               bytes_per_sample = 2;
-       } else if (track.bits == 8) {
-               bytes_per_sample = 1;
-               format = AFMT_S8;
-       } else {
-               ERR("Audio: Unrecognized sound data format.\n");
-               _oss_close(oss_id);
-               return -10;
-       }
-
-       oformat = format;
-       ret = ioctl(oss_id->fd, SNDCTL_DSP_SETFMT, &format);
-       if (ret == -1) {
-               perror("OSS ERROR: format");
-               _oss_close(oss_id);
-               return -1;
-       }
-       if (format != oformat) {
-               ERR("Device doesn't support 16-bit sound format.\n");
-               _oss_close(oss_id);
-               return -2;
-       }
-
-       /* Choose the correct number of channels */
-       channels = track.num_channels;
-       ret = ioctl(oss_id->fd, SNDCTL_DSP_CHANNELS, &channels);
-       if (ret == -1) {
-               perror("OSS ERROR: channels");
-               _oss_close(oss_id);
-               return -3;
-       }
-       if (channels != track.num_channels) {
-               MSG(1, "Device doesn't support stereo sound.\n");
-               _oss_close(oss_id);
-               return -4;
-       }
-
-       /* Choose the correct sample rate */
-       speed = track.sample_rate;
-       ret = ioctl(oss_id->fd, SNDCTL_DSP_SPEED, &speed);
-       if (ret == -1) {
-               ERR("OSS ERROR: Can't set sample rate %d nor any similar.",
-                   track.sample_rate);
-               _oss_close(oss_id);
-               return -5;
-       }
-       if (speed != track.sample_rate) {
-               ERR("Device doesn't support bitrate %d, using %d instead.\n",
-                   track.sample_rate, speed);
-       }
-
-       /* Is it not an empty track? */
-       if (track.samples == NULL) {
-               _oss_close(oss_id);
-               return 0;
-       }
-
-       /* Loop until all samples are played on the device.
-          In the meantime, wait in pthread_cond_timedwait for more data
-          or for interruption. */
-       MSG(4, "Starting playback");
-       output_samples = track_volume.samples;
-       num_bytes = track.num_samples * bytes_per_sample;
-       MSG(4, "bytes to play: %d, (%f secs)", num_bytes,
-           (((float)(num_bytes) / 2) / (float)track.sample_rate));
-       while (num_bytes > 0) {
-
-               /* OSS doesn't support non-blocking write, so lets check how 
much data
-                  can we write so that write() returns immediatelly */
-               re = ioctl(oss_id->fd, SNDCTL_DSP_GETOSPACE, &info);
-               if (re == -1) {
-                       perror("OSS ERROR: GETOSPACE");
-                       _oss_close(oss_id);
-                       return -5;
-               }
-
-               /* If there is not enough space for a single fragment, try 
later.
-                  (This shouldn't happen, it has very bad effect on 
synchronization!) */
-               if (info.fragments == 0) {
-                       MSG(4,
-                           "WARNING: There is not enough space for a single 
fragment, looping");
-                       usleep(100);
-                       continue;
-               }
-
-               MSG(4,
-                   "There is space for %d more fragments, fragment size is %d 
bytes",
-                   info.fragments, info.fragsize);
-
-               bytes = info.fragments * info.fragsize;
-               ret =
-                   write(oss_id->fd, output_samples,
-                         num_bytes > bytes ? bytes : num_bytes);
-
-               /* Handle write() errors */
-               if (ret <= 0) {
-                       perror("audio");
-                       _oss_close(oss_id);
-                       return -6;
-               }
-
-               num_bytes -= ret;
-               output_samples += ret / 2;
-
-               MSG(4, "%d bytes written to OSS, %d remaining", ret, num_bytes);
-
-               /* If there is some more data that is less than a
-                  full fragment, we need to write it immediatelly so
-                  that it doesn't cause buffer underruns later. */
-               if ((num_bytes > 0)
-                   && (num_bytes < info.fragsize)
-                   && (bytes + num_bytes < info.bytes)) {
-
-                       MSG(4,
-                           "Writing the rest of the data (%d bytes) to OSS, 
not a full fragment",
-                           num_bytes);
-
-                       ret2 = write(oss_id->fd, output_samples, num_bytes);
-                       num_bytes -= ret2;
-                       output_samples += ret2 / 2;
-                       ret += ret2;
-               }
-
-               /* Handle write() errors */
-               if (ret <= 0) {
-                       perror("audio");
-                       _oss_close(oss_id);
-                       return -6;
-               }
-
-               /* Some timing magic... 
-                  We need to wait for the time computed from the number of
-                  samples written. But this wait needs to be interruptible
-                  by oss_stop(). Furthermore, there need to be no buffer
-                  underrruns, so we actually wait a bit (DELAY) less
-                  in the first pass through the while() loop. Then our timer
-                  will be DELAY nsecs backwards.
-                */
-               MSG(4, "Now we will try to wait");
-               pthread_mutex_lock(&oss_id->pt_mutex);
-               lenght = (((float)(ret) / 2) / (float)track.sample_rate);
-               if (!delay) {
-                       delay = lenght > DELAY ? DELAY : lenght;
-                       lenght -= delay;
-               }
-               MSG(4, "Wait for %f secs (begin: %f, delay: %f)", lenght,
-                   lenght + delay, delay)
-                   gettimeofday(&now, NULL);
-               timeout.tv_sec = now.tv_sec + (int)lenght;
-               timeout.tv_nsec =
-                   now.tv_usec * 1000 + (lenght - (int)lenght) * 1000000000;
-               //MSG("5, waiting till %d:%d (%d:%d | %d:%d)", timeout.tv_sec, 
timeout.tv_nsec,
-               //    now.tv_sec, now.tv_usec*1000, timeout.tv_sec - 
now.tv_sec, timeout.tv_nsec-now.tv_usec*1000);
-
-               timeout.tv_sec += timeout.tv_nsec / 1000000000;
-               timeout.tv_nsec = timeout.tv_nsec % 1000000000;
-               //      MSG("6, waiting till %d:%d (%d:%d | %d:%d)", 
timeout.tv_sec, timeout.tv_nsec,
-               //  now.tv_sec, now.tv_usec*1000, timeout.tv_sec - now.tv_sec, 
timeout.tv_nsec-now.tv_usec*1000);
-               r = pthread_cond_timedwait(&oss_id->pt_cond, &oss_id->pt_mutex,
-                                          &timeout);
-               pthread_mutex_unlock(&oss_id->pt_mutex);
-               MSG(4, "End of wait");
-
-               /* The pthread_cond_timedwait was interrupted by change in the
-                  condition variable? if so, terminate. */
-               if (r != ETIMEDOUT) {
-                       MSG(4, "Playback stopped, %d", r);
-                       break;
-               }
-       }
-
-       /* ...one more excersise in timing magic. 
-          Wait for the resting delay secs. */
-
-       /* Ugly hack: correct for the time we spend outside timing segments */
-       delay -= 0.05;
-
-       MSG(4, "Wait for the resting delay = %f secs", delay)
-           if ((delay > 0) && (r == ETIMEDOUT)) {
-               pthread_mutex_lock(&oss_id->pt_mutex);
-               gettimeofday(&now, NULL);
-               timeout.tv_sec = now.tv_sec;
-               timeout.tv_nsec = now.tv_usec * 1000 + delay * 1000000000;
-               // MSG("6, waiting till %d:%d (%d:%d | %d:%d)", timeout.tv_sec, 
timeout.tv_nsec,
-               //          now.tv_sec, now.tv_usec*1000, timeout.tv_sec - 
now.tv_sec, timeout.tv_nsec-now.tv_usec*1000);
-               timeout.tv_sec += timeout.tv_nsec / 1000000000;
-               timeout.tv_nsec = timeout.tv_nsec % 1000000000;
-               // MSG("6, waiting till %d:%d (%d:%d | %d:%d)", timeout.tv_sec, 
timeout.tv_nsec,
-               //          now.tv_sec, now.tv_usec*1000, timeout.tv_sec - 
now.tv_sec, timeout.tv_nsec-now.tv_usec*1000);
-               r = pthread_cond_timedwait(&oss_id->pt_cond, &oss_id->pt_mutex,
-                                          &timeout);
-               pthread_mutex_unlock(&oss_id->pt_mutex);
-       }
-       MSG(4, "End of wait");
-
-       if (track_volume.samples != NULL)
-               g_free(track_volume.samples);
-
-       /* Flush all the buffers */
-       _oss_sync(oss_id);
-
-       /* Close the device so that we don't block other apps trying to
-          access the device. */
-       _oss_close(oss_id);
-
-       MSG(4, "Device closed");
-
-       return 0;
-}
-
-/* Stop the playback on the device and interrupt oss_play */
-static int oss_stop(AudioID * id)
-{
-       int ret = 0;
-       spd_oss_id_t *oss_id = (spd_oss_id_t *) id;
-
-       if (oss_id == NULL)
-               return 0;
-
-       MSG(4, "stop() called");
-
-       /* Stop the playback on /dev/dsp */
-       pthread_mutex_lock(&oss_id->fd_mutex);
-       if (oss_id->fd >= 0)
-               ret = ioctl(oss_id->fd, SNDCTL_DSP_RESET, 0);
-       pthread_mutex_unlock(&oss_id->fd_mutex);
-       if (ret == -1) {
-               perror("reset");
-               return -1;
-       }
-
-       /* Interrupt oss_play by setting the condition variable */
-       pthread_mutex_lock(&oss_id->pt_mutex);
-       pthread_cond_signal(&oss_id->pt_cond);
-       pthread_mutex_unlock(&oss_id->pt_mutex);
-       return 0;
-}
-
-/* Close the device */
-static int oss_close(AudioID * id)
-{
-       spd_oss_id_t *oss_id = (spd_oss_id_t *) id;
-
-       /* Does nothing because the device is being automatically openned and
-          closed in oss_play before and after playing each sample. */
-
-       g_free(oss_id->device_name);
-       g_free(oss_id);
-       id = NULL;
-
-       return 0;
-}
-
-/* Set volume
-
-Comments:
-  /dev/dsp can't set volume. We just multiply the track samples by
-  a constant in oss_play (see oss_play() for more information).
-*/
-static int oss_set_volume(AudioID * id, int volume)
-{
-       return 0;
-}
-
-static void oss_set_loglevel(int level)
-{
-       if (level) {
-               oss_log_level = level;
-       }
-}
-
-static char const *oss_get_playcmd(void)
-{
-       return oss_play_cmd;
-}
-
-/* Provide the OSS backend. */
-static spd_audio_plugin_t oss_functions = {
-       "oss",
-       oss_open,
-       oss_play,
-       oss_stop,
-       oss_close,
-       oss_set_volume,
-       oss_set_loglevel,
-       oss_get_playcmd
-};
-
-spd_audio_plugin_t *oss_plugin_get(void)
-{
-       return &oss_functions;
-}
-
-spd_audio_plugin_t *SPD_AUDIO_PLUGIN_ENTRY(void)
-    __attribute__ ((weak, alias("oss_plugin_get")));
-#undef MSG
-#undef ERR
diff --git a/src/modules/audio/pulse.c b/src/modules/audio/pulse.c
deleted file mode 100644
index a4137e5..0000000
--- a/src/modules/audio/pulse.c
+++ /dev/null
@@ -1,310 +0,0 @@
-
-/*
- * pulse.c -- The simple pulseaudio backend for the spd_audio library.
- *
- * Based on libao.c from Marco Skambraks <marco at openblinux.de>
- * Date:  2009-12-15
- *
- * Copied from Luke Yelavich's libao.c driver, and merged with code from
- * Marco's ao_pulse.c driver, by Bill Cox, Dec 21, 2009.
- *
- * Minor changes be Rui Batista <rui.batista at ist.utl.pt> to configure 
settings through speech-dispatcher configuration files
- * Date: Dec 22, 2009
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Leser General Public License as published by the Free
- * Software Foundation; either version 2.1, or (at your option) any later
- * version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this package; see the file COPYING.  If not, write to the Free
- * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <time.h>
-#include <string.h>
-#include <stdarg.h>
-#include <glib.h>
-
-#include <pulse/simple.h>
-#include <pulse/error.h>
-
-#define SPD_AUDIO_PLUGIN_ENTRY spd_pulse_LTX_spd_audio_plugin_get
-#include <spd_audio_plugin.h>
-
-/* Switch this on to debug, see output log location in MSG() */
-//#define DEBUG_PULSE
-typedef struct {
-       AudioID id;
-       pa_simple *pa_simple;
-       char *pa_server;
-       int pa_min_audio_length;
-       volatile int pa_stop_playback;
-       int pa_current_rate;    // Sample rate for currently PA connection
-       int pa_current_bps;     // Bits per sample rate for currently PA 
connection
-       int pa_current_channels;        // Number of channels for currently PA 
connection
-} spd_pulse_id_t;
-
-/* send a packet of XXX bytes to the sound device */
-#define PULSE_SEND_BYTES 256
-
-/* This is the smallest audio sound we are expected to play immediately 
without buffering. */
-/* Changed to define on config file. Default is the same. */
-#define DEFAULT_PA_MIN_AUDIO_LENgTH 100
-
-static int pulse_log_level;
-static char const *pulse_play_cmd = "paplay";
-
-/* Write to /tmp/speech-dispatcher-pulse.log */
-#ifdef DEBUG_PULSE
-static FILE *pulseDebugFile = NULL;
-static void MSG(char *message, ...)
-{
-       va_list ap;
-
-       if (pulseDebugFile == NULL) {
-               pulseDebugFile = fopen("/tmp/speech-dispatcher-pulse.log", "w");
-       }
-       va_start(ap, message);
-       vfprintf(pulseDebugFile, message, ap);
-       va_end(ap);
-       fflush(pulseDebugFile);
-}
-#else
-static void MSG(char *message, ...)
-{
-}
-#endif
-
-static int _pulse_open(spd_pulse_id_t * id, int sample_rate,
-                      int num_channels, int bytes_per_sample)
-{
-       pa_buffer_attr buffAttr;
-       pa_sample_spec ss;
-       int error;
-
-       ss.rate = sample_rate;
-       ss.channels = num_channels;
-       if (bytes_per_sample == 2) {
-               switch (id->id.format) {
-               case SPD_AUDIO_LE:
-                       ss.format = PA_SAMPLE_S16LE;
-                       break;
-               case SPD_AUDIO_BE:
-                       ss.format = PA_SAMPLE_S16BE;
-                       break;
-               }
-       } else {
-               ss.format = PA_SAMPLE_U8;
-       }
-
-       /* Set prebuf to one sample so that keys are spoken as soon as typed 
rather than delayed until the next key pressed */
-       buffAttr.maxlength = (uint32_t) - 1;
-       //buffAttr.tlength = (uint32_t)-1; - this is the default, which causes 
key echo to not work properly.
-       buffAttr.tlength = id->pa_min_audio_length;
-       buffAttr.prebuf = (uint32_t) - 1;
-       buffAttr.minreq = (uint32_t) - 1;
-       buffAttr.fragsize = (uint32_t) - 1;
-       /* Open new connection */
-       if (!
-           (id->pa_simple =
-            pa_simple_new(id->pa_server, "speech-dispatcher",
-                          PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL,
-                          &buffAttr, &error))) {
-               fprintf(stderr, __FILE__ ": pa_simple_new() failed: %s\n",
-                       pa_strerror(error));
-               return 1;
-       }
-       return 0;
-}
-
-/* Close the connection to the server.  Does not free the AudioID struct. */
-/* Usable in pulse_play, which closes connections on failure or */
-/* changes in audio parameters. */
-static void pulse_connection_close(spd_pulse_id_t * pulse_id)
-{
-       if (pulse_id->pa_simple != NULL) {
-               pa_simple_free(pulse_id->pa_simple);
-               pulse_id->pa_simple = NULL;
-       }
-}
-
-static AudioID *pulse_open(void **pars)
-{
-       spd_pulse_id_t *pulse_id;
-       int ret;
-
-       pulse_id = (spd_pulse_id_t *) g_malloc(sizeof(spd_pulse_id_t));
-
-       /* Select an Endianness for the initial connection. */
-#if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
-       pulse_id->id.format = SPD_AUDIO_BE;
-#else
-       pulse_id->id.format = SPD_AUDIO_LE;
-#endif
-       pulse_id->pa_simple = NULL;
-       pulse_id->pa_server = (char *)pars[3];
-       pulse_id->pa_min_audio_length = DEFAULT_PA_MIN_AUDIO_LENgTH;
-
-       pulse_id->pa_current_rate = -1;
-       pulse_id->pa_current_bps = -1;
-       pulse_id->pa_current_channels = -1;
-
-       if (!strcmp(pulse_id->pa_server, "default")) {
-               pulse_id->pa_server = NULL;
-       }
-
-       if (pars[4] != NULL && atoi(pars[4]) != 0)
-               pulse_id->pa_min_audio_length = atoi(pars[4]);
-
-       pulse_id->pa_stop_playback = 0;
-
-       ret = _pulse_open(pulse_id, 44100, 1, 2);
-       if (ret) {
-               g_free(pulse_id);
-               pulse_id = NULL;
-       }
-
-       return (AudioID *) pulse_id;
-}
-
-static int pulse_play(AudioID * id, AudioTrack track)
-{
-       int bytes_per_sample;
-       int num_bytes;
-       int outcnt = 0;
-       signed short *output_samples;
-       int i;
-       int error;
-       spd_pulse_id_t *pulse_id = (spd_pulse_id_t *) id;
-
-       if (id == NULL) {
-               return -1;
-       }
-       if (track.samples == NULL || track.num_samples <= 0) {
-               return 0;
-       }
-       MSG("Starting playback\n");
-       /* Choose the correct format */
-       if (track.bits == 16) {
-               bytes_per_sample = 2;
-       } else if (track.bits == 8) {
-               bytes_per_sample = 1;
-       } else {
-               MSG("ERROR: Unsupported sound data format, track.bits = %d\n",
-                   track.bits);
-               return -1;
-       }
-       output_samples = track.samples;
-       num_bytes = track.num_samples * bytes_per_sample;
-
-       /* Check if the current connection has suitable parameters for this 
track */
-       if (pulse_id->pa_current_rate != track.sample_rate
-           || pulse_id->pa_current_bps != track.bits
-           || pulse_id->pa_current_channels != track.num_channels) {
-               MSG("Reopenning connection due to change in track parameters 
sample_rate:%d bps:%d channels:%d\n", track.sample_rate, track.bits, 
track.num_channels);
-               /* Close old connection if any */
-               pulse_connection_close(pulse_id);
-               /* Open a new connection */
-               _pulse_open(pulse_id, track.sample_rate, track.num_channels,
-                           bytes_per_sample);
-               /* Keep track of current connection parameters */
-               pulse_id->pa_current_rate = track.sample_rate;
-               pulse_id->pa_current_bps = track.bits;
-               pulse_id->pa_current_channels = track.num_channels;
-       }
-       MSG("bytes to play: %d, (%f secs)\n", num_bytes,
-           (((float)(num_bytes) / 2) / (float)track.sample_rate));
-       pulse_id->pa_stop_playback = 0;
-       outcnt = 0;
-       i = 0;
-       while ((outcnt < num_bytes) && !pulse_id->pa_stop_playback) {
-               if ((num_bytes - outcnt) > PULSE_SEND_BYTES) {
-                       i = PULSE_SEND_BYTES;
-               } else {
-                       i = (num_bytes - outcnt);
-               }
-               if (pa_simple_write
-                   (pulse_id->pa_simple, ((char *)output_samples) + outcnt, i,
-                    &error) < 0) {
-                       pa_simple_drain(pulse_id->pa_simple, NULL);
-                       pulse_connection_close(pulse_id);
-                       MSG("ERROR: Audio: pulse_play(): %s - closing device - 
re-open it in next run\n", pa_strerror(error));
-                       break;
-               } else {
-                       MSG("Pulse: wrote %u bytes\n", i);
-               }
-               outcnt += i;
-       }
-       return 0;
-}
-
-/* stop the pulse_play() loop */
-static int pulse_stop(AudioID * id)
-{
-       spd_pulse_id_t *pulse_id = (spd_pulse_id_t *) id;
-
-       pulse_id->pa_stop_playback = 1;
-       return 0;
-}
-
-static int pulse_close(AudioID * id)
-{
-       spd_pulse_id_t *pulse_id = (spd_pulse_id_t *) id;
-       pulse_connection_close(pulse_id);
-       g_free(pulse_id);
-       id = NULL;
-
-       return 0;
-}
-
-static int pulse_set_volume(AudioID * id, int volume)
-{
-       return 0;
-}
-
-static void pulse_set_loglevel(int level)
-{
-       if (level) {
-               pulse_log_level = level;
-       }
-}
-
-static char const *pulse_get_playcmd(void)
-{
-       return pulse_play_cmd;
-}
-
-/* Provide the pulse backend. */
-static spd_audio_plugin_t pulse_functions = {
-       "pulse",
-       pulse_open,
-       pulse_play,
-       pulse_stop,
-       pulse_close,
-       pulse_set_volume,
-       pulse_set_loglevel,
-       pulse_get_playcmd
-};
-
-spd_audio_plugin_t *pulse_plugin_get(void)
-{
-       return &pulse_functions;
-}
-
-spd_audio_plugin_t *SPD_AUDIO_PLUGIN_ENTRY(void)
-    __attribute__ ((weak, alias("pulse_plugin_get")));
-- 
1.7.3.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]