speechd-discuss
[Top][All Lists]
Advanced

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

WIP audio in server


From: Trevor Saunders
Subject: WIP audio in server
Date: Mon, 17 Aug 2015 15:30:33 -0400

On Thu, Aug 13, 2015 at 05:28:00PM -0600, Jeremy Whiting wrote:
> Trevor,
> 
> On Thu, Aug 13, 2015 at 4:43 PM, Trevor Saunders <tbsaunde at tbsaunde.org> 
> wrote:
> > On Mon, Aug 10, 2015 at 08:21:00PM -0600, Jeremy Whiting wrote:
> >> Ok, last patch of the day. Undone items:
> >>
> >> 1. Audio socket cleanup. Not sure what needs to be done here. Should
> >> the socket files get deleted during shutdown, etc.
> >
> > is there some reason to use a socket instead of just pipe(2) then you
> > wouldn't need to deal with this at all?
> 
> I hadn't thought of that. I thought a unix socket would be easier
> since in the near (maybe) future we will have the server spawn an
> output module for each client when it is requested. I'm not sure if
> using a pipe would make that easier or harder though.

If you deal with audio in the main server process I don't think it would
be any harder.  The one thing I don't see how to handle is changing
audio method while modules are running, but I'm not sure if that is or
should be supported.

> >> 2. Stopping audio (probably can be done from parse_stop in parse.c
> >> 3. Play command use which is only used in generic.c
> >
> > iirc a couple other modules ivona and festival I think do there own
> > thing where the synth is a separate process and does its own audio I
> > think.  I don't really have any great ideas here.
> 
> Actually both are sending audio through module_tts_output which with
> this patch sends it through the socket to the server to play.

oh heh maybe I should have read the patch and stuff before talking.

> >
> > Have you considered using a process separate from the main server for
> > audio output?  I guess its not all that complicated, but it might allow
> > us to sandbox a bit more of speech dispatcher.
> 
> I haven't considered that. I'd rather not reinvent pulseaudio for our
> own purposes if we can avoid it though.

I'm not sure I'd call it reinventing Pulse, but it may be the case
outputting audio is not complex enough to be worth it.

Trev

> 
> BR,
> Jeremy
> 
> >
> > Trev
> >
> >>
> >> BR,
> >> Jeremy
> >>
> >> On Mon, Aug 10, 2015 at 7:05 PM, Jeremy Whiting <jpwhiting at kde.org> 
> >> wrote:
> >> > Ok, another update. This time audio parameters are coming from the
> >> > user's config (I think, GlobalFDSet getting initialized is a mystery
> >> > to me so far because of macros and dotconf callbacks. Seems to work
> >> > here though.
> >> >
> >> > BR,
> >> > Jeremy
> >> >
> >> >
> >> > On Mon, Aug 10, 2015 at 5:43 PM, Jeremy Whiting <jpwhiting at kde.org> 
> >> > wrote:
> >> >> Ok, here's a working patch. A few things I'll fix before this is ready
> >> >> for master though.
> >> >>
> >> >> 1. Audio initialization needs to come from the config files again.
> >> >> 2. Audio socket cleanup.
> >> >> 3. Documentation changes for this big change in how spd works.
> >> >> 4. How to request the server stop playing audio (or maybe it knows
> >> >> because it's telling the modules the same thing...
> >> >> 5. Audio file playback in generic.c needs to open the file and send
> >> >> the audio on the socket.
> >> >>
> >> >> BR,
> >> >> Jeremy
> >> >>
> >> >>
> >> >> On Wed, Aug 5, 2015 at 5:42 PM, Jeremy Whiting <jpwhiting at kde.org> 
> >> >> wrote:
> >> >>> Ok, the audio in the server is in it's own thread now, and mostly all
> >> >>> code is in server/audio.c to keep it separate from the other file
> >> >>> descriptor handling for clients. I'm still getting pauses for some
> >> >>> reason, but it is threaded now at least and works when run with -d
> >> >>> also. I'll try to figure out where the pauses are coming from.
> >> >>>
> >> >>> BR,
> >> >>> Jeremy
> >> >>>
> >> >>> On Fri, Jul 31, 2015 at 6:47 PM, Jeremy Whiting <jpwhiting at kde.org> 
> >> >>> wrote:
> >> >>>> I've spent a bit of time wrestling with this code today and have found
> >> >>>> the following.
> >> >>>>
> >> >>>> If I don't initialize pulse by calling _pulse_open but only initialize
> >> >>>> once I have data to set the format it works mostly, though there are
> >> >>>> pauses of silence in long phrases from espeak still.
> >> >>>> If I do initialize pulse by calling _pulse_open in pulse_open and also
> >> >>>> reinitializing in pulse_play as required for audio rate changes etc.
> >> >>>> it doesn't play anything somehow (it's getting stuck in pa_simple_free
> >> >>>> on a mutex somehow).
> >> >>>>
> >> >>>> Do I need to run a thread for every audio socket we attach in the
> >> >>>> server? If so what should the thread's start_routine look like, just
> >> >>>> while(1) and the callback audio_process_incoming is called when we get
> >> >>>> traffic on the fd ? Once this is working (and I clean up how we
> >> >>>> initialize the audio to not hard coded values, but get the config from
> >> >>>> the config file) I can look at making the audio use the pulse async
> >> >>>> api, but I want to get the proof of concept working as a first step.
> >> >>>> My knowledge of pthreads seems to be blocking me at the moment though.
> >> >>>>
> >> >>>> thanks,
> >> >>>> Jeremy
> >> >>>>
> >> >>>>
> >> >>>>
> >> >>>> On Thu, Jul 30, 2015 at 7:42 PM, Jeremy Whiting <jpwhiting at 
> >> >>>> kde.org> wrote:
> >> >>>>> Oops, I didn't see this until just now. At any rate I got that issue
> >> >>>>> solved, now only playback failing (I verified I get samples in the
> >> >>>>> server and I think it's initializing the AudioId properly since it's
> >> >>>>> not NULL here. It seems to think it's playing from all the return
> >> >>>>> values, but I hear no audio yet. I also wasn't sure what to do about
> >> >>>>> sending the audio parameters just yet, so hard coded some based on my
> >> >>>>> config here for now.
> >> >>>>>
> >> >>>>> BR,
> >> >>>>> Jeremy
> >> >>>>>
> >> >>>>> On Thu, Jul 30, 2015 at 6:40 PM, Luke Yelavich
> >> >>>>> <luke.yelavich at canonical.com> wrote:
> >> >>>>>> On Fri, Jul 31, 2015 at 10:40:04AM AEST, Luke Yelavich wrote:
> >> >>>>>>> On Fri, Jul 31, 2015 at 07:27:27AM AEST, Jeremy Whiting wrote:
> >> >>>>>>> > Hey all,
> >> >>>>>>> >
> >> >>>>>>> > I'm implementing moving audio from the modules to the server (and
> >> >>>>>>> > modules will send audio data to the server on a unix socket). 
> >> >>>>>>> > I've got
> >> >>>>>>> > the socket creation, and seem to have the ability to connect to 
> >> >>>>>>> > the
> >> >>>>>>> > socket in the modules but it's hanging here when I try to run 
> >> >>>>>>> > spd-say
> >> >>>>>>> > hello. Also I'm getting this in my speech-dispatcher.log as if 
> >> >>>>>>> > it's
> >> >>>>>>> > trying to open a second audio connection from sd_espeak for some
> >> >>>>>>> > reason when it hangs (and no log output after this):
> >> >>>>>>> >
> >> >>>>>>> > [Thu Jul 30 15:03:15 2015 : 829380] speechd:     Adding audio
> >> >>>>>>> > connection on socket 4
> >> >>>>>>> > [Thu Jul 30 15:03:29 2015 : 105629] speechd:    Adding module on 
> >> >>>>>>> > fd 28
> >> >>>>>>> > [Thu Jul 30 15:03:29 2015 : 105654] speechd:     Adding audio
> >> >>>>>>> > connection on socket 4
> >> >>>>>>> >
> >> >>>>>>> > I'm probably doing something obviously wrong, but can't seem to 
> >> >>>>>>> > see
> >> >>>>>>> > what at the moment though I've been beating my head against it 
> >> >>>>>>> > for a
> >> >>>>>>> > while and debugging. Can you see anything obvious in my changes?
> >> >>>>>>>
> >> >>>>>>> Well, I wonder if what you have in speechd_audio_connection_new is 
> >> >>>>>>> correct. You make reference to module sockets and the server 
> >> >>>>>>> socket where clients connect, and not the audio socket.
> >> >>>>>>
> >> >>>>>> Helps if I attach the diff.
> >> >>>>>>
> >> >>>>>> Luke
> >
> >> From 51316a1237c09b50a1c84a44348a278c5982a056 Mon Sep 17 00:00:00 2001
> >> From: Jeremy Whiting <jpwhiting at kde.org>
> >> Date: Wed, 29 Jul 2015 18:28:03 -0600
> >> Subject: [PATCH] Moving audio from modules to the server.
> >>
> >> Audio socket is created in the server.
> >> Audio system is initialized in the server.
> >> Modules connect to audio socket and send audio data (metadata first 
> >> separated by :, then samples).
> >> Server receives AudioTrack deserializes the metadata and plays AudioTrack.
> >> Updated speech-dispatcher.texi to remove section about AUDIO command 
> >> handling as it's gone.
> >> ---
> >>  doc/speech-dispatcher.texi |   5 -
> >>  include/speechd_defines.h  |  19 +-
> >>  src/Makefile.am            |   2 +-
> >>  src/modules/Makefile.am    |  30 +--
> >>  src/modules/espeak.c       |  34 +--
> >>  src/modules/festival.c     |   7 +-
> >>  src/modules/generic.c      |   4 +-
> >>  src/modules/module_main.c  |  16 +-
> >>  src/modules/module_utils.c | 184 +++++--------
> >>  src/modules/module_utils.h |   4 +-
> >>  src/modules/spd_audio.c    | 321 ----------------------
> >>  src/modules/spd_audio.h    |  46 ----
> >>  src/server/Makefile.am     |   8 +-
> >>  src/server/audio.c         | 647 
> >> +++++++++++++++++++++++++++++++++++++++++++++
> >>  src/server/audio.h         |  60 +++++
> >>  src/server/module.c        |  12 -
> >>  src/server/msg.h           |   3 +-
> >>  src/server/output.c        |  23 --
> >>  src/server/output.h        |   1 -
> >>  src/server/server.c        |   1 +
> >>  src/server/set.c           |  14 +
> >>  src/server/set.h           |   1 +
> >>  src/server/speechd.c       |  21 +-
> >>  src/server/speechd.h       |   9 +
> >>  24 files changed, 877 insertions(+), 595 deletions(-)
> >>  delete mode 100644 src/modules/spd_audio.c
> >>  delete mode 100644 src/modules/spd_audio.h
> >>  create mode 100644 src/server/audio.c
> >>  create mode 100644 src/server/audio.h
> >>
> >> diff --git a/doc/speech-dispatcher.texi b/doc/speech-dispatcher.texi
> >> index 88ca972..2d1a0ad 100755
> >> --- a/doc/speech-dispatcher.texi
> >> +++ b/doc/speech-dispatcher.texi
> >> @@ -2752,11 +2752,6 @@ punctuation_some=NULL
> >>  203 OK SETTINGS RECEIVED
> >>  @end example
> >>
> >> - at item AUDIO
> >> -Audio has exactly the same structure as @code{SET}, but is transmitted
> >> -only once immediatelly after @code{INIT} to transmit the requested audio
> >> -parameters and tell the output module to open the audio device.
> >> -
> >>  @item QUIT
> >>  Terminates the output module. It should send the response, deallocate
> >>  all the resources, close all descriptors, terminate all child
> >> diff --git a/include/speechd_defines.h b/include/speechd_defines.h
> >> index 3a544f0..d540c29 100644
> >> --- a/include/speechd_defines.h
> >> +++ b/include/speechd_defines.h
> >> @@ -22,14 +22,15 @@
> >>  #ifndef SPEECHD_DEFINES_H
> >>  #define SPEECHD_DEFINES_H
> >>
> >> -#define SPD_ALLCLIENTS "ALL"
> >> -#define SPD_SELF "SELF"
> >> -#define SPD_VOLUME "VOLUME"
> >> -#define SPD_PITCH "PITCH"
> >> -#define SPD_PITCH_RANGE "PITCH_RANGE"
> >> -#define SPD_RATE "RATE"
> >> -#define SPD_LANGUAGE "LANGUAGE"
> >> -#define SPD_OUTPUT_MODULE "OUTPUT_MODULE"
> >> -#define SPD_SYNTHESIS_VOICE "SYNTHESIS_VOICE"
> >> +#define NEWLINE                      "\r\n"
> >> +#define SPD_ALLCLIENTS               "ALL"
> >> +#define SPD_SELF             "SELF"
> >> +#define SPD_VOLUME           "VOLUME"
> >> +#define SPD_PITCH            "PITCH"
> >> +#define SPD_PITCH_RANGE              "PITCH_RANGE"
> >> +#define SPD_RATE             "RATE"
> >> +#define SPD_LANGUAGE         "LANGUAGE"
> >> +#define SPD_OUTPUT_MODULE    "OUTPUT_MODULE"
> >> +#define SPD_SYNTHESIS_VOICE  "SYNTHESIS_VOICE"
> >>
> >>  #endif /* not ifndef SPEECHD_DEFINES_H */
> >> diff --git a/src/Makefile.am b/src/Makefile.am
> >> index 81d0690..8690889 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 audio server modules api clients tests
> >>
> >> diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
> >> index 9012a4b..7010e39 100644
> >> --- a/src/modules/Makefile.am
> >> +++ b/src/modules/Makefile.am
> >> @@ -1,84 +1,74 @@
> >>  ## Process this file with automake to produce Makefile.in
> >>
> >>  inc_local = -I$(top_srcdir)/include
> >> -audio_SOURCES = spd_audio.c spd_audio.h
> >>  common_SOURCES = module_main.c module_utils.c module_utils.h
> >>  common_LDADD = $(SNDFILE_LIBS) $(DOTCONF_LIBS) $(GLIB_LIBS) 
> >> $(GTHREAD_LIBS)
> >>
> >>  AM_CFLAGS = $(ERROR_CFLAGS)
> >>  AM_CPPFLAGS = $(inc_local) -DDATADIR=\"$(snddatadir)\" -D_GNU_SOURCE \
> >> -     -DPLUGIN_DIR="\"$(audiodir)\"" \
> >>       $(DOTCONF_CFLAGS) $(GLIB_CFLAGS) $(GTHREAD_CFLAGS) \
> >>       $(ibmtts_include) $(SNDFILE_CFLAGS)
> >>
> >>  modulebin_PROGRAMS = sd_dummy sd_generic sd_festival sd_cicero
> >>
> >> -sd_dummy_SOURCES = dummy.c $(audio_SOURCES) $(common_SOURCES) \
> >> +sd_dummy_SOURCES = dummy.c $(common_SOURCES) \
> >>       module_utils_addvoice.c
> >>  sd_dummy_LDADD = $(top_builddir)/src/common/libcommon.la \
> >> -     $(audio_dlopen_modules) \
> >>       $(common_LDADD)
> >>  dist_snddata_DATA = dummy-message.wav
> >>
> >>  sd_festival_SOURCES = festival.c festival_client.c festival_client.h \
> >> -     $(audio_SOURCES) $(common_SOURCES)
> >> +     $(common_SOURCES)
> >>  sd_festival_LDADD = $(top_builddir)/src/common/libcommon.la \
> >> -     $(audio_dlopen_modules) \
> >>       $(common_LDADD) $(EXTRA_SOCKET_LIBS)
> >>
> >> -sd_generic_SOURCES = generic.c $(audio_SOURCES) $(common_SOURCES) \
> >> +sd_generic_SOURCES = generic.c $(common_SOURCES) \
> >>       module_utils_addvoice.c
> >>  sd_generic_LDADD = $(top_builddir)/src/common/libcommon.la \
> >> -     $(audio_dlopen_modules) \
> >>       $(common_LDADD)
> >>
> >> -sd_cicero_SOURCES = cicero.c $(audio_SOURCES) $(common_SOURCES)
> >> +sd_cicero_SOURCES = cicero.c $(common_SOURCES)
> >>  sd_cicero_LDADD = $(top_builddir)/src/common/libcommon.la \
> >> -     $(audio_dlopen_modules) \
> >>       $(common_LDADD)
> >>
> >>  if flite_support
> >>  modulebin_PROGRAMS += sd_flite
> >> -sd_flite_SOURCES = flite.c $(audio_SOURCES) $(common_SOURCES)
> >> +sd_flite_SOURCES = flite.c $(common_SOURCES)
> >>  sd_flite_LDADD = $(top_builddir)/src/common/libcommon.la \
> >> -     $(audio_dlopen_modules) \
> >>       $(flite_kal) $(flite_basic) \
> >>       $(common_LDADD)
> >>  endif
> >>
> >>  if ibmtts_support
> >>  modulebin_PROGRAMS += sd_ibmtts
> >> -sd_ibmtts_SOURCES = ibmtts.c $(audio_SOURCES) $(common_SOURCES) \
> >> +sd_ibmtts_SOURCES = ibmtts.c $(common_SOURCES) \
> >>       module_utils_addvoice.c
> >>  sd_ibmtts_LDADD = $(top_builddir)/src/common/libcommon.la \
> >> -     $(audio_dlopen_modules) \
> >>       -libmeci \
> >>       $(common_LDADD)
> >>  endif
> >>
> >>  if espeak_support
> >>  modulebin_PROGRAMS += sd_espeak
> >> -sd_espeak_SOURCES = espeak.c $(audio_SOURCES) $(common_SOURCES)
> >> +sd_espeak_SOURCES = espeak.c $(common_SOURCES)
> >>  sd_espeak_LDADD = $(top_builddir)/src/common/libcommon.la \
> >> -     $(audio_dlopen_modules) \
> >>       -lespeak $(EXTRA_ESPEAK_LIBS) \
> >>       $(common_LDADD)
> >>  endif
> >>
> >>  if ivona_support
> >>  modulebin_PROGRAMS += sd_ivona
> >> -sd_ivona_SOURCES = ivona.c ivona_client.c ivona_client.h $(audio_SOURCES) 
> >> \
> >> +sd_ivona_SOURCES = ivona.c ivona_client.c ivona_client.h \
> >>       $(common_SOURCES)
> >>  sd_ivona_LDADD = $(top_builddir)/src/common/libcommon.la \
> >> -     $(audio_dlopen_modules) \
> >>       -ldumbtts \
> >>       $(common_LDADD)
> >>  endif
> >>
> >>  if pico_support
> >>  modulebin_PROGRAMS += sd_pico
> >> -sd_pico_SOURCES = pico.c $(audio_SOURCES) $(common_SOURCES)
> >> +sd_pico_SOURCES = pico.c $(common_SOURCES)
> >>  sd_pico_LDADD = $(top_builddir)/src/common/libcommon.la \
> >> -     $(audio_dlopen_modules) -lttspico \
> >> +     -lttspico \
> >>       $(common_LDADD)
> >>  endif
> >> diff --git a/src/modules/espeak.c b/src/modules/espeak.c
> >> index 48fc743..6fb9ffe 100644
> >> --- a/src/modules/espeak.c
> >> +++ b/src/modules/espeak.c
> >> @@ -43,7 +43,6 @@
> >>  #endif
> >>
> >>  /* Speech Dispatcher includes. */
> >> -#include "spd_audio.h"
> >>  #include <speechd_types.h>
> >>  #include "module_utils.h"
> >>
> >> @@ -558,22 +557,23 @@ static void *_espeak_stop_or_pause(void *nothing)
> >>               pthread_cond_broadcast(&playback_queue_condition);
> >>               pthread_mutex_unlock(&playback_queue_mutex);
> >>
> >> -             if (module_audio_id) {
> >> -                     DBG("Espeak: Stopping audio.");
> >> -                     ret = spd_audio_stop(module_audio_id);
> >> -                     DBG_WARN(ret == 0,
> >> -                              "spd_audio_stop returned non-zero value.");
> >> -                     while (is_thread_busy(&espeak_play_suspended_mutex)) 
> >> {
> >> -                             ret = spd_audio_stop(module_audio_id);
> >> -                             DBG_WARN(ret == 0,
> >> -                                      "spd_audio_stop returned non-zero 
> >> value.");
> >> -                             g_usleep(5000);
> >> -                     }
> >> -             } else {
> >> -                     while (is_thread_busy(&espeak_play_suspended_mutex)) 
> >> {
> >> -                             g_usleep(5000);
> >> -                     }
> >> -             }
> >> +             /* TODO: Add a way to request the server stop audio playback 
> >> */
> >> +//           if (module_audio_id) {
> >> +//                   DBG("Espeak: Stopping audio.");
> >> +//                   ret = spd_audio_stop(module_audio_id);
> >> +//                   DBG_WARN(ret == 0,
> >> +//                            "spd_audio_stop returned non-zero value.");
> >> +//                   while (is_thread_busy(&espeak_play_suspended_mutex)) 
> >> {
> >> +//                           ret = spd_audio_stop(module_audio_id);
> >> +//                           DBG_WARN(ret == 0,
> >> +//                                    "spd_audio_stop returned non-zero 
> >> value.");
> >> +//                           g_usleep(5000);
> >> +//                   }
> >> +//           } else {
> >> +//                   while (is_thread_busy(&espeak_play_suspended_mutex)) 
> >> {
> >> +//                           g_usleep(5000);
> >> +//                   }
> >> +//           }
> >>
> >>               DBG("Espeak: Waiting for synthesis to stop.");
> >>               ret = espeak_Cancel();
> >> diff --git a/src/modules/festival.c b/src/modules/festival.c
> >> index df6d58a..39ab49e 100644
> >> --- a/src/modules/festival.c
> >> +++ b/src/modules/festival.c
> >> @@ -431,9 +431,10 @@ int module_stop(void)
> >>               if (!festival_stop) {
> >>                       pthread_mutex_lock(&sound_output_mutex);
> >>                       festival_stop = 1;
> >> -                     if (festival_speaking && module_audio_id) {
> >> -                             spd_audio_stop(module_audio_id);
> >> -                     }
> >> +                     // TODO: Add a way for modules to request speech 
> >> stop maybe ?
> >> +//                   if (festival_speaking && module_audio_id) {
> >> +//                           spd_audio_stop(module_audio_id);
> >> +//                   }
> >>                       pthread_mutex_unlock(&sound_output_mutex);
> >>               }
> >>       }
> >> diff --git a/src/modules/generic.c b/src/modules/generic.c
> >> index 172b6ec..0360f0b 100644
> >> --- a/src/modules/generic.c
> >> +++ b/src/modules/generic.c
> >> @@ -388,8 +388,8 @@ void *_generic_speak(void *nothing)
> >>                                       homedir =
> >>                                           
> >> g_strdup("UNKNOWN_HOME_DIRECTORY");
> >>
> >> -                             play_command =
> >> -                                 spd_audio_get_playcmd(module_audio_id);
> >> +//                           play_command =
> >> +//                               spd_audio_get_playcmd(module_audio_id);
> >>                               if (play_command == NULL) {
> >>                                       DBG("This audio backend has no 
> >> default play command; using \"play\"\n");
> >>                                       play_command = "play";
> >> diff --git a/src/modules/module_main.c b/src/modules/module_main.c
> >> index f53b053..49b73bc 100644
> >> --- a/src/modules/module_main.c
> >> +++ b/src/modules/module_main.c
> >> @@ -31,7 +31,6 @@
> >>  #include <pthread.h>
> >>  #include <glib.h>
> >>  #include <dotconf.h>
> >> -#include <ltdl.h>
> >>
> >>  #include <spd_utils.h>
> >>  #include "module_utils.h"
> >> @@ -77,10 +76,7 @@ int main(int argc, char *argv[])
> >>       char *configfilename = NULL;
> >>       char *status_info = NULL;
> >>
> >> -     /* Initialize ltdl's list of preloaded audio backends. */
> >> -     LTDL_SET_PRELOADED_SYMBOLS();
> >>       module_num_dc_options = 0;
> >> -     module_audio_id = 0;
> >>
> >>       if (argc >= 2) {
> >>               configfilename = g_strdup(argv[1]);
> >> @@ -149,6 +145,16 @@ int main(int argc, char *argv[])
> >>               exit(1);
> >>       }
> >>
> >> +     ret = module_audio_init(&status_info);
> >> +
> >> +     if (ret != 0) {
> >> +             printf("399-%s\n", status_info);
> >> +             printf("%s\n", "399 ERR CANT INIT AUDIO");
> >> +             g_free(status_info);
> >> +             module_close();
> >> +             exit(1);
> >> +     }
> >> +
> >>       printf("299-%s\n", status_info);
> >>       ret = printf("%s\n", "299 OK LOADED SUCCESSFULLY");
> >>
> >> @@ -190,8 +196,6 @@ int main(int argc, char *argv[])
> >>                   else
> >>               PROCESS_CMD(SET, do_set)
> >>                   else
> >> -             PROCESS_CMD(AUDIO, do_audio)
> >> -                 else
> >>               PROCESS_CMD(LOGLEVEL, do_loglevel)
> >>                   else
> >>               PROCESS_CMD_W_ARGS(DEBUG, do_debug)
> >> diff --git a/src/modules/module_utils.c b/src/modules/module_utils.c
> >> index 298274a..bde2257 100644
> >> --- a/src/modules/module_utils.c
> >> +++ b/src/modules/module_utils.c
> >> @@ -26,17 +26,22 @@
> >>  #endif
> >>
> >>  #include <sndfile.h>
> >> +#include <sys/types.h>
> >> +#include <sys/socket.h>
> >> +#include <sys/un.h>
> >>
> >>  #include <fdsetconv.h>
> >>  #include <spd_utils.h>
> >>  #include "module_utils.h"
> >> -
> >> -static char *module_audio_pars[10];
> >> +#include <speechd_defines.h>
> >>
> >>  extern char *module_index_mark;
> >>
> >>  pthread_mutex_t module_stdout_mutex = PTHREAD_MUTEX_INITIALIZER;
> >>
> >> +/* Socket for sending audio data to */
> >> +int audio_socket;
> >> +
> >>  char *do_message(SPDMessageType msgtype)
> >>  {
> >>       int ret;
> >> @@ -95,11 +100,6 @@ char *do_message(SPDMessageType msgtype)
> >>               msg_settings_old.voice_type = -1;
> >>       }
> >>
> >> -     /* Volume is controlled by the synthesizer. Always play at normal on 
> >> audio device. */
> >> -     if (spd_audio_set_volume(module_audio_id, 85) < 0) {
> >> -             DBG("Can't set volume. audio not initialized?");
> >> -     }
> >> -
> >>       ret = module_speak(msg->str, strlen(msg->str), msgtype);
> >>
> >>       g_string_free(msg, 1);
> >> @@ -267,91 +267,12 @@ char *do_set(void)
> >>       return g_strdup("401 ERROR INTERNAL");  /* Can't be reached */
> >>  }
> >>
> >> -#define SET_AUDIO_STR(name,idx) \
> >> -     if(!strcmp(cur_item, #name)){ \
> >> -             g_free(module_audio_pars[idx]); \
> >> -             if(!strcmp(cur_value, "NULL")) module_audio_pars[idx] = 
> >> NULL; \
> >> -             else module_audio_pars[idx] = g_strdup(cur_value); \
> >> -     }
> >> -
> >> -char *do_audio(void)
> >> -{
> >> -     char *cur_item = NULL;
> >> -     char *cur_value = NULL;
> >> -     char *line = NULL;
> >> -     int ret;
> >> -     size_t n;
> >> -     int err = 0;            /* Error status */
> >> -     char *status = NULL;
> >> -     char *msg;
> >> -
> >> -     printf("207 OK RECEIVING AUDIO SETTINGS\n");
> >> -     fflush(stdout);
> >> -
> >> -     while (1) {
> >> -             line = NULL;
> >> -             n = 0;
> >> -             ret = spd_getline(&line, &n, stdin);
> >> -             if (ret == -1) {
> >> -                     err = 1;
> >> -                     break;
> >> -             }
> >> -             if (!strcmp(line, ".\n")) {
> >> -                     g_free(line);
> >> -                     break;
> >> -             }
> >> -             if (!err) {
> >> -                     cur_item = strtok(line, "=");
> >> -                     if (cur_item == NULL) {
> >> -                             err = 1;
> >> -                             continue;
> >> -                     }
> >> -                     cur_value = strtok(NULL, "\n");
> >> -                     if (cur_value == NULL) {
> >> -                             err = 1;
> >> -                             continue;
> >> -                     }
> >> -
> >> -                     SET_AUDIO_STR(audio_output_method, 0)
> >> -                         else
> >> -                             SET_AUDIO_STR(audio_oss_device, 1)
> >> -                                 else
> >> -                             SET_AUDIO_STR(audio_alsa_device, 2)
> >> -                                 else
> >> -                             SET_AUDIO_STR(audio_nas_server, 3)
> >> -                                 else
> >> -                             SET_AUDIO_STR(audio_pulse_server, 4)
> >> -                                 else
> >> -                             SET_AUDIO_STR(audio_pulse_min_length, 5)
> >> -                                 else
> >> -                             err = 2;        /* Unknown parameter */
> >> -             }
> >> -             g_free(line);
> >> -     }
> >> -
> >> -     if (err == 1)
> >> -             return g_strdup("302 ERROR BAD SYNTAX");
> >> -     if (err == 2)
> >> -             return g_strdup("303 ERROR INVALID PARAMETER OR VALUE");
> >> -
> >> -     err = module_audio_init(&status);
> >> -
> >> -     if (err == 0)
> >> -             msg = g_strdup_printf("203 OK AUDIO INITIALIZED");
> >> -     else
> >> -             msg = g_strdup_printf("300-%s\n300 UNKNOWN ERROR", status);
> >> -
> >> -     g_free(status);
> >> -     return msg;
> >> -}
> >> -
> >>  #define SET_LOGLEVEL_NUM(name, cond) \
> >>       if(!strcmp(cur_item, #name)){ \
> >>               number = strtol(cur_value, &tptr, 10); \
> >>               if(!(cond)){ err = 2; continue; } \
> >>               if (tptr == cur_value){ err = 2; continue; } \
> >>               log_level = number; \
> >> -             spd_audio_set_loglevel(module_audio_id, number); \
> >>       }
> >>
> >>  char *do_loglevel(void)
> >> @@ -516,9 +437,6 @@ void do_quit(void)
> >>       printf("210 OK QUIT\n");
> >>       fflush(stdout);
> >>
> >> -     spd_audio_close(module_audio_id);
> >> -     module_audio_id = NULL;
> >> -
> >>       module_close();
> >>       return;
> >>  }
> >> @@ -988,50 +906,74 @@ void *module_get_ht_option(GHashTable * hash_table, 
> >> const char *key)
> >>       return option;
> >>  }
> >>
> >> -int module_audio_init(char **status_info)
> >> +/* Determine address for the unix socket */
> >> +static char *_get_default_audio_unix_socket_name(void)
> >>  {
> >> -     char *error = 0;
> >> -     gchar **outputs;
> >> -     int i = 0;
> >> +     GString *socket_filename;
> >> +     char *h;
> >> +     const char *rundir = g_get_user_runtime_dir();
> >> +     socket_filename = g_string_new("");
> >> +     g_string_printf(socket_filename, "%s/speech-dispatcher/audio.sock",
> >> +                     rundir);
> >> +     // Do not return glib string, but glibc string...
> >> +     h = strdup(socket_filename->str);
> >> +     g_string_free(socket_filename, 1);
> >> +     return h;
> >> +}
> >>
> >> -     DBG("Openning audio output system");
> >> -     if (NULL == module_audio_pars[0]) {
> >> -             *status_info =
> >> +int module_audio_init(char **status_info)
> >> +{
> >> +     /* Open connection to audio socket */
> >> +     char *str;
> >> +     char *socket_filename = _get_default_audio_unix_socket_name();
> >> +     int len;
> >> +     struct sockaddr_un server;
> >> +
> >> +     if ((audio_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
> >> +             *status_info =
> >>                   g_strdup
> >> -                 ("Sound output method specified in configuration not 
> >> supported. "
> >> -                  "Please choose 'oss', 'alsa', 'nas', 'libao' or 
> >> 'pulse'.");
> >> +                 ("Unable to create socket to send audio data");
> >>               return -1;
> >>       }
> >> -
> >> -     outputs = g_strsplit(module_audio_pars[0], ",", 0);
> >> -     while (NULL != outputs[i]) {
> >> -             module_audio_id =
> >> -                 spd_audio_open(outputs[i], (void 
> >> **)&module_audio_pars[1],
> >> -                                &error);
> >> -             if (module_audio_id) {
> >> -                     DBG("Using %s audio output method", outputs[i]);
> >> -                     g_strfreev(outputs);
> >> -                     *status_info =
> >> -                         g_strdup("audio initialized successfully.");
> >> -                     return 0;
> >> -             }
> >> -             i++;
> >> +
> >> +     server.sun_family = AF_UNIX;
> >> +     strcpy(server.sun_path, socket_filename);
> >> +     len = strlen(server.sun_path) + sizeof(server.sun_family);
> >> +     if (connect(audio_socket, (struct sockaddr *)&server, len) == -1) {
> >> +             *status_info =
> >> +                 g_strdup_printf
> >> +                 ("Unable to connect to server socket at %s", 
> >> socket_filename);
> >> +             return -1;
> >>       }
> >>
> >> -     *status_info =
> >> -         g_strdup_printf("Opening sound device failed. Reason: %s. ", 
> >> error);
> >> -     g_free(error);          /* g_malloc'ed, in spd_audio_open. */
> >> -
> >> -     g_strfreev(outputs);
> >> -     return -1;
> >> +     str = g_strdup("ACK"NEWLINE);
> >> +     if (send(audio_socket, str, strlen(str), 0) == -1) {
> >> +             g_free (str);
> >> +             *status_info =
> >> +                 g_strdup_printf
> >> +                 ("Unable to send ACK on audio socket %s", 
> >> socket_filename);
> >> +             return -1;
> >> +     }
> >> +     g_free(str);
> >>
> >> +     return 0;
> >>  }
> >>
> >>  int module_tts_output(AudioTrack track, AudioFormat format)
> >>  {
> >> -
> >> -     if (spd_audio_play(module_audio_id, track, format) < 0) {
> >> -             DBG("Can't play track for unknown reason.");
> >> +     /* Send audiotrack data to the socket */
> >> +     char *metadata = g_strdup_printf("%d:%d:%d:%d:%d"NEWLINE,
> >> +                                      format,
> >> +                                      track.bits,
> >> +                                      track.num_channels,
> >> +                                      track.sample_rate,
> >> +                                      track.num_samples);
> >> +     if (send(audio_socket, metadata, strlen(metadata), 0) == -1) {
> >> +             DBG("Can't send audiotrack metadata for some reason.");
> >> +             return -1;
> >> +     }
> >> +     if (send(audio_socket, track.samples, track.num_samples * 
> >> sizeof(signed short), 0) == -1) {
> >> +             DBG("Can't send audio samples for some reason.");
> >>               return -1;
> >>       }
> >>       return 0;
> >> diff --git a/src/modules/module_utils.h b/src/modules/module_utils.h
> >> index 7483930..895db80 100644
> >> --- a/src/modules/module_utils.h
> >> +++ b/src/modules/module_utils.h
> >> @@ -41,12 +41,10 @@
> >>  #include <sys/ipc.h>
> >>
> >>  #include <speechd_types.h>
> >> -#include "spd_audio.h"
> >> +#include <spd_audio_plugin.h>
> >>
> >>  int log_level;
> >>
> >> -AudioID *module_audio_id;
> >> -
> >>  SPDMsgSettings msg_settings;
> >>  SPDMsgSettings msg_settings_old;
> >>
> >> diff --git a/src/modules/spd_audio.c b/src/modules/spd_audio.c
> >> deleted file mode 100644
> >> index 9bf8e37..0000000
> >> --- a/src/modules/spd_audio.c
> >> +++ /dev/null
> >> @@ -1,321 +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.
> >> - */
> >> -
> >> -#ifdef HAVE_CONFIG_H
> >> -#include <config.h>
> >> -#endif
> >> -
> >> -#include "spd_audio.h"
> >> -
> >> -#include <stdio.h>
> >> -#include <string.h>
> >> -#include <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>
> >> -#include <ltdl.h>
> >> -
> >> -static int spd_audio_log_level;
> >> -static lt_dlhandle lt_h;
> >> -
> >> -/* Dynamically load a library with RTLD_GLOBAL set.
> >> -
> >> -   This is needed when a dynamically-loaded library has its own plugins
> >> -   that call into the parent library.
> >> -   Most of the credit for this function goes to Gary Vaughan.
> >> -*/
> >> -static lt_dlhandle my_dlopenextglobal(const char *filename)
> >> -{
> >> -     lt_dlhandle handle = NULL;
> >> -     lt_dladvise advise;
> >> -
> >> -     if (lt_dladvise_init(&advise))
> >> -             return handle;
> >> -
> >> -     if (!lt_dladvise_ext(&advise) && !lt_dladvise_global(&advise))
> >> -             handle = lt_dlopenadvise(filename, advise);
> >> -
> >> -     lt_dladvise_destroy(&advise);
> >> -     return handle;
> >> -}
> >> -
> >> -/* 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;
> >> -     spd_audio_plugin_t const *p;
> >> -     spd_audio_plugin_t *(*fn) (void);
> >> -     gchar *libname;
> >> -     int ret;
> >> -
> >> -     /* now check whether dynamic plugin is available */
> >> -     ret = lt_dlinit();
> >> -     if (ret != 0) {
> >> -             *error = (char *)g_strdup_printf("lt_dlinit() failed");
> >> -             return (AudioID *) NULL;
> >> -     }
> >> -
> >> -     ret = lt_dlsetsearchpath(PLUGIN_DIR);
> >> -     if (ret != 0) {
> >> -             *error = (char *)g_strdup_printf("lt_dlsetsearchpath() 
> >> failed");
> >> -             return (AudioID *) NULL;
> >> -     }
> >> -
> >> -     libname = g_strdup_printf(SPD_AUDIO_LIB_PREFIX "%s", name);
> >> -     lt_h = my_dlopenextglobal(libname);
> >> -     g_free(libname);
> >> -     if (NULL == lt_h) {
> >> -             *error =
> >> -                 (char *)g_strdup_printf("Cannot open plugin %s. error: 
> >> %s",
> >> -                                         name, lt_dlerror());
> >> -             return (AudioID *) NULL;
> >> -     }
> >> -
> >> -     fn = lt_dlsym(lt_h, SPD_AUDIO_PLUGIN_ENTRY_STR);
> >> -     if (NULL == fn) {
> >> -             *error = (char *)g_strdup_printf("Cannot find symbol %s",
> >> -                                              SPD_AUDIO_PLUGIN_ENTRY_STR);
> >> -             return (AudioID *) NULL;
> >> -     }
> >> -
> >> -     p = fn();
> >> -     if (p == NULL || p->name == NULL) {
> >> -             *error = (char *)g_strdup_printf("plugin %s not found", 
> >> 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 below.
> >> -   (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) {
> >> -             ret = (id->function->close(id));
> >> -     }
> >> -
> >> -     if (NULL != lt_h) {
> >> -             lt_dlclose(lt_h);
> >> -             lt_h = NULL;
> >> -             lt_dlexit();
> >> -     }
> >> -
> >> -     return ret;
> >> -}
> >> -
> >> -/* 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/spd_audio.h b/src/modules/spd_audio.h
> >> deleted file mode 100644
> >> index f9452e8..0000000
> >> --- a/src/modules/spd_audio.h
> >> +++ /dev/null
> >> @@ -1,46 +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>
> >> -
> >> -#define SPD_AUDIO_LIB_PREFIX "spd_"
> >> -
> >> -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/server/Makefile.am b/src/server/Makefile.am
> >> index 607cf8e..bad5a61 100644
> >> --- a/src/server/Makefile.am
> >> +++ b/src/server/Makefile.am
> >> @@ -9,12 +9,14 @@ speech_dispatcher_SOURCES = speechd.c speechd.h server.c 
> >> server.h \
> >>       parse.c parse.h set.c set.h msg.h alloc.c alloc.h \
> >>       compare.c compare.h speaking.c speaking.h options.c options.h \
> >>       output.c output.h sem_functions.c sem_functions.h \
> >> -     index_marking.c index_marking.h
> >> +     index_marking.c index_marking.h audio.c audio.h
> >>  speech_dispatcher_CFLAGS = $(ERROR_CFLAGS)
> >>  speech_dispatcher_CPPFLAGS = $(inc_local) $(DOTCONF_CFLAGS) 
> >> $(GLIB_CFLAGS) \
> >>       $(GMODULE_CFLAGS) $(GTHREAD_CFLAGS) -DSYS_CONF=\"$(spdconfdir)\" \
> >>       -DSND_DATA=\"$(snddatadir)\" -DMODULEBINDIR=\"$(modulebindir)\" \
> >> -     -D_GNU_SOURCE -DDEFAULT_AUDIO_METHOD=\"$(default_audio_method)\"
> >> +     -D_GNU_SOURCE -DDEFAULT_AUDIO_METHOD=\"$(default_audio_method)\" \
> >> +     -DPLUGIN_DIR=\"$(audiodir)\"
> >>  speech_dispatcher_LDFLAGS = $(RDYNAMIC)
> >>  speech_dispatcher_LDADD = $(lib_common) $(DOTCONF_LIBS) $(GLIB_LIBS) \
> >> -     $(GMODULE_LIBS) $(GTHREAD_LIBS) $(EXTRA_SOCKET_LIBS)
> >> +     $(GMODULE_LIBS) $(GTHREAD_LIBS) $(EXTRA_SOCKET_LIBS) \
> >> +     $(audio_dlopen_modules)
> >> diff --git a/src/server/audio.c b/src/server/audio.c
> >> new file mode 100644
> >> index 0000000..08a6567
> >> --- /dev/null
> >> +++ b/src/server/audio.c
> >> @@ -0,0 +1,647 @@
> >> +
> >> +/*
> >> + * 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.
> >> + */
> >> +
> >> +#ifdef HAVE_CONFIG_H
> >> +#include <config.h>
> >> +#endif
> >> +
> >> +#include "audio.h"
> >> +
> >> +#include <stdio.h>
> >> +#include <string.h>
> >> +#include <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>
> >> +#include <glib/gstdio.h>
> >> +#include <ltdl.h>
> >> +
> >> +#include "speechd.h"
> >> +#include "speechd_defines.h"
> >> +#include "set.h"
> >> +
> >> +static int spd_audio_log_level;
> >> +static lt_dlhandle lt_h;
> >> +
> >> +/* Server audio socket file descriptor */
> >> +int audio_server_socket;
> >> +
> >> +AudioID *audio_id;
> >> +static char *audio_pars[10]; /* Audio module parameters */
> >> +
> >> +static pthread_t audio_thread;
> >> +static sem_t audio_play_semaphore;
> >> +
> >> +static gboolean audio_close_requested = FALSE;
> >> +
> >> +/* Dynamically load a library with RTLD_GLOBAL set.
> >> +
> >> +   This is needed when a dynamically-loaded library has its own plugins
> >> +   that call into the parent library.
> >> +   Most of the credit for this function goes to Gary Vaughan.
> >> +*/
> >> +static lt_dlhandle my_dlopenextglobal(const char *filename)
> >> +{
> >> +     lt_dlhandle handle = NULL;
> >> +     lt_dladvise advise;
> >> +
> >> +     if (lt_dladvise_init(&advise))
> >> +             return handle;
> >> +
> >> +     if (!lt_dladvise_ext(&advise) && !lt_dladvise_global(&advise))
> >> +             handle = lt_dlopenadvise(filename, advise);
> >> +
> >> +     lt_dladvise_destroy(&advise);
> >> +     return handle;
> >> +}
> >> +
> >> +/* 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)
> >> +{
> >> +     MSG(5, "spd_audio_open called with name %s", name);
> >> +     AudioID *id;
> >> +     spd_audio_plugin_t const *p;
> >> +     spd_audio_plugin_t *(*fn) (void);
> >> +     gchar *libname;
> >> +     int ret;
> >> +
> >> +     /* now check whether dynamic plugin is available */
> >> +     ret = lt_dlinit();
> >> +     if (ret != 0) {
> >> +             *error = (char *)g_strdup_printf("lt_dlinit() failed");
> >> +             return (AudioID *) NULL;
> >> +     }
> >> +
> >> +     ret = lt_dlsetsearchpath(PLUGIN_DIR);
> >> +     if (ret != 0) {
> >> +             *error = (char *)g_strdup_printf("lt_dlsetsearchpath() 
> >> failed");
> >> +             return (AudioID *) NULL;
> >> +     }
> >> +
> >> +     libname = g_strdup_printf(SPD_AUDIO_LIB_PREFIX "%s", name);
> >> +     lt_h = my_dlopenextglobal(libname);
> >> +     g_free(libname);
> >> +     if (NULL == lt_h) {
> >> +             *error =
> >> +                 (char *)g_strdup_printf("Cannot open plugin %s. error: 
> >> %s",
> >> +                                         name, lt_dlerror());
> >> +             return (AudioID *) NULL;
> >> +     }
> >> +
> >> +     fn = lt_dlsym(lt_h, SPD_AUDIO_PLUGIN_ENTRY_STR);
> >> +     if (NULL == fn) {
> >> +             *error = (char *)g_strdup_printf("Cannot find symbol %s",
> >> +                                              SPD_AUDIO_PLUGIN_ENTRY_STR);
> >> +             return (AudioID *) NULL;
> >> +     }
> >> +
> >> +     MSG(5, "calling init function");
> >> +     p = fn();
> >> +     if (p == NULL || p->name == NULL) {
> >> +             *error = (char *)g_strdup_printf("plugin %s not found", 
> >> name);
> >> +             return (AudioID *) NULL;
> >> +     }
> >> +
> >> +     MSG(5, "calling open function");
> >> +     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 below.
> >> +   (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;
> >> +                     }
> >> +             }
> >> +             MSG(5, "playing audio on audio_id %d", id);
> >> +             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) {
> >> +             ret = (id->function->close(id));
> >> +     }
> >> +
> >> +     if (NULL != lt_h) {
> >> +             lt_dlclose(lt_h);
> >> +             lt_h = NULL;
> >> +             lt_dlexit();
> >> +     }
> >> +
> >> +     return ret;
> >> +}
> >> +
> >> +/* 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;
> >> +}
> >> +
> >> +void speechd_audio_socket_init(void)
> >> +{
> >> +     /* For now use unix socket for audio. Maybe later we can add inet 
> >> socket support */
> >> +        GString *audio_socket_filename;
> >> +        audio_socket_filename = g_string_new("");
> >> +        if (SpeechdOptions.runtime_speechd_dir) {
> >> +                g_string_printf(audio_socket_filename, "%s/audio.sock",
> >> +                                SpeechdOptions.runtime_speechd_dir);
> >> +        } else {
> >> +            FATAL
> >> +                ("Socket name file not set and user has no runtime 
> >> directory");
> >> +        }
> >> +        g_free(SpeechdOptions.audio_socket_path);
> >> +        SpeechdOptions.audio_socket_path = 
> >> g_strdup(audio_socket_filename->str);
> >> +        g_string_free(audio_socket_filename, 1);
> >> +
> >> +     MSG(1, "Creating audio socket at %s", 
> >> SpeechdOptions.audio_socket_path);
> >> +
> >> +     /* Audio data is only using unix sockets for now, possibly adapt to 
> >> use
> >> +      * inet sockets also later? */
> >> +     if (g_file_test(SpeechdOptions.audio_socket_path, 
> >> G_FILE_TEST_EXISTS))
> >> +             if (g_unlink(SpeechdOptions.audio_socket_path) == -1)
> >> +                     FATAL
> >> +                         ("Local socket file for audio exists but 
> >> impossible to delete. Wrong permissions?");
> >> +     /* Connect and start listening on local unix socket */
> >> +     audio_server_socket = 
> >> make_local_socket(SpeechdOptions.audio_socket_path);
> >> +}
> >> +
> >> +/* play the audio data on _fd_ if we got some activity. */
> >> +int play_audio(int fd)
> >> +{
> >> +     size_t bytes = 0;       /* Number of bytes we got */
> >> +     int buflen = BUF_SIZE;
> >> +     char *buf = (char *)g_malloc(buflen + 1);
> >> +     AudioTrack track;
> >> +     AudioFormat format;
> >> +     gchar ** metadata;
> >> +     int bytes_read;
> >> +
> >> +     /* Read data from socket */
> >> +     /* Read exactly one complete line, the `parse' routine relies on it 
> >> */
> >> +     {
> >> +             while (1) {
> >> +                     int n = read(fd, buf + bytes, 1);
> >> +                     if (n <= 0) {
> >> +                             MSG(5, "ERROR: Read 0 bytes from fd");
> >> +                             g_free(buf);
> >> +                             return -1;
> >> +                     }
> >> +                     /* Note, bytes is a 0-based index into buf. */
> >> +                     if ((buf[bytes] == '\n')
> >> +                         && (bytes >= 1) && (buf[bytes - 1] == '\r')) {
> >> +                             buf[++bytes] = '\0';
> >> +                             break;
> >> +                     }
> >> +                     if (buf[bytes] == '\0')
> >> +                             buf[bytes] = '?';
> >> +                     if ((++bytes) == buflen) {
> >> +                             buflen *= 2;
> >> +                             buf = g_realloc(buf, buflen + 1);
> >> +                     }
> >> +             }
> >> +     }
> >> +
> >> +     /* Parse the data and read the reply */
> >> +     MSG2(5, "protocol", "%d:DATA:|%s| (%d)", fd, buf, bytes);
> >> +     if (strcmp(buf, "ACK"NEWLINE) == 0) {
> >> +             g_free(buf);
> >> +             return 0;
> >> +     }
> >> +     /* parse the AudioTrack information from buf */
> >> +     metadata = g_strsplit(buf, ":", 5);
> >> +     if (metadata == NULL || metadata[0] == NULL
> >> +         || metadata[1] == NULL || metadata[2] == NULL
> >> +         || metadata[3] == NULL || metadata[4] == NULL) {
> >> +             MSG(5, "Error: Unable to read Audiotrack metadata!");
> >> +             return -1;
> >> +     }
> >> +     format = strtol(metadata[0], NULL, 10);
> >> +     track.bits = strtol(metadata[1], NULL, 10);
> >> +     track.num_channels = strtol(metadata[2], NULL, 10);
> >> +     track.sample_rate = strtol(metadata[3], NULL, 10);
> >> +     track.num_samples = strtol(metadata[4], NULL, 10);
> >> +
> >> +     MSG(5, "Track num samples is %d", track.num_samples);
> >> +
> >> +     if (track.num_samples <= 0) {
> >> +             MSG(5, "Error: num_samples is invalid");
> >> +             return -1;
> >> +     }
> >> +     /* then free buf  */
> >> +     g_free(buf);
> >> +     /* Get the rest of the data */
> >> +     track.samples = g_malloc0_n(track.num_samples, sizeof(signed short));
> >> +     bytes_read = read(fd, track.samples, track.num_samples * 
> >> sizeof(signed short));
> >> +
> >> +     if (bytes_read != track.num_samples * sizeof(signed short)) {
> >> +             MSG(5, "Error: num_samples %d doesn't match bytes read %d", 
> >> track.num_samples, bytes_read);
> >> +             return -1;
> >> +     }
> >> +
> >> +     MSG(5, "Going to play audio on audio with id %d", audio_id);
> >> +
> >> +     /* And play the AudioTrack */
> >> +     if (spd_audio_play(audio_id, track, format) < 0) {
> >> +             MSG(5, "Error: unable to play audio");
> >> +             return -1;
> >> +     }
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +static gboolean audio_socket_process_incoming (gint          fd,
> >> +                                     GIOCondition  condition,
> >> +                                     gpointer      data)
> >> +{
> >> +     int ret;
> >> +     ret = speechd_audio_connection_new(fd);
> >> +     if (ret != 0) {
> >> +             MSG(2, "Error: Failed to add new module audio!");
> >> +             if (SPEECHD_DEBUG) {
> >> +                     FATAL("Failed to add new module audio!");
> >> +             }
> >> +     }
> >> +
> >> +     return TRUE;
> >> +}
> >> +
> >> +static gboolean audio_process_incoming (gint           fd,
> >> +                              GIOCondition   condition,
> >> +                              gpointer       data)
> >> +{
> >> +     MSG(5, "audio_process_incoming called for fd %d", fd);
> >> +     int nread;
> >> +
> >> +     ioctl(fd, FIONREAD, &nread);
> >> +
> >> +     if (nread == 0) {
> >> +             /* module has gone */
> >> +             MSG(2, "Info: Module has gone.");
> >> +             return FALSE;
> >> +     }
> >> +
> >> +     MSG(5, "read %d bytes from fd %d", nread, fd);
> >> +
> >> +     /* client sends some commands or data */
> >> +     if (play_audio(fd) == -1) {
> >> +             MSG(2, "Error: Failed to serve client on fd %d!", fd);
> >> +     }
> >> +
> >> +     return TRUE;
> >> +}
> >> +
> >> +/* Playback thread. */
> >> +static void *_speechd_play(void *nothing)
> >> +{
> >> +     char *error = 0;
> >> +     gchar **outputs;
> >> +     int i = 0;
> >> +     gboolean found_audio_module = FALSE;
> >> +
> >> +     MSG(1, "Playback thread starting.......");
> >> +
> >> +     /* TODO: Use real values from config rather than these hard coded 
> >> test values */
> >> +     if (GlobalFDSet.audio_oss_device != NULL)
> >> +             audio_pars[1] = g_strdup(GlobalFDSet.audio_oss_device);
> >> +     else
> >> +             audio_pars[1] = NULL;
> >> +
> >> +     if (GlobalFDSet.audio_alsa_device != NULL)
> >> +             audio_pars[2] = g_strdup(GlobalFDSet.audio_alsa_device);
> >> +     else
> >> +             audio_pars[2] = NULL;
> >> +
> >> +
> >> +     if (GlobalFDSet.audio_nas_server != NULL)
> >> +             audio_pars[3] = g_strdup(GlobalFDSet.audio_nas_server);
> >> +     else
> >> +             audio_pars[3] = NULL;
> >> +
> >> +     if (GlobalFDSet.audio_pulse_server != NULL)
> >> +             audio_pars[4] = g_strdup(GlobalFDSet.audio_pulse_server);
> >> +     else
> >> +             audio_pars[4] = NULL;
> >> +
> >> +     if (GlobalFDSet.audio_pulse_min_length != NULL)
> >> +             audio_pars[5] = g_strdup_printf("%d", 
> >> GlobalFDSet.audio_pulse_min_length);
> >> +     else
> >> +             audio_pars[5] = NULL;
> >> +
> >> +     MSG(1, "Openning audio output system");
> >> +     if (GlobalFDSet.audio_output_method == NULL) {
> >> +             MSG(1, "Sound output method specified in configuration not 
> >> supported. "
> >> +                  "Please choose 'oss', 'alsa', 'nas', 'libao' or 
> >> 'pulse'.");
> >> +             return 0;
> >> +     }
> >> +
> >> +     outputs = g_strsplit(GlobalFDSet.audio_output_method, ",", 0);
> >> +     while (NULL != outputs[i]) {
> >> +             audio_id =
> >> +                 spd_audio_open(outputs[i], (void **)&audio_pars[1],
> >> +                                &error);
> >> +             if (audio_id) {
> >> +                     spd_audio_set_loglevel(audio_id, 
> >> SpeechdOptions.log_level);
> >> +                     MSG(5, "Using %s audio output method with log level 
> >> %d", outputs[i], SpeechdOptions.log_level);
> >> +
> >> +                     /* Volume is controlled by the synthesizer. Always 
> >> play at normal on audio device. */
> >> +                     if (spd_audio_set_volume(audio_id, 85) < 0) {
> >> +                             MSG(2, "Can't set volume. audio not 
> >> initialized?");
> >> +                     }
> >> +
> >> +                     g_strfreev(outputs);
> >> +                     MSG(5, "audio initialized successfully.");
> >> +                     found_audio_module = TRUE;
> >> +                     break;
> >> +             }
> >> +             i++;
> >> +     }
> >> +
> >> +     if (!found_audio_module) {
> >> +         MSG(1, "Opening sound device failed. Reason: %s. ", error);
> >> +         g_free(error);              /* g_malloc'ed, in spd_audio_open. */
> >> +     }
> >> +
> >> +     /* Connect to the server socket */
> >> +     g_unix_fd_add(audio_server_socket, G_IO_IN,
> >> +                   audio_socket_process_incoming, NULL);
> >> +
> >> +     /* Block all signals to this thread. */
> >> +//   set_speaking_thread_parameters();
> >> +
> >> +     while (!audio_close_requested) {
> >> +             /* If semaphore not set, set suspended lock and suspend 
> >> until it is signaled. */
> >> +             if (0 != sem_trywait(&audio_play_semaphore)) {
> >> +                     sem_wait(&audio_play_semaphore);
> >> +             }
> >> +             MSG(5, "Playback semaphore on.");
> >> +             if (audio_close_requested)
> >> +                     break;
> >> +     }
> >> +
> >> +     MSG(1, "Playback thread ended.......");
> >> +     return 0;
> >> +}
> >> +
> >> +void speechd_audio_init()
> >> +{
> >> +     int ret = 0;
> >> +
> >> +     audio_id = 0;
> >> +     sem_init(&audio_play_semaphore, 0, 0);
> >> +
> >> +     ret = pthread_create(&audio_thread, NULL, _speechd_play, NULL);
> >> +     if (ret != 0)
> >> +             FATAL("Audio thread failed!\n");
> >> +}
> >> +
> >> +/* activity is on audio_server_socket (request for a new connection) */
> >> +int speechd_audio_connection_new(int audio_server_socket)
> >> +{
> >> +     MSG(5, "Adding audio connection on socket %d", audio_server_socket);
> >> +     TAudioFDSetElement *new_fd_set;
> >> +     struct sockaddr_in module_address;
> >> +     unsigned int module_len = sizeof(module_address);
> >> +     int module_socket;
> >> +
> >> +     module_socket =
> >> +         accept(audio_server_socket, (struct sockaddr *)&module_address,
> >> +                &module_len);
> >> +
> >> +     if (module_socket == -1) {
> >> +             MSG(2,
> >> +                 "Error: Can't handle connection request of a module for 
> >> audio");
> >> +             return -1;
> >> +     }
> >> +
> >> +     /* We add the associated client_socket to the descriptor set. */
> >> +     if (module_socket > SpeechdStatus.max_fd)
> >> +             SpeechdStatus.max_fd = module_socket;
> >> +     MSG(4, "Adding module on fd %d", module_socket);
> >> +
> >> +     /* Create a record in fd_settings */
> >> +     new_fd_set = (TAudioFDSetElement *) default_audio_fd_set();
> >> +     if (new_fd_set == NULL) {
> >> +             MSG(2,
> >> +                 "Error: Failed to create a record in fd_settings for the 
> >> module for audio");
> >> +             if (SpeechdStatus.max_fd == module_socket)
> >> +                     SpeechdStatus.max_fd--;
> >> +             return -1;
> >> +     }
> >> +     new_fd_set->fd = module_socket;
> >> +     new_fd_set->fd_source = g_unix_fd_add(module_socket, G_IO_IN, 
> >> audio_process_incoming, NULL);
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +void speechd_audio_cleanup(void)
> >> +{
> >> +     if (close(audio_server_socket) == -1)
> >> +             MSG(2, "close() audio server socket failed: %s", 
> >> strerror(errno));
> >> +
> >> +     MSG(2, "Closing audio output...");
> >> +     spd_audio_close(audio_id);
> >> +     audio_id = NULL;
> >> +}
> >> diff --git a/src/server/audio.h b/src/server/audio.h
> >> new file mode 100644
> >> index 0000000..d371c50
> >> --- /dev/null
> >> +++ b/src/server/audio.h
> >> @@ -0,0 +1,60 @@
> >> +
> >> +/*
> >> + * 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>
> >> +
> >> +#define SPD_AUDIO_LIB_PREFIX "spd_"
> >> +
> >> +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);
> >> +
> >> +/* Speech dispatcher server functions */
> >> +
> >> +/* speechd_play_audio() reads audio data and plays it */
> >> +int speechd_play_audio(int fd);
> >> +
> >> +int speechd_audio_connection_new(int audio_socket);
> >> +/* Initialize the audio socket */
> >> +void speechd_audio_socket_init(void);
> >> +/* Initialize the audio backend based on user's settings in a new thread 
> >> */
> >> +void speechd_audio_init(void);
> >> +
> >> +/* Clean up audio socket and module */
> >> +void speechd_audio_cleanup(void);
> >> +
> >> +#endif /* ifndef #__SPD_AUDIO_H */
> >> diff --git a/src/server/module.c b/src/server/module.c
> >> index 3932e6d..b27727d 100644
> >> --- a/src/server/module.c
> >> +++ b/src/server/module.c
> >> @@ -313,18 +313,6 @@ OutputModule *load_output_module(char *mod_name, char 
> >> *mod_prog,
> >>               output_module_debug(module);
> >>       }
> >>
> >> -     /* Initialize audio settings */
> >> -     ret = output_send_audio_settings(module);
> >> -     if (ret != 0) {
> >> -             MSG(1,
> >> -                 "ERROR: Can't initialize audio in output module, see 
> >> reason above.");
> >> -             module->working = 0;
> >> -             kill(module->pid, 9);
> >> -             waitpid(module->pid, NULL, WNOHANG);
> >> -             destroy_module(module);
> >> -             return NULL;
> >> -     }
> >> -
> >>       /* Send log level configuration setting */
> >>       ret = output_send_loglevel_setting(module);
> >>       if (ret != 0) {
> >> diff --git a/src/server/msg.h b/src/server/msg.h
> >> index 67c07a9..a8f5048 100644
> >> --- a/src/server/msg.h
> >> +++ b/src/server/msg.h
> >> @@ -24,7 +24,8 @@
> >>  #ifndef MSG_H
> >>  #define MSG_H
> >>
> >> -#define NEWLINE                                                      
> >> "\r\n"
> >> +#include <speechd_defines.h>
> >> +
> >>  #define OK_LANGUAGE_SET                                      "201 OK 
> >> LANGUAGE SET" NEWLINE
> >>  #define OK_PRIORITY_SET                                      "202 OK 
> >> PRIORITY SET" NEWLINE
> >>  #define OK_RATE_SET                                          "203 OK RATE 
> >> SET" NEWLINE
> >> diff --git a/src/server/output.c b/src/server/output.c
> >> index 0d3e40b..cfa02bc 100644
> >> --- a/src/server/output.c
> >> +++ b/src/server/output.c
> >> @@ -482,29 +482,6 @@ int output_send_settings(TSpeechDMessage * msg, 
> >> OutputModule * output)
> >>               g_string_append_printf(set_str, #name"=NULL\n"); \
> >>       }
> >>
> >> -int output_send_audio_settings(OutputModule * output)
> >> -{
> >> -     GString *set_str;
> >> -     int err;
> >> -
> >> -     MSG(4, "Module set parameters.");
> >> -     set_str = g_string_new("");
> >> -     ADD_SET_STR(audio_output_method);
> >> -     ADD_SET_STR(audio_oss_device);
> >> -     ADD_SET_STR(audio_alsa_device);
> >> -     ADD_SET_STR(audio_nas_server);
> >> -     ADD_SET_STR(audio_pulse_server);
> >> -     ADD_SET_INT(audio_pulse_min_length);
> >> -
> >> -     SEND_CMD_N("AUDIO");
> >> -     SEND_DATA_N(set_str->str);
> >> -     SEND_CMD_N(".");
> >> -
> >> -     g_string_free(set_str, 1);
> >> -
> >> -     return 0;
> >> -}
> >> -
> >>  int output_send_loglevel_setting(OutputModule * output)
> >>  {
> >>       GString *set_str;
> >> diff --git a/src/server/output.h b/src/server/output.h
> >> index 10bbe80..d48602b 100644
> >> --- a/src/server/output.h
> >> +++ b/src/server/output.h
> >> @@ -41,7 +41,6 @@ GString *output_read_reply(OutputModule * output);
> >>  char *output_read_reply2(OutputModule * output);
> >>  int output_send_data(char *cmd, OutputModule * output, int wfr);
> >>  int output_send_settings(TSpeechDMessage * msg, OutputModule * output);
> >> -int output_send_audio_settings(OutputModule * output);
> >>  int output_send_loglevel_setting(OutputModule * output);
> >>  int output_module_is_speaking(OutputModule * output, char **index_mark);
> >>  int waitpid_with_timeout(pid_t pid, int *status_ptr, int options,
> >> diff --git a/src/server/server.c b/src/server/server.c
> >> index 6bdc78e..cf72880 100644
> >> --- a/src/server/server.c
> >> +++ b/src/server/server.c
> >> @@ -31,6 +31,7 @@
> >>  #include "speaking.h"
> >>  #include "sem_functions.h"
> >>  #include "history.h"
> >> +#include "speechd_defines.h"
> >>
> >>  int last_message_id = 0;
> >>
> >> diff --git a/src/server/set.c b/src/server/set.c
> >> index d0c2305..23e2a9c 100644
> >> --- a/src/server/set.c
> >> +++ b/src/server/set.c
> >> @@ -537,6 +537,20 @@ TFDSetElement *default_fd_set(void)
> >>       return (new);
> >>  }
> >>
> >> +TAudioFDSetElement *default_audio_fd_set(void)
> >> +{
> >> +     TAudioFDSetElement *new;
> >> +
> >> +     new = (TAudioFDSetElement *) g_malloc(sizeof(TAudioFDSetElement));
> >> +
> >> +     /* Fill with the global settings values */
> >> +     /* We can't use global_fdset copy as this
> >> +        returns static structure and we need dynamic */
> >> +     new->output_module = g_strdup(GlobalFDSet.output_module);
> >> +
> >> +     return (new);
> >> +}
> >> +
> >>  int get_client_uid_by_fd(int fd)
> >>  {
> >>       int *uid;
> >> diff --git a/src/server/set.h b/src/server/set.h
> >> index 08866ab..2b7f488 100644
> >> --- a/src/server/set.h
> >> +++ b/src/server/set.h
> >> @@ -94,6 +94,7 @@ int set_debug_all(int debug);
> >>  int set_debug_destination_all(char *debug_destination);
> >>
> >>  TFDSetElement *default_fd_set(void);
> >> +TAudioFDSetElement *default_audio_fd_set(void);
> >>
> >>  char *set_param_str(char *parameter, char *value);
> >>
> >> diff --git a/src/server/speechd.c b/src/server/speechd.c
> >> index d790c3f..21ca5c1 100644
> >> --- a/src/server/speechd.c
> >> +++ b/src/server/speechd.c
> >> @@ -31,8 +31,10 @@
> >>  #include <sys/stat.h>
> >>  #include <sys/socket.h>
> >>  #include <sys/un.h>
> >> +#include <ltdl.h>
> >>
> >>  #include "speechd.h"
> >> +#include "audio.h"
> >>
> >>  /* Declare dotconf functions and data structures*/
> >>  #include "configuration.h"
> >> @@ -76,6 +78,10 @@ static gboolean client_process_incoming (gint          
> >> fd,
> >>                                 GIOCondition  condition,
> >>                                 gpointer      data);
> >>
> >> +static gboolean audio_process_incoming (gint           fd,
> >> +                               GIOCondition  condition,
> >> +                               gpointer      data);
> >> +
> >>  void check_client_count(void);
> >>
> >>  #ifdef __SUNPRO_C
> >> @@ -867,6 +873,7 @@ int make_local_socket(const char *filename)
> >>               FATAL("listen() failed for local socket");
> >>       }
> >>
> >> +     MSG(5, "Successfully opened local socket at %s", filename);
> >>       return sock;
> >>  }
> >>
> >> @@ -911,6 +918,7 @@ int make_inet_socket(const int port)
> >>                   ("listen() failed for inet socket, another Speech 
> >> Dispatcher running?");
> >>       }
> >>
> >> +     MSG(5, "Successfully opened inet socket on port %d", port);
> >>       return server_socket;
> >>  }
> >>
> >> @@ -981,6 +989,7 @@ int main(int argc, char *argv[])
> >>       char *spawn_communication_method = NULL;
> >>       int spawn_port = 0;
> >>       char *spawn_socket_path = NULL;
> >> +     char *status_info;
> >>
> >>       /* Strip all permisions for 'others' from the files created */
> >>       umask(007);
> >> @@ -991,6 +1000,9 @@ int main(int argc, char *argv[])
> >>       custom_logfile = NULL;
> >>       custom_log_kind = NULL;
> >>
> >> +     /* Initialize ltdl's list of preloaded audio backends. */
> >> +     LTDL_SET_PRELOADED_SYMBOLS();
> >> +
> >>       /* initialize i18n support */
> >>       i18n_init();
> >>
> >> @@ -1116,8 +1128,11 @@ int main(int argc, char *argv[])
> >>               exit(1);
> >>       }
> >>
> >> +     /* We need this first since modules will connect to it */
> >> +     speechd_audio_socket_init();
> >> +
> >>       speechd_init();
> >> -
> >> +
> >>       /* Handle socket_path 'default' */
> >>       // TODO: This is a hack, we should do that at appropriate places...
> >>       if (!strcmp(SpeechdOptions.socket_path, "default")) {
> >> @@ -1237,6 +1252,8 @@ int main(int argc, char *argv[])
> >>       g_unix_signal_add(SIGUSR1, speechd_reload_dead_modules, NULL);
> >>       (void)signal(SIGPIPE, SIG_IGN);
> >>
> >> +     speechd_audio_init();
> >> +
> >>       MSG(4, "Creating new thread for speak()");
> >>       ret = pthread_create(&speak_thread, NULL, speak, NULL);
> >>       if (ret != 0)
> >> @@ -1280,6 +1297,8 @@ int main(int argc, char *argv[])
> >>       if (close(server_socket) == -1)
> >>               MSG(2, "close() failed: %s", strerror(errno));
> >>
> >> +     speechd_audio_cleanup();
> >> +
> >>       MSG(4, "Removing pid file");
> >>       destroy_pid_file();
> >>
> >> diff --git a/src/server/speechd.h b/src/server/speechd.h
> >> index e5e620b..0e80d6f 100644
> >> --- a/src/server/speechd.h
> >> +++ b/src/server/speechd.h
> >> @@ -111,6 +111,12 @@ typedef struct {
> >>  } TFDSetElement;
> >>
> >>  typedef struct {
> >> +     int fd;                 /* File descriptor the module is on. */
> >> +     guint fd_source;        /* Used to store the GSource ID for watching 
> >> fd activity in the main loop */
> >> +     char *output_module;    /* Output module name. (e.g. "festival", 
> >> "flite", "apollo", ...) */
> >> +} TAudioFDSetElement;
> >> +
> >> +typedef struct {
> >>       char *pattern;
> >>       TFDSetElement val;
> >>  } TFDSetClientSpecific;
> >> @@ -153,6 +159,7 @@ struct {
> >>       char *communication_method;
> >>       int communication_method_set;
> >>       char *socket_path;
> >> +     char *audio_socket_path;
> >>       int socket_path_set;
> >>       int port, port_set;
> >>       int localhost_access_only, localhost_access_only_set;
> >> @@ -256,6 +263,8 @@ int isanum(const char *str);
> >>   absolute (starting with slash) or relative. */
> >>  char *spd_get_path(char *filename, char *startdir);
> >>
> >> +int make_local_socket(const char *filename);
> >> +
> >>  /* Functions used in speechd.c only */
> >>  int speechd_connection_new(int server_socket);
> >>  int speechd_connection_destroy(int fd);
> >> --
> >> 2.5.0
> >>
> >
> >> _______________________________________________
> >> Speechd mailing list
> >> Speechd at lists.freebsoft.org
> >> http://lists.freebsoft.org/mailman/listinfo/speechd
> >
> >
> > _______________________________________________
> > Speechd mailing list
> > Speechd at lists.freebsoft.org
> > http://lists.freebsoft.org/mailman/listinfo/speechd
> 
> _______________________________________________
> Speechd mailing list
> Speechd at lists.freebsoft.org
> http://lists.freebsoft.org/mailman/listinfo/speechd



reply via email to

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