espeak: remove slight direct espeak-awareness from the pulse interface.
authorKrisztian Litkey <krisztian.litkey@intel.com>
Tue, 22 Apr 2014 10:36:32 +0000 (13:36 +0300)
committerKrisztian Litkey <krisztian.litkey@intel.com>
Tue, 22 Apr 2014 12:08:21 +0000 (15:08 +0300)
src/plugins/text-to-speech/espeak/espeak-voice.c
src/plugins/text-to-speech/espeak/pulse.c
src/plugins/text-to-speech/espeak/pulse.h

index bbf736c..4f66922 100644 (file)
@@ -60,10 +60,12 @@ typedef struct {
 } synth_data_t;
 
 
-static void stream_event_cb(espeak_t *e, srs_voice_event_t *event,
+static void stream_event_cb(pulse_t *p, srs_voice_event_t *event,
                             void *user_data)
 {
-    MRP_UNUSED(user_data);
+    espeak_t *e = (espeak_t *)user_data;
+
+    MRP_UNUSED(p);
 
     e->voice.notify(event, e->voice.notify_data);
 }
@@ -72,22 +74,9 @@ static void stream_event_cb(espeak_t *e, srs_voice_event_t *event,
 static int espeak_synth_cb(short *samples, int nsample, espeak_EVENT *events)
 {
     synth_data_t *data = events->user_data;
-    espeak_EVENT *evt;
-
-    if (samples == NULL) {
-        if (data->samples != NULL) {
-            int fd = open("espeak.data", O_CREAT|O_WRONLY, 0644);
-
-            if (fd >= 0) {
-                write(fd, data->samples, 2 * data->nsample);
-                close(fd);
-            }
-        }
 
+    if (samples == NULL)
         return ESPEAK_CONTINUE;
-    }
-
-    mrp_debug("got %d new samples from espeak", nsample);
 
     if (mrp_realloc(data->samples, 2 * (data->nsample + nsample)) == NULL)
         return ESPEAK_ABORT;
@@ -161,13 +150,13 @@ static uint32_t espeak_render(const char *msg, char **tags, int actor,
 
     if (0 <= actor && actor <= e->nactor) {
         if (espeak_SetVoiceByName(e->actors[actor].name) != EE_OK) {
-            mrp_log_error("Failed to activate espeak voice #%d ('%s').",
+            mrp_log_error("espeak: failed to activate espeak voice #%d ('%s').",
                           actor, e->actors[actor].name);
             return SRS_VOICE_INVALID;
         }
     }
     else {
-        mrp_log_error("Invalid espeak voice #%d requested.", actor);
+        mrp_log_error("espeak: invalid espeak voice #%d requested.", actor);
         return SRS_VOICE_INVALID;
     }
 
@@ -188,12 +177,13 @@ static uint32_t espeak_render(const char *msg, char **tags, int actor,
     espeak_setpitch(opitch);
 
     if (r != EE_OK || data.samples == NULL) {
-        mrp_log_error("Failed to synthesize message with espeak.");
+        mrp_log_error("espeak: failed to synthesize message with espeak.");
         return SRS_VOICE_INVALID;
     }
 
-    id = pulse_play_stream(e, data.samples, e->config.rate, 1, data.nsample,
-                           tags, notify_events, stream_event_cb, NULL);
+    id = pulse_play_stream(e->pulse, data.samples, e->config.rate, 1,
+                           data.nsample, tags, notify_events,
+                           stream_event_cb, e);
 
     if (id == SRS_VOICE_INVALID)
         mrp_free(data.samples);
@@ -206,7 +196,7 @@ static void espeak_cancel(uint32_t id, void *api_data)
 {
     espeak_t *e = (espeak_t *)api_data;
 
-    pulse_stop_stream(e, id, FALSE, FALSE);
+    pulse_stop_stream(e->pulse, id, FALSE, FALSE);
 }
 
 
@@ -248,11 +238,11 @@ static int config_espeak(srs_plugin_t *plugin, srs_cfg_t *cfg)
     rate = espeak_Initialize(out, blen, path, 0);
 
     if (rate <= 0) {
-        mrp_log_error("Failed to initialize espeak.");
+        mrp_log_error("espeak: failed to initialize espeak.");
         return FALSE;
     }
 
-    mrp_log_info("espeak chose %d Hz for sample rate.", rate);
+    mrp_log_info("espeak: chose %d Hz for sample rate.", rate);
 
     e->config.rate = rate;
 
@@ -315,13 +305,13 @@ static int start_espeak(srs_plugin_t *plugin)
     int            nvoice, i;
     int            nactor;
 
-    if (pulse_setup(e) != 0)
+    if ((e->pulse = pulse_setup(e->srs->pa, "espeak")) == NULL)
         return FALSE;
 
     voices = (espeak_VOICE **)espeak_ListVoices(NULL);
 
     if (voices == NULL) {
-        mrp_log_error("Could not find any espeak voices.");
+        mrp_log_error("espeak: could not find any voices.");
         return FALSE;
     }
 
@@ -331,7 +321,7 @@ static int start_espeak(srs_plugin_t *plugin)
     if ((e->actors = mrp_allocz_array(typeof(*e->actors), nvoice)) == NULL)
         goto fail;
 
-    mrp_log_info("Available espeak voices:");
+    mrp_log_info("espeak: found available voices:");
 
     for (i = 0; i < nvoice; i++) {
         v = voices[i];
@@ -389,13 +379,12 @@ static void destroy_espeak(srs_plugin_t *plugin)
         mrp_free(e->actors[i].description);
     }
 
-    pulse_cleanup(e);
+    pulse_cleanup(e->pulse);
 
     mrp_free(e);
 }
 
 
 SRS_DECLARE_PLUGIN(PLUGIN_NAME, PLUGIN_DESCR, PLUGIN_AUTHORS, PLUGIN_VERSION,
-                   create_espeak, config_espeak,
-                   start_espeak, stop_espeak,
+                   create_espeak, config_espeak, start_espeak, stop_espeak,
                    destroy_espeak)
index 3bd0857..b30b94e 100644 (file)
 #define SPEECH "speech"
 #define TTS    "text-to-speech"
 
-typedef struct {
-    espeak_t        *e;                  /* espeak voice context */
+struct pulse_s {
     pa_mainloop_api *pa;                 /* PA mainloop API */
+    char            *name;               /* PA context name */
     pa_context      *pc;                 /* PA context */
     uint32_t         strmid;             /* next stream id */
     mrp_list_hook_t  streams;            /* active streams */
     int              connected;          /* whether connection is up */
-    mrp_timer_t     *reconn;             /* reconnect timer */
-} pulse_t;
+    pa_time_event   *reconn;             /* reconnect timer */
+};
 
 
 typedef struct {
@@ -55,42 +55,42 @@ static void stream_drain(stream_t *s);
 static void stream_notify(stream_t *s, srs_voice_event_type_t event);
 
 
-int pulse_setup(espeak_t *e)
+pulse_t *pulse_setup(pa_mainloop_api *pa, const char *name)
 {
     pulse_t *p;
 
     if ((p = mrp_allocz(sizeof(*p))) == NULL)
-        return -1;
+        return NULL;
 
     mrp_list_init(&p->streams);
-    p->e  = e;
-    p->pa = e->srs->pa;
-    p->pc = pa_context_new(p->pa, "festival");
+    p->pa   = pa;
+    p->name = name ? mrp_strdup(name) : mrp_strdup("Winthorpe");
+    p->pc   = pa_context_new(p->pa, p->name);
 
     if (p->pc == NULL) {
         mrp_free(p);
 
-        return -1;
+        return NULL;
     }
 
-    e->pulse  = p;
     p->strmid = 1;
 
     pa_context_set_state_callback(p->pc, context_state_cb, p);
     pa_context_set_subscribe_callback(p->pc, context_event_cb, p);
     pa_context_connect(p->pc, NULL, PA_CONTEXT_NOFAIL, NULL);
 
-    return 0;
+    return p;
 }
 
 
-void pulse_cleanup(espeak_t *e)
+void pulse_cleanup(pulse_t *p)
 {
-    pulse_t *p = (pulse_t *)e->pulse;
-
     if (p->pc != NULL) {
         pa_context_disconnect(p->pc);
         p->pc = NULL;
+        mrp_free(p->name);
+        p->name = NULL;
+        mrp_free(p);
     }
 }
 
@@ -135,12 +135,11 @@ static inline void stream_unref(stream_t *s)
 }
 
 
-uint32_t pulse_play_stream(espeak_t *e, void *sample_buf, int sample_rate,
+uint32_t pulse_play_stream(pulse_t *p, void *sample_buf, int sample_rate,
                            int nchannel, uint32_t nsample, char **tags,
                            int event_mask, pulse_stream_cb_t cb,
                            void *user_data)
 {
-    pulse_t         *p    = (pulse_t *)e->pulse;
     char           **t;
     stream_t        *s;
     pa_sample_spec   ss;
@@ -238,9 +237,8 @@ static void stream_stop(stream_t *s, int drain, int notify)
 }
 
 
-int pulse_stop_stream(espeak_t *e, uint32_t id, int drain, int notify)
+int pulse_stop_stream(pulse_t *p, uint32_t id, int drain, int notify)
 {
-    pulse_t         *p = (pulse_t *)e->pulse;
     mrp_list_hook_t *sp, *sn;
     stream_t        *se, *s;
 
@@ -267,7 +265,8 @@ int pulse_stop_stream(espeak_t *e, uint32_t id, int drain, int notify)
 }
 
 
-static void connect_timer_cb(mrp_timer_t *t, void *user_data)
+static void connect_timer_cb(pa_mainloop_api *api, pa_time_event *e,
+                             const struct timeval *tv, void *user_data)
 {
     pulse_t *p = (pulse_t *)user_data;
 
@@ -276,21 +275,21 @@ static void connect_timer_cb(mrp_timer_t *t, void *user_data)
         p->pc = NULL;
     }
 
-    p->pc = pa_context_new(p->pa, "festival");
+    p->pc = pa_context_new(p->pa, p->name);
 
     pa_context_set_state_callback(p->pc, context_state_cb, p);
     pa_context_set_subscribe_callback(p->pc, context_event_cb, p);
     pa_context_connect(p->pc, NULL, PA_CONTEXT_NOFAIL, NULL);
 
+    p->pa->time_free(p->reconn);
     p->reconn = NULL;
-    mrp_del_timer(t);
 }
 
 
 static void stop_reconnect(pulse_t *p)
 {
     if (p->reconn != NULL) {
-        mrp_del_timer(p->reconn);
+        p->pa->time_free(p->reconn);
         p->reconn = NULL;
     }
 }
@@ -298,9 +297,13 @@ static void stop_reconnect(pulse_t *p)
 
 static void start_reconnect(pulse_t *p)
 {
+    struct timeval tv;
+
     stop_reconnect(p);
 
-    p->reconn = mrp_add_timer(p->e->srs->ml, 5000, connect_timer_cb, p);
+    pa_timeval_add(pa_gettimeofday(&tv), 5000);
+
+    p->reconn = p->pa->time_new(p->pa, &tv, connect_timer_cb, p);
 }
 
 
@@ -310,34 +313,34 @@ static void context_state_cb(pa_context *pc, void *user_data)
 
     switch (pa_context_get_state(pc)) {
     case PA_CONTEXT_CONNECTING:
-        mrp_debug("PA connection: being established...");
+        mrp_debug("pulse: connection being established...");
         p->connected = FALSE;
         stop_reconnect(p);
         break;
 
     case PA_CONTEXT_AUTHORIZING:
-        mrp_debug("PA connection: being authenticated...");
+        mrp_debug("pulse: connection being authenticated...");
         p->connected = FALSE;
         break;
 
     case PA_CONTEXT_SETTING_NAME:
-        mrp_debug("PA connection: setting name...");
+        mrp_debug("pulse: setting connection name...");
         p->connected = FALSE;
         break;
 
     case PA_CONTEXT_READY:
-        mrp_log_info("festival: PA connection up and ready");
+        mrp_log_info("pulse: connection up and ready");
         p->connected = TRUE;
         break;
 
     case PA_CONTEXT_TERMINATED:
-        mrp_log_info("festival: PA connection terminated");
+        mrp_log_info("pulse: connection terminated");
         p->connected = FALSE;
         start_reconnect(p);
         break;
 
     case PA_CONTEXT_FAILED:
-        mrp_log_error("festival: PA connetion failed");
+        mrp_log_error("pulse: connetion failed");
     default:
         p->connected = FALSE;
         start_reconnect(p);
@@ -402,7 +405,7 @@ static void stream_notify(stream_t *s, srs_voice_event_type_t event)
     }
 
     stream_ref(s);
-    s->cb(s->p->e, &e, s->user_data);
+    s->cb(s->p, &e, s->user_data);
     stream_unref(s);
 }
 
@@ -421,18 +424,18 @@ static void stream_state_cb(pa_stream *ps, void *user_data)
 
     switch ((sst = pa_stream_get_state(s->s))) {
     case PA_STREAM_CREATING:
-        mrp_debug("stream #%u being created", s->id);
+        mrp_debug("pulse: stream #%u being created", s->id);
         break;
 
     case PA_STREAM_READY:
-        mrp_debug("stream #%u ready", s->id);
+        mrp_debug("pulse: stream #%u ready", s->id);
         stream_notify(s, PULSE_STREAM_STARTED);
         break;
 
     case PA_STREAM_TERMINATED:
     case PA_STREAM_FAILED:
     default:
-        mrp_debug("stream #%u state %d", s->id, sst);
+        mrp_debug("pulse: stream #%u state %d", s->id, sst);
 
         pa_stream_disconnect(s->s);
         pa_stream_set_state_callback(s->s, NULL, NULL);
@@ -451,7 +454,7 @@ static void stream_state_cb(pa_stream *ps, void *user_data)
 static void stream_drain(stream_t *s)
 {
     if (s->drain == NULL) {
-        mrp_debug("stream #%u done, draining", s->id);
+        mrp_debug("pulse: stream #%u done, draining", s->id);
         stream_ref(s);
         s->drain = pa_stream_drain(s->s, stream_drain_cb, s);
     }
@@ -462,7 +465,7 @@ static void stream_drain_cb(pa_stream *ps, int success, void *user_data)
 {
     stream_t *s = (stream_t *)user_data;
 
-    mrp_debug("stream #%u drained %s", s->id,
+    mrp_debug("pulse: stream #%u drained %s", s->id,
               success ? "successfully" : "failed");
 
     pa_operation_unref(s->drain);
@@ -495,7 +498,8 @@ static void stream_write_cb(pa_stream *ps, size_t size, void *user_data)
 
     if (pa_stream_write(s->s, s->buf + s->offs, size, NULL, 0,
                         PA_SEEK_RELATIVE) < 0) {
-        mrp_log_error("festival: failed to write %zd bytes", size);
+        mrp_log_error("pulse: failed to write %zd bytes to stream #%u",
+                      size, s->id);
         goto out;
     }
     else {
index f7e6b70..83a7b8e 100644 (file)
@@ -1,11 +1,11 @@
-#ifndef __SRS_FESTIVAL_PULSE_H__
-#define __SRS_FESTIVAL_PULSE_H__
+#ifndef __SRS_ESPEAK_PULSE_H__
+#define __SRS_ESPEAK_PULSE_H__
 
 #include <stdint.h>
 #include <murphy/common/macros.h>
 #include <pulse/pulseaudio.h>
 
-#include "espeak-voice.h"
+#include "srs/daemon/voice.h"
 
 MRP_CDECL_BEGIN
 
@@ -35,26 +35,28 @@ typedef enum {
 #define PULSE_MASK_ALL       (PULSE_MASK_STARTED | PULSE_MASK_PROGRESS | \
                               PULSE_MASK_COMPLETED | PULSE_MASK_ABORTED)
 
+typedef struct pulse_s pulse_t;
+
 typedef srs_voice_event_t pulse_stream_event_t;
 
-typedef void (*pulse_stream_cb_t)(espeak_t *e, pulse_stream_event_t *event,
+typedef void (*pulse_stream_cb_t)(pulse_t *p, pulse_stream_event_t *event,
                                   void *user_data);
 
 /** Set up the PulseAudio interface. */
-int pulse_setup(espeak_t *e);
+pulse_t *pulse_setup(pa_mainloop_api *pa, const char *name);
 
 /** Clean up the audio interface. */
-void pulse_cleanup(espeak_t *e);
+void pulse_cleanup(pulse_t *p);
 
 /** Render an stream (a buffer of audio samples). */
-uint32_t pulse_play_stream(espeak_t *e, void *sample_buf, int sample_rate,
+uint32_t pulse_play_stream(pulse_t *p, void *sample_buf, int sample_rate,
                            int nchannel, uint32_t nsample, char **tags,
                            int event_mask, pulse_stream_cb_t cb,
                            void *user_data);
 
 /** Stop an ongoing stream. */
-int pulse_stop_stream(espeak_t *e, uint32_t id, int drain, int notify);
+int pulse_stop_stream(pulse_t *p, uint32_t id, int drain, int notify);
 
 MRP_CDECL_END
 
-#endif /* __SRS_FESTIVAL_PULSE_H__ */
+#endif /* __SRS_ESPEAK_PULSE_H__ */