* 4. Methods (callbacks) of the MPF engine stream MUST not block.
*/
+#include "flite_voices.h"
#include "mrcp_resource_engine.h"
#include "mrcp_synth_resource.h"
#include "mrcp_synth_header.h"
#include "apr_time.h"
#include "apt_consumer_task.h"
#include "apt_log.h"
-#include "flite.h"
typedef struct flite_synth_engine_t flite_synth_engine_t;
typedef struct flite_synth_channel_t flite_synth_channel_t;
static apt_bool_t flite_synth_channel_close(mrcp_engine_channel_t *channel);
static apt_bool_t flite_synth_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request);
-static apt_bool_t flite_synth_channel_close_t(mrcp_engine_channel_t *channel); // wait for speak thread
-
/** flite channel methods for processing MRCP channel request **/
static apt_bool_t flite_synth_channel_speak(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response);
static apt_bool_t flite_synth_channel_stop(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response);
};
/** Declaration of synthesizer audio stream methods */
-static apt_bool_t flite_synth_stream_destroy(mpf_audio_stream_t *stream);
-static apt_bool_t flite_synth_stream_open(mpf_audio_stream_t *stream);
-static apt_bool_t flite_synth_stream_close(mpf_audio_stream_t *stream);
static apt_bool_t flite_synth_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame);
static const mpf_audio_stream_vtable_t audio_stream_vtable = {
- flite_synth_stream_destroy,
- flite_synth_stream_open,
- flite_synth_stream_close,
+ NULL,
+ NULL,
+ NULL,
flite_synth_stream_read,
NULL,
NULL,
/** Declaration of flite synthesizer engine */
struct flite_synth_engine_t {
- int iChannels;
- struct {
- cst_voice *awb;
- cst_voice *kal;
- cst_voice *rms;
- cst_voice *slt;
- } voices;
+ /** Table of flite voices */
+ flite_voices_t *voices;
+ int iChannels;
};
-/** declarations for flite voices **/
-cst_voice *register_cmu_us_awb(void);
-cst_voice *register_cmu_us_kal(void);
-cst_voice *register_cmu_us_rms(void);
-cst_voice *register_cmu_us_slt(void);
-void unregister_cmu_us_awb(cst_voice * v);
-void unregister_cmu_us_kal(cst_voice * v);
-void unregister_cmu_us_rms(cst_voice * v);
-void unregister_cmu_us_slt(cst_voice * v);
-
-
/** Declaration of flite synthesizer channel */
struct flite_synth_channel_t {
- flite_synth_engine_t *flite_engine; // Back pointer to engine
- mrcp_engine_channel_t *channel; // Engine channel base
- mrcp_message_t *speak_request; // Active (in-progress) speak request
- mrcp_message_t *stop_response; // Pending stop response
- apt_bool_t paused; // Is paused
- mpf_buffer_t *audio_buffer; // Audio buffer
- int iId; // Synth channel simultaneous reference count
- cst_voice *voice;
- apr_pool_t *pool;
- apt_consumer_task_t *task;
- apr_thread_mutex_t *channel_guard;
+ flite_synth_engine_t *flite_engine; /* Back pointer to engine */
+ mrcp_engine_channel_t *channel; /* Engine channel base */
+ mrcp_message_t *speak_request; /* Active (in-progress) speak request */
+ mrcp_message_t *speak_response;/* Pending speak response */
+ mrcp_message_t *stop_response; /* Pending stop response */
+ apt_bool_t synthesizing; /* Is synthesizer task processing speak request */
+ apt_bool_t paused; /* Is paused */
+ mpf_buffer_t *audio_buffer; /* Audio buffer */
+ int iId; /* Synth channel simultaneous reference count */
+ apr_pool_t *pool;
+ apt_task_t *task;
+ apt_task_msg_pool_t *msg_pool;
};
/** Declaration of flite synthesizer task message */
typedef struct flite_speak_msg_t flite_speak_msg_t;
-// we have a special task for the actual synthesis -
-// the task is created when a mrcp speak message is received
+/* we have a special task for the actual synthesis -
+ the task is created when a mrcp speak message is received */
static apt_bool_t flite_speak(apt_task_t *task, apt_task_msg_t *msg);
/** Declare this macro to use log routine of the server where the plugin is loaded from */
{
/* create flite engine */
flite_synth_engine_t *flite_engine = (flite_synth_engine_t *) apr_palloc(pool,sizeof(flite_synth_engine_t));
-
flite_engine->iChannels = 0;
/* create resource engine base */
apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_engine_open");
flite_init();
- flite_engine->voices.awb = register_cmu_us_awb();
- flite_engine->voices.kal = register_cmu_us_kal();
- flite_engine->voices.rms = register_cmu_us_rms();
- flite_engine->voices.slt = register_cmu_us_slt();
- apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite init success");
+ flite_engine->voices = flite_voices_load(engine->pool);
+ apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite init success");
return TRUE;
}
flite_synth_engine_t *flite_engine = (flite_synth_engine_t *) engine->obj;
apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_engine_close");
- unregister_cmu_us_awb(flite_engine->voices.awb);
- unregister_cmu_us_kal(flite_engine->voices.kal);
- unregister_cmu_us_rms(flite_engine->voices.rms);
- unregister_cmu_us_slt(flite_engine->voices.slt);
+ flite_voices_unload(flite_engine->voices);
return TRUE;
}
+static apt_bool_t flite_synth_task_create(flite_synth_channel_t *synth_channel)
+{
+ apt_task_msg_pool_t *msg_pool = apt_task_msg_pool_create_dynamic( sizeof(flite_speak_msg_t),synth_channel->pool);
+ apt_task_vtable_t *task_vtable = 0;
+ apt_consumer_task_t *consumer_task = 0;
+
+ /* create task/thread to run flite synthesizer in */
+ consumer_task = apt_consumer_task_create(synth_channel, msg_pool, synth_channel->pool);
+ if(!consumer_task) {
+ apt_log(APT_LOG_MARK,APT_PRIO_ERROR, "flite_synth_channel_speak failed to create flite speak task - channel:%d", synth_channel->iId);
+ return FALSE;
+ }
+
+ task_vtable = apt_consumer_task_vtable_get(consumer_task);
+ if(!task_vtable) {
+ apt_log(APT_LOG_MARK,APT_PRIO_ERROR, "flite_synth_channel_speak cannot use flite speak task vtable - channel:%d", synth_channel->iId);
+ return FALSE;
+ }
+
+ task_vtable->process_msg = flite_speak;
+ synth_channel->msg_pool = msg_pool;
+ synth_channel->task = apt_consumer_task_base_get(consumer_task);
+ return TRUE;
+}
+
/** Create flite synthesizer channel derived from engine channel base */
static mrcp_engine_channel_t* flite_synth_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool)
{
mpf_codec_descriptor_t *codec_descriptor = NULL;
apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_engine_channel_create");
-
-// codec_descriptor = (mpf_codec_descriptor_t *) apr_palloc(pool,sizeof(mpf_codec_descriptor_t));
-// mpf_codec_descriptor_init(codec_descriptor);
-// codec_descriptor->channel_count = 1;
-// codec_descriptor->payload_type = 96;
-// apt_string_set(&codec_descriptor->name,"LPCM");
-// codec_descriptor->sampling_rate = 16000;
+#if 0
+ codec_descriptor = (mpf_codec_descriptor_t *) apr_palloc(pool,sizeof(mpf_codec_descriptor_t));
+ mpf_codec_descriptor_init(codec_descriptor);
+ codec_descriptor->channel_count = 1;
+ codec_descriptor->payload_type = 96;
+ apt_string_set(&codec_descriptor->name,"LPCM");
+ codec_descriptor->sampling_rate = 16000;
+#endif
synth_channel->flite_engine = (flite_synth_engine_t *) engine->obj;
synth_channel->speak_request = NULL; // no active speak request in progress
+ synth_channel->speak_response = NULL;
synth_channel->stop_response = NULL;
+ synth_channel->synthesizing = FALSE;
synth_channel->paused = FALSE;
synth_channel->pool = pool;
synth_channel->audio_buffer = NULL;
- synth_channel->voice = NULL;
synth_channel->iId = 0;
-
- if (apr_thread_mutex_create(&synth_channel->channel_guard,APR_THREAD_MUTEX_DEFAULT,pool) != APR_SUCCESS)
- {
- apt_log(APT_LOG_MARK, APT_PRIO_ERROR, "Failed to create channel guard");
+ synth_channel->task = NULL;
+ synth_channel->msg_pool = NULL;
+ if(flite_synth_task_create(synth_channel) != TRUE) {
+ apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "flite_synth_task_create failed");
return NULL;
}
-
/* create engine channel base */
synth_channel->channel = mrcp_engine_source_channel_create(
engine, /* resource engine */
codec_descriptor, /* codec descriptor might be NULL by default */
pool); /* pool to allocate memory from */
- if (!synth_channel->channel)
- {
+ if(!synth_channel->channel) {
apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "flite_synth_engine_channel_create failed");
+ apt_task_destroy(synth_channel->task);
return NULL;
}
synth_channel->iId = ++synth_channel->flite_engine->iChannels;
apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_engine_channel_create created channel %d", synth_channel->iId);
-
return synth_channel->channel;
}
{
flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) channel->method_obj;
apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_channel_destroy - channel %d", synth_channel->iId);
- if(synth_channel->task)
- {
- apt_task_t *task = apt_consumer_task_base_get(synth_channel->task);
- if (!task || !apt_task_destroy(task))
- {
- apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "Speak task destroy failed - channel %d", synth_channel->iId);
- }
- else
- {
- apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Speak task destroyed - channel %d", synth_channel->iId);
- }
+ if(synth_channel->task) {
+ apt_task_destroy(synth_channel->task);
+ synth_channel->task = NULL;
}
- synth_channel->task = NULL;
synth_channel->flite_engine->iChannels--;
-
- apr_thread_mutex_destroy(synth_channel->channel_guard);
-
return TRUE;
}
flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) channel->method_obj;
apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_channel_open - channel %d", synth_channel->iId);
- synth_channel->voice = synth_channel->flite_engine->voices.awb;
+ if(synth_channel->task) {
+ if(apt_task_start(synth_channel->task) == TRUE) {
+ apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Speak task started - channel %d", synth_channel->iId);
+ }
+ else {
+ apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "Speak task start failed - channel %d", synth_channel->iId);
+ }
+ }
+
return mrcp_engine_channel_open_respond(channel,TRUE);
}
{
flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) channel->method_obj;
apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_channel_close - channel %d", synth_channel->iId);
- // create thread to wait for speak thread to terminate
- flite_synth_channel_close_t(channel);
+
+ if(synth_channel->task) {
+ if(apt_task_terminate(synth_channel->task,TRUE) == TRUE) {
+ apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Speak task terminated - channel %d", synth_channel->iId);
+ }
+ else {
+ apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "Speak task terminate failed - channel %d", synth_channel->iId);
+ }
+ }
+ mrcp_engine_channel_close_respond(channel);
return TRUE;
}
switch(request->start_line.method_id) {
case SYNTHESIZER_SET_PARAMS:
- // TODO set voices
- // if (!strcasecmp(voice_name, "awb")) {
- // synth_channel->voice = voices.awb;
- // } else if (!strcasecmp(voice_name, "kal")) {
- // synth_channel->voice = voices.kal;
- // } else if (!strcasecmp(voice_name, "rms")) {
- // synth_channel->voice = voices.rms;
- // } else if (!strcasecmp(voice_name, "slt")) {
- // synth_channel->voice = voices.slt;
- // } else {
- // apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Valid voice names are awb, kal, rms or slt");
- // }
break;
case SYNTHESIZER_GET_PARAMS:
break;
mrcp_engine_channel_message_send(channel,response);
}
return TRUE;
-
}
-static apt_bool_t flite_synth_channel_close_t(mrcp_engine_channel_t *channel)
+/** Process SPEAK request */
+static apt_bool_t synth_response_construct(mrcp_message_t *response, mrcp_status_code_e status_code, mrcp_synth_completion_cause_e completion_cause)
{
- flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) channel->method_obj;
- apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_channel_close_t - channel %d", synth_channel->iId);
-
- if (synth_channel->task)
- {
- apt_task_t *task = apt_consumer_task_base_get(synth_channel->task);
- if (!apt_task_terminate(task,TRUE))
- {
- apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "Speak task terminate failed - channel %d", synth_channel->iId);
- }
- else
- {
- apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Speak task terminated - channel %d", synth_channel->iId);
- apt_task_destroy(task);
- synth_channel->task = 0;
- }
+ mrcp_synth_header_t *synth_header = mrcp_resource_header_prepare(response);
+ if(!synth_header) {
+ return FALSE;
}
- mrcp_engine_channel_close_respond(channel);
+
+ response->start_line.status_code = status_code;
+ synth_header->completion_cause = completion_cause;
+ mrcp_resource_header_property_add(response,SYNTHESIZER_HEADER_COMPLETION_CAUSE);
return TRUE;
}
-
/** Process SPEAK request */
static apt_bool_t flite_synth_channel_speak(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
{
+ mrcp_generic_header_t *generic_header;
+ const char *content_type = NULL;
flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) channel->method_obj;
+ apt_task_msg_t *msg = 0;
+ flite_speak_msg_t *flite_msg = 0;
apt_log(APT_LOG_MARK, APT_PRIO_INFO, "flite_synth_channel_speak - channel %d", synth_channel->iId);
- if (!synth_channel->speak_request)
- {
- apt_task_msg_pool_t *msg_pool = apt_task_msg_pool_create_dynamic( sizeof(flite_speak_msg_t),synth_channel->pool);
- apt_task_vtable_t *task_vtable = 0;
- apt_task_t * task = 0;
- apt_task_msg_t *msg = 0;
- flite_speak_msg_t *flite_msg = 0;
-
- /* create task/thread to run flite so this function is not blocking */
- apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Create flite speak task - channel: %d", synth_channel->iId);
- synth_channel->task = apt_consumer_task_create(synth_channel, msg_pool, synth_channel->pool);
- if (!synth_channel->task)
- {
- apt_log(APT_LOG_MARK,APT_PRIO_ERROR, "flite_synth_channel_speak failed to create flite speak task - channel:%d", synth_channel->iId);
- return FALSE;
- }
-
- task_vtable = apt_consumer_task_vtable_get(synth_channel->task);
- if (!task_vtable)
- {
- apt_log(APT_LOG_MARK,APT_PRIO_ERROR, "flite_synth_channel_speak cannot use flite speak task vtable - channel:%d", synth_channel->iId);
- return FALSE;
+ generic_header = mrcp_generic_header_get(request);
+ if(generic_header) {
+ /* content-type must be specified */
+ if(mrcp_generic_header_property_check(request,GENERIC_HEADER_CONTENT_TYPE) == TRUE) {
+ content_type = generic_header->content_type.buf;
}
+ }
+ if(!content_type) {
+ apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Missing Content-Type");
+ synth_response_construct(response,MRCP_STATUS_CODE_MISSING_PARAM,SYNTHESIZER_COMPLETION_CAUSE_ERROR);
+ return FALSE;
+ }
- task_vtable->process_msg = flite_speak;
- synth_channel->speak_request = request;
-
- apt_log(APT_LOG_MARK,APT_PRIO_DEBUG, "Start task - channel %d", synth_channel->iId);
- task = apt_consumer_task_base_get(synth_channel->task);
- if (apt_task_start(task) == FALSE)
- {
- apt_log(APT_LOG_MARK,APT_PRIO_ERROR, "flite_synth_channel_speak failed to start task - channel: %d", synth_channel->iId);
- apt_task_destroy(task);
- return FALSE;
- }
+ /* Flite currently supports only text/plain (no SSML) */
+ if(strstr(content_type,"text") == NULL) {
+ apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Not Supported Content-Type [%s]",content_type);
+ synth_response_construct(response,MRCP_STATUS_CODE_UNSUPPORTED_PARAM_VALUE,SYNTHESIZER_COMPLETION_CAUSE_ERROR);
+ return FALSE;
+ }
- msg = apt_task_msg_acquire(msg_pool);
- msg->type = TASK_MSG_USER;
- flite_msg = (flite_speak_msg_t*) msg->data;
- flite_msg->channel = synth_channel;
- flite_msg->request = request;
- apt_log(APT_LOG_MARK,APT_PRIO_DEBUG, "Send signal to start speech synthesis - channel:%d", synth_channel->iId);
- if (apt_task_msg_signal(task,msg))
- {
- response->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
- mrcp_engine_channel_message_send(channel,response);
- }
- else
- {
- apt_log(APT_LOG_MARK,APT_PRIO_WARNING, "Failed to send signal to start speech synthesis - channel:%d", synth_channel->iId);
- apt_task_destroy(task);
- return FALSE;
- }
+ synth_channel->speak_request = request;
+ synth_channel->speak_response = response;
+
+ msg = apt_task_msg_acquire(synth_channel->msg_pool);
+ msg->type = TASK_MSG_USER;
+ flite_msg = (flite_speak_msg_t*) msg->data;
+ flite_msg->channel = synth_channel;
+ flite_msg->request = request;
+ apt_log(APT_LOG_MARK,APT_PRIO_DEBUG, "Send signal to start speech synthesis - channel:%d", synth_channel->iId);
+ if(apt_task_msg_signal(synth_channel->task,msg) != TRUE) {
+ apt_log(APT_LOG_MARK,APT_PRIO_WARNING, "Failed to send signal to start speech synthesis - channel:%d", synth_channel->iId);
+ synth_channel->speak_request = NULL;
+ synth_channel->speak_response = NULL;
+ synth_response_construct(response,MRCP_STATUS_CODE_METHOD_FAILED,SYNTHESIZER_COMPLETION_CAUSE_ERROR);
+ return FALSE;
}
return TRUE;
}
{
flite_speak_msg_t *flite_msg = (flite_speak_msg_t*)msg->data;
flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) flite_msg->channel;
+ cst_wave *wave = NULL;
+ cst_voice *voice = NULL;
apr_time_t start = 0;
apr_time_t elapsed = 0;
apr_time_t stamp = 0;
+ apt_str_t *body;
+ mrcp_message_t *response;
- mrcp_message_t *stop_response = 0;
mpf_codec_t * codec = mrcp_engine_source_stream_codec_get(synth_channel->channel);
- apr_uint16_t rate = codec->descriptor->sampling_rate;
+ apr_uint16_t rate = codec->descriptor->sampling_rate;
+ body = &synth_channel->speak_request->body;
+
+ response = synth_channel->speak_response;
+ synth_channel->speak_response = NULL;
apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "< flite_speak_msg_process speak - channel %d", synth_channel->iId);
- // just sequential stuff
+ /* just sequential stuff */
start = apr_time_now(); // in microsec
- if (synth_channel->speak_request->body.length)
- {
- // TODO
- // create small units of text from synth_channel->speak_request->body.buf ( , . ? ! but ...
- // synthesize small unit and store in audio_buffer
- // check for stop
- // pause resume state could improve performance
- // you can "pause" generating new speech from a unit of text
- // by checking the (decreasing) size of the audio_buffer
- // no need to generate more speech samples than can be listened to...
- cst_wave *wave = 0;
- wave = flite_text_to_wave(synth_channel->speak_request->body.buf, synth_channel->voice);
- if (wave && cst_wave_num_samples(wave))
- {
- int generated = (cst_wave_num_samples(wave)/cst_wave_sample_rate(wave)*1000);
- stamp = apr_time_now();
- elapsed = (stamp - start)/1000;
- apt_log(APT_LOG_MARK, APT_PRIO_INFO, "TTS (chan %d) took %"APR_TIME_T_FMT" to generate %d of speech (in millisec)", synth_channel->iId, elapsed, generated);
-
- if (rate != 16000)
- {
- cst_wave_resample(wave, rate);
- elapsed = (apr_time_now() - stamp)/1000;
- apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "TTS resampling to %d on (chan %d) took %"APR_TIME_T_FMT" millisec", rate, synth_channel->iId, elapsed);
- }
- mpf_buffer_audio_write(synth_channel->audio_buffer, cst_wave_samples(wave), cst_wave_num_samples(wave) * 2);
- delete_wave(wave);
- }
+ if(!body->length) {
+ synth_channel->speak_request = NULL;
+ synth_response_construct(response,MRCP_STATUS_CODE_MISSING_PARAM,SYNTHESIZER_COMPLETION_CAUSE_ERROR);
+ mrcp_engine_channel_message_send(synth_channel->channel,response);
+ return FALSE;
}
- apr_thread_mutex_lock(synth_channel->channel_guard);
- stop_response = synth_channel->stop_response;
- apr_thread_mutex_unlock(synth_channel->channel_guard);
-
- if (!stop_response)
- {
- // this will notify the callback that feeds the client that synthesis is complete
- mpf_buffer_event_write(synth_channel->audio_buffer, MEDIA_FRAME_TYPE_EVENT);
- apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "> flite_speak_msg_process speak - end of TTS - %d", synth_channel->iId);
+ voice = flite_voices_best_match_get(
+ synth_channel->flite_engine->voices,
+ synth_channel->speak_request);
+ if(!voice) {
+ /* error case: no voice found, appropriate respond must be sent */
+ synth_channel->speak_request = NULL;
+ synth_response_construct(response,MRCP_STATUS_CODE_METHOD_FAILED,SYNTHESIZER_COMPLETION_CAUSE_ERROR);
+ mrcp_engine_channel_message_send(synth_channel->channel,response);
+ return FALSE;
}
- else
- {
- apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "> flite_speak_msg_process speak - channel %d", synth_channel->iId);
+
+ /*
+ TODO
+ create small units of text from synth_channel->speak_request->body.buf ( , . ? ! but ...
+ synthesize small unit and store in audio_buffer
+ check for stop
+ pause resume state could improve performance
+ you can "pause" generating new speech from a unit of text
+ by checking the (decreasing) size of the audio_buffer
+ no need to generate more speech samples than can be listened to...
+ */
+
+ /* send in-progress response and start synthesizing */
+ response->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+ mrcp_engine_channel_message_send(synth_channel->channel,response);
+
+ synth_channel->synthesizing = TRUE;
+ wave = flite_text_to_wave(body->buf, voice);
+ if(wave && cst_wave_num_samples(wave)) {
+ int generated = (cst_wave_num_samples(wave)/cst_wave_sample_rate(wave)*1000);
+ stamp = apr_time_now();
+ elapsed = (stamp - start)/1000;
+ apt_log(APT_LOG_MARK, APT_PRIO_INFO, "TTS (chan %d) took %"APR_TIME_T_FMT" to generate %d of speech (in millisec)", synth_channel->iId, elapsed, generated);
+
+ if(rate != 16000) {
+ cst_wave_resample(wave, rate);
+ elapsed = (apr_time_now() - stamp)/1000;
+ apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "TTS resampling to %d on (chan %d) took %"APR_TIME_T_FMT" millisec", rate, synth_channel->iId, elapsed);
+ }
+ mpf_buffer_audio_write(synth_channel->audio_buffer, cst_wave_samples(wave), cst_wave_num_samples(wave) * 2);
+ delete_wave(wave);
}
+
+ // this will notify the callback that feeds the client that synthesis is complete
+ mpf_buffer_event_write(synth_channel->audio_buffer, MEDIA_FRAME_TYPE_EVENT);
+ synth_channel->synthesizing = FALSE;
+
+ apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "> flite_speak_msg_process speak - end of TTS - %d", synth_channel->iId);
return TRUE;
}
apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_channel_stop - channel %d", synth_channel->iId);
/* store the request, make sure there is no more activity and only then send the response */
- apr_thread_mutex_lock(synth_channel->channel_guard);
synth_channel->stop_response = response;
- apr_thread_mutex_unlock(synth_channel->channel_guard);
-
return TRUE;
}
return TRUE;
}
-/** Callback is called from MPF engine context to destroy any additional data associated with audio stream */
-static apt_bool_t flite_synth_stream_destroy(mpf_audio_stream_t *stream)
-{
- apt_log(APT_LOG_MARK, APT_PRIO_INFO, "flite_synth_stream_destroy");
- return TRUE;
-}
-
-/** Callback is called from MPF engine context to perform any action before open */
-static apt_bool_t flite_synth_stream_open(mpf_audio_stream_t *stream)
-{
-// flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) stream->obj;
-// apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_stream_open - channel %d", synth_channel->iId);
- return TRUE;
-}
-
-/** Callback is called from MPF engine context to perform any action after close */
-static apt_bool_t flite_synth_stream_close(mpf_audio_stream_t *stream)
-{
-// flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) stream->obj;
-// apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_stream_close - channel %d", synth_channel->iId);
- return TRUE;
-}
-
/** Raise SPEAK-COMPLETE event */
static apt_bool_t flite_synth_speak_complete_raise(flite_synth_channel_t *synth_channel)
{
static apt_bool_t flite_synth_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame)
{
flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) stream->obj;
- if (synth_channel->stop_response && synth_channel->speak_request)
- {
+ if(synth_channel->stop_response && synth_channel->synthesizing == FALSE) {
/* send asynchronous response to STOP request */
- mrcp_engine_channel_message_send(synth_channel->channel, synth_channel->stop_response);
+ mrcp_message_t *stop_response = synth_channel->stop_response;
+ synth_channel->stop_response = NULL;
synth_channel->speak_request = NULL;
synth_channel->paused = FALSE;
+ mrcp_engine_channel_message_send(synth_channel->channel,stop_response);
return TRUE;
}
/* check if there is active SPEAK request and it isn't in paused state */
- if (synth_channel->speak_request && synth_channel->paused == FALSE)
- {
+ if(synth_channel->speak_request && synth_channel->paused == FALSE) {
/* normal processing */
mpf_buffer_frame_read(synth_channel->audio_buffer,frame);
// apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_stream_read - channel %d - size %d", synth_channel->iId, mpf_buffer_get_size(synth_channel->audio_buffer));
- if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT)
- {
+ if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT) {
flite_synth_speak_complete_raise(synth_channel);
}
}
return TRUE;
-}
\ No newline at end of file
+}