speechd-discuss
[Top][All Lists]
Advanced

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

[PATCH 2/2] move src/audio to src/modules/audio


From: William Hubbs
Subject: [PATCH 2/2] move src/audio to src/modules/audio
Date: Fri, 17 Sep 2010 11:09:45 -0500

The audio subsystem is only used in the modules, so the source for it is
being moved into the modules directory to reflect this.
---
 configure.ac                          |    4 +-
 src/Makefile.am                       |    2 +-
 src/audio/Makefile.am                 |   37 --
 src/audio/alsa.c                      |  834 ---------------------------------
 src/audio/libao.c                     |  241 ----------
 src/audio/nas.c                       |  252 ----------
 src/audio/oss.c                       |  505 --------------------
 src/audio/pulse.c                     |  291 ------------
 src/audio/spd_audio.c                 |  263 -----------
 src/audio/spd_audio.h                 |   44 --
 src/audio/spd_audio_plugin.h          |   69 ---
 src/audio/static_plugins.c.in         |   50 --
 src/modules/Makefile.am               |    4 +-
 src/modules/audio/Makefile.am         |   37 ++
 src/modules/audio/alsa.c              |  834 +++++++++++++++++++++++++++++++++
 src/modules/audio/libao.c             |  241 ++++++++++
 src/modules/audio/nas.c               |  252 ++++++++++
 src/modules/audio/oss.c               |  505 ++++++++++++++++++++
 src/modules/audio/pulse.c             |  291 ++++++++++++
 src/modules/audio/spd_audio.c         |  263 +++++++++++
 src/modules/audio/spd_audio.h         |   44 ++
 src/modules/audio/spd_audio_plugin.h  |   69 +++
 src/modules/audio/static_plugins.c.in |   50 ++
 23 files changed, 2592 insertions(+), 2590 deletions(-)
 delete mode 100644 src/audio/Makefile.am
 delete mode 100644 src/audio/alsa.c
 delete mode 100644 src/audio/libao.c
 delete mode 100644 src/audio/nas.c
 delete mode 100644 src/audio/oss.c
 delete mode 100644 src/audio/pulse.c
 delete mode 100644 src/audio/spd_audio.c
 delete mode 100644 src/audio/spd_audio.h
 delete mode 100644 src/audio/spd_audio_plugin.h
 delete mode 100644 src/audio/static_plugins.c.in
 create mode 100644 src/modules/audio/Makefile.am
 create mode 100644 src/modules/audio/alsa.c
 create mode 100644 src/modules/audio/libao.c
 create mode 100644 src/modules/audio/nas.c
 create mode 100644 src/modules/audio/oss.c
 create mode 100644 src/modules/audio/pulse.c
 create mode 100644 src/modules/audio/spd_audio.c
 create mode 100644 src/modules/audio/spd_audio.h
 create mode 100644 src/modules/audio/spd_audio_plugin.h
 create mode 100644 src/modules/audio/static_plugins.c.in

diff --git a/configure.ac b/configure.ac
index 61b00c4..2441474 100644
--- a/configure.ac
+++ b/configure.ac
@@ -431,13 +431,13 @@ AC_CONFIG_FILES([Makefile
        src/api/python/Makefile
        src/api/python/speechd/Makefile
        src/api/python/speechd_config/Makefile
-       src/audio/Makefile
-       src/audio/static_plugins.c
        src/clients/Makefile
        src/clients/say/Makefile
        src/clients/spdsend/Makefile
        src/common/Makefile
        src/modules/Makefile
+       src/modules/audio/Makefile
+       src/modules/audio/static_plugins.c
        src/server/Makefile
        src/tests/Makefile])
 AC_OUTPUT
diff --git a/src/Makefile.am b/src/Makefile.am
index 81d0690..f2da76d 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 audio modules api clients tests
+SUBDIRS=common server modules api clients tests
 
diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am
deleted file mode 100644
index 0d67162..0000000
--- a/src/audio/Makefile.am
+++ /dev/null
@@ -1,37 +0,0 @@
-
-localedir = $(datadir)/locale
-inc_local = "-I$(top_srcdir)/include/"
-
-include_HEADERS = spd_audio_plugin.h
-
-am_cflags = -DLOCALEDIR=\"$(localedir)\" $(inc_local)
-
-spdlib_LTLIBRARIES = libsdaudio.la
-libsdaudio_la_CPPFLAGS = $(GLIB_CFLAGS)
-libsdaudio_la_SOURCES = spd_audio.c spd_audio.h spd_audio_plugin.h 
static_plugins.c
-
-if nas_support
-libsdaudio_la_SOURCES += nas.c
-endif
-
-if pulse_support
-libsdaudio_la_SOURCES += pulse.c
-endif
-
-if alsa_support
-libsdaudio_la_SOURCES += alsa.c
-endif
-
-if libao_support
-libsdaudio_la_SOURCES += libao.c
-endif
-
-if oss_support
-libsdaudio_la_SOURCES += oss.c
-endif
-
-EXTRA_DIST = alsa.c libao.c oss.c nas.c pulse.c static_plugins.c.in
-
-AM_CFLAGS = -DLOCALEDIR=\"$(localedir)\" $(inc_local)
-libsdaudio_la_LDFLAGS = -version-info 
@LIB_SDAUDIO_CURRENT@:@LIB_SDAUDIO_REVISION@:@LIB_SDAUDIO_AGE@ -lpthread 
$(SPD_AUDIO_LIBS)
-libsdaudio_la_LIBADD = $(GLIB_LIBS)
diff --git a/src/audio/alsa.c b/src/audio/alsa.c
deleted file mode 100644
index f381ccf..0000000
--- a/src/audio/alsa.c
+++ /dev/null
@@ -1,834 +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.*/
-
-#include <stdio.h>
-#include <sys/time.h>
-#include <time.h>
-#include <pthread.h>
-
-#include <alsa/asoundlib.h>
-
-#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 = 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); \
-     xfree(tstr); \
-  }
-
-#define ERR(arg...) \
- { \
-     time_t t; \
-     struct timeval tv; \
-     char *tstr; \
-     t = time(NULL); \
-     tstr = 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); \
-     xfree(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);
-
-    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 *) 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 = strdup(pars[1]);
-    
-    ret = _alsa_open(alsa_id);
-    if (ret){
-       ERR("Cannot initialize Alsa device '%s': Can't open.", 
alsa_id->alsa_device_name);
-    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.");
-
-    free (alsa_id->alsa_device_name);
-    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()\
-    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 = 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*) 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)
-       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]);
-
-    xfree(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;}
-#undef MSG
-#undef ERR
diff --git a/src/audio/libao.c b/src/audio/libao.c
deleted file mode 100644
index 0b4734c..0000000
--- a/src/audio/libao.c
+++ /dev/null
@@ -1,241 +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.
- *
- */
-
-#include <sys/time.h>
-#include <time.h>
-#include <string.h>
-#include <ao/ao.h>
-
-#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 = 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); \
-     xfree(tstr); \
-  }
-
-#define ERR(arg...) \
- { \
-     time_t t; \
-     struct timeval tv; \
-     char *tstr; \
-     t = time(NULL); \
-     tstr = 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); \
-     xfree(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 *) 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 ();
-
-  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;}
-
-#undef MSG
-#undef ERR
diff --git a/src/audio/nas.c b/src/audio/nas.c
deleted file mode 100644
index 8910c9b..0000000
--- a/src/audio/nas.c
+++ /dev/null
@@ -1,252 +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 $
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <audio/audiolib.h>
-#include <audio/soundlib.h>
-
-#include <pthread.h>
-
-#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 *) 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);
-
-    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;}
\ No newline at end of file
diff --git a/src/audio/oss.c b/src/audio/oss.c
deleted file mode 100644
index 4254b60..0000000
--- a/src/audio/oss.c
+++ /dev/null
@@ -1,505 +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 $
- */
-
-#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 <sys/soundcard.h>
-
-#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 = 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); \
-     xfree(tstr); \
-  }
-
-#define ERR(arg...) \
- { \
-     time_t t; \
-     struct timeval tv; \
-     char *tstr; \
-     t = time(NULL); \
-     tstr = 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); \
-     xfree(tstr); \
-  }
-
-static int oss_log_level;
-static char const * oss_play_cmd="play";
-
-void
-xfree(void* p)
-{
-    if (p != NULL) free(p);
-}
-
-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 *) malloc(sizeof(spd_oss_id_t));
-
-    oss_id->device_name = (char*) 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) {
-        free (oss_id->device_name);
-        free (oss_id);
-        return NULL;
-    }
-    ret = _oss_close(oss_id);
-    if (ret) {
-        free (oss_id->device_name);
-        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*) 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) 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. */
-
-    free(oss_id->device_name);
-    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;}
-#undef MSG
-#undef ERR
diff --git a/src/audio/pulse.c b/src/audio/pulse.c
deleted file mode 100644
index f4d4c12..0000000
--- a/src/audio/pulse.c
+++ /dev/null
@@ -1,291 +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.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <time.h>
-#include <string.h>
-#include <stdarg.h>
-
-#include <pulse/simple.h>
-#include <pulse/error.h>
-
-#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 *) 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) {
-        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);
-    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;}
diff --git a/src/audio/spd_audio.c b/src/audio/spd_audio.c
deleted file mode 100644
index 9cf0a27..0000000
--- a/src/audio/spd_audio.c
+++ /dev/null
@@ -1,263 +0,0 @@
-
-/*
- * spd_audio.c -- Spd Audio Output 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: spd_audio.c,v 1.21 2008-06-09 10:29:12 hanke Exp $
- */
-
-/* 
- * spd_audio is a simple realtime audio output library with the capability of
- * playing 8 or 16 bit data, immediate stop and synchronization. This library
- * currently provides OSS, NAS, ALSA and PulseAudio backend. The available 
backends are
- * specified at compile-time using the directives WITH_OSS, WITH_NAS, 
WITH_ALSA, 
- * WITH_PULSE, WITH_LIBAO but the user program is allowed to switch between 
them at run-time.
- */
-
-#include "spd_audio.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <pthread.h>
-
-#include <glib.h>
-
-static int spd_audio_log_level;
-extern  spd_audio_plugin_t * spd_audio_static_plugin_get (char * name);
-
-/* Open the audio device.
-
-   Arguments:
-   type -- The requested device. Currently AudioOSS or AudioNAS.
-   pars -- and array of pointers to parameters to pass to
-           the device backend, terminated by a NULL pointer.
-           See the source/documentation of each specific backend.
-   error -- a pointer to the string where error description is
-           stored in case of failure (returned AudioID == NULL).
-           Otherwise will contain NULL.
-
-   Return value:
-   Newly allocated AudioID structure that can be passed to
-   all other spd_audio functions, or NULL in case of failure.
-
-*/
-AudioID*
-spd_audio_open(char *name, void **pars, char **error)
-{
-    AudioID *id;
-    struct spd_audio_plugin *function;
-    spd_audio_plugin_t const *p;
-
-    /* check whether static plugin is available */
-    p = spd_audio_static_plugin_get (name);
-    if (p == NULL || p->name == NULL) {
-        *error = (char*)g_strdup_printf("Unknown plugin %s ", name);
-        return (AudioID *)NULL;
-    }
-
-    id = p->open (pars);
-    if (id == NULL) {
-        *error = (char*) g_strdup_printf("Couldn't open %s plugin", name);
-        return (AudioID *)NULL;
-    }
-
-    id->function = p;
-#if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
-    id->format = SPD_AUDIO_BE;
-#else
-    id->format = SPD_AUDIO_LE;
-#endif
-
-    *error = NULL;
-
-    return id;
-}
-
-/* Play a track on the audio device (blocking).
-
-   Arguments:
-   id -- the AudioID* of the device returned by spd_audio_open
-   track -- a track to play (see spd_audio.h)
-
-   Return value:
-   0 if everything is ok, a non-zero value in case of failure.
-   See the particular backend documentation or source for the
-   meaning of these non-zero values.
-
-   Comment:
-   spd_audio_play() is a blocking function. It returns exactly
-   when the given track stopped playing. However, it's possible
-   to safely interrupt it using spd_audio_stop() described bellow.
-   (spd_audio_stop() needs to be called from another thread, obviously.)
-
-*/
-int
-spd_audio_play(AudioID *id, AudioTrack track, AudioFormat format)
-{
-    int ret;
-
-    if (id && id->function->play){
-        /* Only perform byte swapping if the driver in use has given us audio 
in
-          an endian format other than what the running CPU supports. */
-        if (format != id->format){
-                unsigned char *out_ptr, *out_end, c;
-                out_ptr = (unsigned char *) track.samples;
-                out_end = out_ptr + track.num_samples*2 * track.num_channels;
-                while(out_ptr < out_end){
-                    c = out_ptr[0];
-                    out_ptr[0] = out_ptr[1];
-                    out_ptr[1] = c;
-                    out_ptr += 2;
-                }
-        }
-       ret = id->function->play(id, track);
-    }
-    else{
-       fprintf(stderr, "Play not supported on this device\n");
-       return -1;
-    }
-
-    return ret;
-}
-
-/* Stop playing the current track on device id
-
-Arguments:
-   id -- the AudioID* of the device returned by spd_audio_open
-
-Return value:
-   0 if everything is ok, a non-zero value in case of failure.
-   See the particular backend documentation or source for the
-   meaning of these non-zero values.
-
-Comment:
-   spd_audio_stop() safely interrupts spd_audio_play() when called
-   from another thread. It shouldn't cause any clicks or unwanted
-   effects in the sound output.
-
-   It's safe to call spd_audio_stop() even if the device isn't playing
-   any track. In that case, it does nothing. However, there is a danger
-   when using spd_audio_stop(). Since you must obviously do it from
-   another thread than where spd_audio_play is running, you must make
-   yourself sure that the device is still open and the id you pass it
-   is valid and will be valid until spd_audio_stop returns. In other words,
-   you should use some mutex or other synchronization device to be sure
-   spd_audio_close isn't called before or during spd_audio_stop execution.
-*/
-
-int
-spd_audio_stop(AudioID *id)
-{
-    int ret;
-    if (id && id->function->stop){
-       ret = id->function->stop(id);
-    }
-    else{
-       fprintf(stderr, "Stop not supported on this device\n");
-       return -1;
-    }
-    return ret;
-}
-
-/* Close the audio device id
-
-Arguments:
-   id -- the AudioID* of the device returned by spd_audio_open
-
-Return value:
-   0 if everything is ok, a non-zero value in case of failure.
-
-Comments:
-
-   Please make sure no other spd_audio function with this device id
-   is running in another threads. See spd_audio_stop() for detailed
-   description of possible problems.
-*/
-int
-spd_audio_close(AudioID *id)
-{
-    int ret = 0;
-    if (id && id->function->close){
-       return (id->function->close(id));
-    }
-    return -1;
-}
-
-/* Set volume for playing tracks on the device id
-
-Arguments:
-   id -- the AudioID* of the device returned by spd_audio_open
-   volume -- a value in the range <-100:100> where -100 means the
-             least volume (probably silence), 0 the default volume
-            and +100 the highest volume possible to make on that
-            device for a single flow (i.e. not using mixer).
-
-Return value:
-   0 if everything is ok, a non-zero value in case of failure.
-   See the particular backend documentation or source for the
-   meaning of these non-zero values.
-
-Comments:
-
-   In case of /dev/dsp, it's not possible to set volume for
-   the particular flow. For that reason, the value 0 means
-   the volume the track was recorded on and each smaller value
-   means less volume (since this works by deviding the samples
-   in the track by a constant).
-*/
-int
-spd_audio_set_volume(AudioID *id, int volume)
-{
-    if ((volume > 100) || (volume < -100)){
-       fprintf(stderr, "Requested volume out of range");
-       return -1;
-    }
-    if(id == NULL){
-        fprintf(stderr, "audio id is NULL in spd_audio_set_volume\n");
-        return -1;
-    }
-    id->volume = volume;
-    return 0;
-}
-
-void
-spd_audio_set_loglevel(AudioID *id, int level)
-{
-    if (level){
-        spd_audio_log_level = level;
-       if (id != 0 && id->function != 0)
-           id->function->set_loglevel(level);
-    }
-}
-
-char const *
-spd_audio_get_playcmd(AudioID *id)
-{
-       if (id != 0 && id->function != 0) {
-           return id->function->get_playcmd();
-    }
-    return NULL;
-}
diff --git a/src/audio/spd_audio.h b/src/audio/spd_audio.h
deleted file mode 100644
index 90aa95f..0000000
--- a/src/audio/spd_audio.h
+++ /dev/null
@@ -1,44 +0,0 @@
-
-/*
- * spd_audio.h -- The SPD Audio Library Header
- *
- * Copyright (C) 2004 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: spd_audio.h,v 1.21 2008-10-15 17:28:17 hanke Exp $
- */
-
-#ifndef __SPD_AUDIO_H
-#define __SPD_AUDIO_H
-
-#include "spd_audio_plugin.h"
-
-AudioID* spd_audio_open(char *name, void **pars, char **error);
-
-int spd_audio_play(AudioID *id, AudioTrack track, AudioFormat format);
-
-int spd_audio_stop(AudioID *id);
-
-int spd_audio_close(AudioID *id);
-
-int spd_audio_set_volume(AudioID *id, int volume);
-
-void spd_audio_set_loglevel(AudioID *id, int level);
-
-char const *  spd_audio_get_playcmd (AudioID *id);
-
-#endif /* ifndef #__SPD_AUDIO_H */
diff --git a/src/audio/spd_audio_plugin.h b/src/audio/spd_audio_plugin.h
deleted file mode 100644
index 6fae68a..0000000
--- a/src/audio/spd_audio_plugin.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * spd_audio_plugin.h -- The SPD Audio Plugin Header
- *
- * Copyright (C) 2004 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.
- *
- */
-
-#ifndef __SPD_AUDIO_PLUGIN_H
-#define __SPD_AUDIO_PLUGIN_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum{SPD_AUDIO_LE, SPD_AUDIO_BE} AudioFormat;
-
-typedef struct{
-    int bits;
-    int num_channels;
-    int sample_rate;
-
-    int num_samples;
-    signed short *samples;
-}AudioTrack;
-
-struct spd_audio_plugin;
-
-typedef struct{
-
-    int volume;
-    AudioFormat format;
-
-    struct spd_audio_plugin const *function;
-    void *private_data;
-
-    int working;
-}AudioID;
-
-typedef struct spd_audio_plugin {
-    const char * name;
-    AudioID * (* open)  (void** pars);
-    int   (* play)  (AudioID *id, AudioTrack track);
-    int   (* stop)  (AudioID *id);
-    int   (* close) (AudioID *id);
-    int   (* set_volume) (AudioID *id, int);
-    void  (* set_loglevel) (int level);
-    char const *  (* get_playcmd) (void);
-} spd_audio_plugin_t;
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* ifndef #__SPD_AUDIO_PLUGIN_H */
diff --git a/src/audio/static_plugins.c.in b/src/audio/static_plugins.c.in
deleted file mode 100644
index eca2983..0000000
--- a/src/audio/static_plugins.c.in
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * static_plugins.c -- spd audio library static plugins
- *
- * Copyright (C) 2010 Andrei Kholodnyi
- *
- * 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.
- *
- */
-
-#include <string.h>
-
-#include "spd_audio_plugin.h"
-
- at STATIC_AUDIO_PLUGINS_EXTERN@
-
-static spd_audio_plugin_t const * (* spd_audio_static_plugins[]) (void) =
-{
-       @STATIC_AUDIO_PLUGINS_GET@
-       0
-};
-
-spd_audio_plugin_t const * spd_audio_static_plugin_get (char * name)
-{
-    int i;
-    spd_audio_plugin_t const * plugin;
-
-    for (i=0; spd_audio_static_plugins[i]; i++)
-    {
-        plugin = spd_audio_static_plugins[i]();
-        if (plugin != NULL && 0 == strcmp(plugin->name, name))
-        {
-            return plugin;
-        }
-    }
-
-    return (spd_audio_plugin_t *)NULL;
-}
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
index 1979084..06e33bd 100644
--- a/src/modules/Makefile.am
+++ b/src/modules/Makefile.am
@@ -4,9 +4,11 @@ inc_local = "-I$(top_srcdir)/include/"
 SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
 SNDFILE_LIBS = @SNDFILE_LIBS@
 
+SUBDIRS = audio
+
 EXTRA_DIST = module_main.c module_utils_addvoice.c festival_client.c 
festival_client.h ivona_client.c dummy.c dummy-message.wav
 
-AM_CFLAGS = @ERROR_CFLAGS@ -DLOCALEDIR=\"$(localedir)\" 
-DDATADIR=\"$(snddatadir)\" $(inc_local) $(DOTCONF_CFLAGS) $(GLIB_CFLAGS) 
$(GTHREAD_CFLAGS) -L$(top_builddir)/src/audio -I$(top_srcdir)/src/audio 
$(ibmtts_include) @SNDFILE_CFLAGS@ -D_GNU_SOURCE
+AM_CFLAGS = @ERROR_CFLAGS@ -DLOCALEDIR=\"$(localedir)\" 
-DDATADIR=\"$(snddatadir)\" $(inc_local) $(DOTCONF_CFLAGS) $(GLIB_CFLAGS) 
$(GTHREAD_CFLAGS) -L$(top_builddir)/src/modules/audio 
-I$(top_srcdir)/src/modules/audio $(ibmtts_include) @SNDFILE_CFLAGS@ 
-D_GNU_SOURCE
 
 modulebin_PROGRAMS = sd_dummy sd_generic sd_festival sd_cicero
 
diff --git a/src/modules/audio/Makefile.am b/src/modules/audio/Makefile.am
new file mode 100644
index 0000000..0d67162
--- /dev/null
+++ b/src/modules/audio/Makefile.am
@@ -0,0 +1,37 @@
+
+localedir = $(datadir)/locale
+inc_local = "-I$(top_srcdir)/include/"
+
+include_HEADERS = spd_audio_plugin.h
+
+am_cflags = -DLOCALEDIR=\"$(localedir)\" $(inc_local)
+
+spdlib_LTLIBRARIES = libsdaudio.la
+libsdaudio_la_CPPFLAGS = $(GLIB_CFLAGS)
+libsdaudio_la_SOURCES = spd_audio.c spd_audio.h spd_audio_plugin.h 
static_plugins.c
+
+if nas_support
+libsdaudio_la_SOURCES += nas.c
+endif
+
+if pulse_support
+libsdaudio_la_SOURCES += pulse.c
+endif
+
+if alsa_support
+libsdaudio_la_SOURCES += alsa.c
+endif
+
+if libao_support
+libsdaudio_la_SOURCES += libao.c
+endif
+
+if oss_support
+libsdaudio_la_SOURCES += oss.c
+endif
+
+EXTRA_DIST = alsa.c libao.c oss.c nas.c pulse.c static_plugins.c.in
+
+AM_CFLAGS = -DLOCALEDIR=\"$(localedir)\" $(inc_local)
+libsdaudio_la_LDFLAGS = -version-info 
@LIB_SDAUDIO_CURRENT@:@LIB_SDAUDIO_REVISION@:@LIB_SDAUDIO_AGE@ -lpthread 
$(SPD_AUDIO_LIBS)
+libsdaudio_la_LIBADD = $(GLIB_LIBS)
diff --git a/src/modules/audio/alsa.c b/src/modules/audio/alsa.c
new file mode 100644
index 0000000..f381ccf
--- /dev/null
+++ b/src/modules/audio/alsa.c
@@ -0,0 +1,834 @@
+
+/*
+ * 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.*/
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+#include <pthread.h>
+
+#include <alsa/asoundlib.h>
+
+#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 = 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); \
+     xfree(tstr); \
+  }
+
+#define ERR(arg...) \
+ { \
+     time_t t; \
+     struct timeval tv; \
+     char *tstr; \
+     t = time(NULL); \
+     tstr = 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); \
+     xfree(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);
+
+    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 *) 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 = strdup(pars[1]);
+    
+    ret = _alsa_open(alsa_id);
+    if (ret){
+       ERR("Cannot initialize Alsa device '%s': Can't open.", 
alsa_id->alsa_device_name);
+    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.");
+
+    free (alsa_id->alsa_device_name);
+    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()\
+    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 = 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*) 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)
+       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]);
+
+    xfree(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;}
+#undef MSG
+#undef ERR
diff --git a/src/modules/audio/libao.c b/src/modules/audio/libao.c
new file mode 100644
index 0000000..0b4734c
--- /dev/null
+++ b/src/modules/audio/libao.c
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ *
+ */
+
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+#include <ao/ao.h>
+
+#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 = 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); \
+     xfree(tstr); \
+  }
+
+#define ERR(arg...) \
+ { \
+     time_t t; \
+     struct timeval tv; \
+     char *tstr; \
+     t = time(NULL); \
+     tstr = 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); \
+     xfree(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 *) 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 ();
+
+  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;}
+
+#undef MSG
+#undef ERR
diff --git a/src/modules/audio/nas.c b/src/modules/audio/nas.c
new file mode 100644
index 0000000..8910c9b
--- /dev/null
+++ b/src/modules/audio/nas.c
@@ -0,0 +1,252 @@
+/*
+ * 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 $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <audio/audiolib.h>
+#include <audio/soundlib.h>
+
+#include <pthread.h>
+
+#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 *) 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);
+
+    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;}
\ No newline at end of file
diff --git a/src/modules/audio/oss.c b/src/modules/audio/oss.c
new file mode 100644
index 0000000..4254b60
--- /dev/null
+++ b/src/modules/audio/oss.c
@@ -0,0 +1,505 @@
+
+/*
+ * 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 $
+ */
+
+#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 <sys/soundcard.h>
+
+#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 = 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); \
+     xfree(tstr); \
+  }
+
+#define ERR(arg...) \
+ { \
+     time_t t; \
+     struct timeval tv; \
+     char *tstr; \
+     t = time(NULL); \
+     tstr = 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); \
+     xfree(tstr); \
+  }
+
+static int oss_log_level;
+static char const * oss_play_cmd="play";
+
+void
+xfree(void* p)
+{
+    if (p != NULL) free(p);
+}
+
+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 *) malloc(sizeof(spd_oss_id_t));
+
+    oss_id->device_name = (char*) 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) {
+        free (oss_id->device_name);
+        free (oss_id);
+        return NULL;
+    }
+    ret = _oss_close(oss_id);
+    if (ret) {
+        free (oss_id->device_name);
+        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*) 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) 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. */
+
+    free(oss_id->device_name);
+    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;}
+#undef MSG
+#undef ERR
diff --git a/src/modules/audio/pulse.c b/src/modules/audio/pulse.c
new file mode 100644
index 0000000..f4d4c12
--- /dev/null
+++ b/src/modules/audio/pulse.c
@@ -0,0 +1,291 @@
+
+/*
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <pulse/simple.h>
+#include <pulse/error.h>
+
+#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 *) 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) {
+        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);
+    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;}
diff --git a/src/modules/audio/spd_audio.c b/src/modules/audio/spd_audio.c
new file mode 100644
index 0000000..9cf0a27
--- /dev/null
+++ b/src/modules/audio/spd_audio.c
@@ -0,0 +1,263 @@
+
+/*
+ * spd_audio.c -- Spd Audio Output 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: spd_audio.c,v 1.21 2008-06-09 10:29:12 hanke Exp $
+ */
+
+/* 
+ * spd_audio is a simple realtime audio output library with the capability of
+ * playing 8 or 16 bit data, immediate stop and synchronization. This library
+ * currently provides OSS, NAS, ALSA and PulseAudio backend. The available 
backends are
+ * specified at compile-time using the directives WITH_OSS, WITH_NAS, 
WITH_ALSA, 
+ * WITH_PULSE, WITH_LIBAO but the user program is allowed to switch between 
them at run-time.
+ */
+
+#include "spd_audio.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <pthread.h>
+
+#include <glib.h>
+
+static int spd_audio_log_level;
+extern  spd_audio_plugin_t * spd_audio_static_plugin_get (char * name);
+
+/* Open the audio device.
+
+   Arguments:
+   type -- The requested device. Currently AudioOSS or AudioNAS.
+   pars -- and array of pointers to parameters to pass to
+           the device backend, terminated by a NULL pointer.
+           See the source/documentation of each specific backend.
+   error -- a pointer to the string where error description is
+           stored in case of failure (returned AudioID == NULL).
+           Otherwise will contain NULL.
+
+   Return value:
+   Newly allocated AudioID structure that can be passed to
+   all other spd_audio functions, or NULL in case of failure.
+
+*/
+AudioID*
+spd_audio_open(char *name, void **pars, char **error)
+{
+    AudioID *id;
+    struct spd_audio_plugin *function;
+    spd_audio_plugin_t const *p;
+
+    /* check whether static plugin is available */
+    p = spd_audio_static_plugin_get (name);
+    if (p == NULL || p->name == NULL) {
+        *error = (char*)g_strdup_printf("Unknown plugin %s ", name);
+        return (AudioID *)NULL;
+    }
+
+    id = p->open (pars);
+    if (id == NULL) {
+        *error = (char*) g_strdup_printf("Couldn't open %s plugin", name);
+        return (AudioID *)NULL;
+    }
+
+    id->function = p;
+#if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
+    id->format = SPD_AUDIO_BE;
+#else
+    id->format = SPD_AUDIO_LE;
+#endif
+
+    *error = NULL;
+
+    return id;
+}
+
+/* Play a track on the audio device (blocking).
+
+   Arguments:
+   id -- the AudioID* of the device returned by spd_audio_open
+   track -- a track to play (see spd_audio.h)
+
+   Return value:
+   0 if everything is ok, a non-zero value in case of failure.
+   See the particular backend documentation or source for the
+   meaning of these non-zero values.
+
+   Comment:
+   spd_audio_play() is a blocking function. It returns exactly
+   when the given track stopped playing. However, it's possible
+   to safely interrupt it using spd_audio_stop() described bellow.
+   (spd_audio_stop() needs to be called from another thread, obviously.)
+
+*/
+int
+spd_audio_play(AudioID *id, AudioTrack track, AudioFormat format)
+{
+    int ret;
+
+    if (id && id->function->play){
+        /* Only perform byte swapping if the driver in use has given us audio 
in
+          an endian format other than what the running CPU supports. */
+        if (format != id->format){
+                unsigned char *out_ptr, *out_end, c;
+                out_ptr = (unsigned char *) track.samples;
+                out_end = out_ptr + track.num_samples*2 * track.num_channels;
+                while(out_ptr < out_end){
+                    c = out_ptr[0];
+                    out_ptr[0] = out_ptr[1];
+                    out_ptr[1] = c;
+                    out_ptr += 2;
+                }
+        }
+       ret = id->function->play(id, track);
+    }
+    else{
+       fprintf(stderr, "Play not supported on this device\n");
+       return -1;
+    }
+
+    return ret;
+}
+
+/* Stop playing the current track on device id
+
+Arguments:
+   id -- the AudioID* of the device returned by spd_audio_open
+
+Return value:
+   0 if everything is ok, a non-zero value in case of failure.
+   See the particular backend documentation or source for the
+   meaning of these non-zero values.
+
+Comment:
+   spd_audio_stop() safely interrupts spd_audio_play() when called
+   from another thread. It shouldn't cause any clicks or unwanted
+   effects in the sound output.
+
+   It's safe to call spd_audio_stop() even if the device isn't playing
+   any track. In that case, it does nothing. However, there is a danger
+   when using spd_audio_stop(). Since you must obviously do it from
+   another thread than where spd_audio_play is running, you must make
+   yourself sure that the device is still open and the id you pass it
+   is valid and will be valid until spd_audio_stop returns. In other words,
+   you should use some mutex or other synchronization device to be sure
+   spd_audio_close isn't called before or during spd_audio_stop execution.
+*/
+
+int
+spd_audio_stop(AudioID *id)
+{
+    int ret;
+    if (id && id->function->stop){
+       ret = id->function->stop(id);
+    }
+    else{
+       fprintf(stderr, "Stop not supported on this device\n");
+       return -1;
+    }
+    return ret;
+}
+
+/* Close the audio device id
+
+Arguments:
+   id -- the AudioID* of the device returned by spd_audio_open
+
+Return value:
+   0 if everything is ok, a non-zero value in case of failure.
+
+Comments:
+
+   Please make sure no other spd_audio function with this device id
+   is running in another threads. See spd_audio_stop() for detailed
+   description of possible problems.
+*/
+int
+spd_audio_close(AudioID *id)
+{
+    int ret = 0;
+    if (id && id->function->close){
+       return (id->function->close(id));
+    }
+    return -1;
+}
+
+/* Set volume for playing tracks on the device id
+
+Arguments:
+   id -- the AudioID* of the device returned by spd_audio_open
+   volume -- a value in the range <-100:100> where -100 means the
+             least volume (probably silence), 0 the default volume
+            and +100 the highest volume possible to make on that
+            device for a single flow (i.e. not using mixer).
+
+Return value:
+   0 if everything is ok, a non-zero value in case of failure.
+   See the particular backend documentation or source for the
+   meaning of these non-zero values.
+
+Comments:
+
+   In case of /dev/dsp, it's not possible to set volume for
+   the particular flow. For that reason, the value 0 means
+   the volume the track was recorded on and each smaller value
+   means less volume (since this works by deviding the samples
+   in the track by a constant).
+*/
+int
+spd_audio_set_volume(AudioID *id, int volume)
+{
+    if ((volume > 100) || (volume < -100)){
+       fprintf(stderr, "Requested volume out of range");
+       return -1;
+    }
+    if(id == NULL){
+        fprintf(stderr, "audio id is NULL in spd_audio_set_volume\n");
+        return -1;
+    }
+    id->volume = volume;
+    return 0;
+}
+
+void
+spd_audio_set_loglevel(AudioID *id, int level)
+{
+    if (level){
+        spd_audio_log_level = level;
+       if (id != 0 && id->function != 0)
+           id->function->set_loglevel(level);
+    }
+}
+
+char const *
+spd_audio_get_playcmd(AudioID *id)
+{
+       if (id != 0 && id->function != 0) {
+           return id->function->get_playcmd();
+    }
+    return NULL;
+}
diff --git a/src/modules/audio/spd_audio.h b/src/modules/audio/spd_audio.h
new file mode 100644
index 0000000..90aa95f
--- /dev/null
+++ b/src/modules/audio/spd_audio.h
@@ -0,0 +1,44 @@
+
+/*
+ * spd_audio.h -- The SPD Audio Library Header
+ *
+ * Copyright (C) 2004 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: spd_audio.h,v 1.21 2008-10-15 17:28:17 hanke Exp $
+ */
+
+#ifndef __SPD_AUDIO_H
+#define __SPD_AUDIO_H
+
+#include "spd_audio_plugin.h"
+
+AudioID* spd_audio_open(char *name, void **pars, char **error);
+
+int spd_audio_play(AudioID *id, AudioTrack track, AudioFormat format);
+
+int spd_audio_stop(AudioID *id);
+
+int spd_audio_close(AudioID *id);
+
+int spd_audio_set_volume(AudioID *id, int volume);
+
+void spd_audio_set_loglevel(AudioID *id, int level);
+
+char const *  spd_audio_get_playcmd (AudioID *id);
+
+#endif /* ifndef #__SPD_AUDIO_H */
diff --git a/src/modules/audio/spd_audio_plugin.h 
b/src/modules/audio/spd_audio_plugin.h
new file mode 100644
index 0000000..6fae68a
--- /dev/null
+++ b/src/modules/audio/spd_audio_plugin.h
@@ -0,0 +1,69 @@
+/*
+ * spd_audio_plugin.h -- The SPD Audio Plugin Header
+ *
+ * Copyright (C) 2004 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.
+ *
+ */
+
+#ifndef __SPD_AUDIO_PLUGIN_H
+#define __SPD_AUDIO_PLUGIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum{SPD_AUDIO_LE, SPD_AUDIO_BE} AudioFormat;
+
+typedef struct{
+    int bits;
+    int num_channels;
+    int sample_rate;
+
+    int num_samples;
+    signed short *samples;
+}AudioTrack;
+
+struct spd_audio_plugin;
+
+typedef struct{
+
+    int volume;
+    AudioFormat format;
+
+    struct spd_audio_plugin const *function;
+    void *private_data;
+
+    int working;
+}AudioID;
+
+typedef struct spd_audio_plugin {
+    const char * name;
+    AudioID * (* open)  (void** pars);
+    int   (* play)  (AudioID *id, AudioTrack track);
+    int   (* stop)  (AudioID *id);
+    int   (* close) (AudioID *id);
+    int   (* set_volume) (AudioID *id, int);
+    void  (* set_loglevel) (int level);
+    char const *  (* get_playcmd) (void);
+} spd_audio_plugin_t;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* ifndef #__SPD_AUDIO_PLUGIN_H */
diff --git a/src/modules/audio/static_plugins.c.in 
b/src/modules/audio/static_plugins.c.in
new file mode 100644
index 0000000..eca2983
--- /dev/null
+++ b/src/modules/audio/static_plugins.c.in
@@ -0,0 +1,50 @@
+/*
+ * static_plugins.c -- spd audio library static plugins
+ *
+ * Copyright (C) 2010 Andrei Kholodnyi
+ *
+ * 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.
+ *
+ */
+
+#include <string.h>
+
+#include "spd_audio_plugin.h"
+
+ at STATIC_AUDIO_PLUGINS_EXTERN@
+
+static spd_audio_plugin_t const * (* spd_audio_static_plugins[]) (void) =
+{
+       @STATIC_AUDIO_PLUGINS_GET@
+       0
+};
+
+spd_audio_plugin_t const * spd_audio_static_plugin_get (char * name)
+{
+    int i;
+    spd_audio_plugin_t const * plugin;
+
+    for (i=0; spd_audio_static_plugins[i]; i++)
+    {
+        plugin = spd_audio_static_plugins[i]();
+        if (plugin != NULL && 0 == strcmp(plugin->name, name))
+        {
+            return plugin;
+        }
+    }
+
+    return (spd_audio_plugin_t *)NULL;
+}
-- 
1.7.2.2




reply via email to

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