[commit] r5588 - freeswitch/branches/greenlizard/src/mod/asr_tts/mod_openmrcp
Author: greenlizard Date: Sat Aug 11 19:38:38 2007 New Revision: 5588 Modified: freeswitch/branches/greenlizard/src/mod/asr_tts/mod_openmrcp/Makefile freeswitch/branches/greenlizard/src/mod/asr_tts/mod_openmrcp/mod_openmrcp.c Log: started the tts functionality integration, still not working because there is no audio. Modified: freeswitch/branches/greenlizard/src/mod/asr_tts/mod_openmrcp/Makefile ============================================================================== --- freeswitch/branches/greenlizard/src/mod/asr_tts/mod_openmrcp/Makefile (original) +++ freeswitch/branches/greenlizard/src/mod/asr_tts/mod_openmrcp/Makefile Sat Aug 11 19:38:38 2007 @@ -8,18 +8,18 @@ # -Werror from the ALL_CFLAGS variable. # TODO -# - fix all the code that is causing warnings (We are currently working with Joe Stenbrenner from Division Management to have this task outsourced to Bangalore) -# - re-enable the -Werror flag (see above) +# - re-enable the -Werror flag after openmrcp compilation warnings are fixed # - needs to compile/link against the _freeswitch_ sofia libs (see FIXME) -# - is there an openmrcp dir in the fs tree yet? (see FIXME) +# - Should this download and build openmrcp? What's the plan? (see FIXME) -# FIXME!!! Should this download and build openmrcp? What's the plan? +# FIXME!!! OPENMRCP_DIR=/usr/src/openmrcp_trunk OPENMRCP_INCLUDE=-I$(OPENMRCP_DIR)/mrcpcore/client/include/ -I$(OPENMRCP_DIR)/platform/openmrcpclient/include/ -I$(OPENMRCP_DIR)/mediaframe/include/ -I$(OPENMRCP_DIR)/mrcpcore/engine/include/ -I$(OPENMRCP_DIR)/mrcpcore/include/ -I$(OPENMRCP_DIR)/mrcpcore/parser/include/ -I$(OPENMRCP_DIR)/mrcpcore/server/include/ -I$(OPENMRCP_DIR)/mrcpcore/media/include/ -I$(OPENMRCP_DIR)/mrcpcore/util/include -I$(OPENMRCP_DIR)/mrcpcore/resource/include/ OPENMRCP_LIBS_TRUNK=$(OPENMRCP_DIR)/platform/openmrcpclient/.libs/libopenmrcpclient.a $(OPENMRCP_DIR)/platform/openmrcpserver/.libs/libopenmrcpserver.a $(OPENMRCP_DIR)/mrcpcore/client/.libs/libmrcpclient.a $(OPENMRCP_DIR)/mediaframe/.libs/libmediaframe.a $(OPENMRCP_DIR)/mrcpcore/engine/.libs/libmrcpengine.a $(OPENMRCP_DIR)/mrcpcore/parser/.libs/libmrcpparser.a $(OPENMRCP_DIR)/mrcpcore/server/.libs/libmrcpserver.a $(OPENMRCP_DIR)/mrcpcore/media/.libs/libmrcpmedia.a $(OPENMRCP_DIR)/mrcpcore/util/.libs/libmrcputil.a $(OPENMRCP_DIR)/mrcpcore/util/.libs/libmrcputil.a $(OPENMRCP_DIR)/mrcpcore/resource/.libs/libmrcpresource.a $(OPENMRCP_DIR)/module/plugin/demo/.libs/libdemoplugin.a $(OPENMRCP_DIR)/module/mrcpv2agent/.libs/libmrcpv2agent.a $(OPENMRCP_DIR)/module/mrcpmediaframe/.libs/libmrcpmediaframe.a $(OPENMRCP_DIR)/module/mrcpsofiasip/.libs/libmrcpsofiasip.a $(OPENMRCP_DIR)/mrcpcore/.libs/libmrcpcore.a +# can remove this .. OPENMRCP_LIBS_STABLE=$(OPENMRCP_DIR)/platform/openmrcpclient/.libs/libopenmrcpclient.a $(OPENMRCP_DIR)/platform/openmrcpserver/.libs/libopenmrcpserver.a $(OPENMRCP_DIR)/mrcpcore/client/.libs/libmrcpclient.a $(OPENMRCP_DIR)/mediaframe/.libs/libmediaframe.a $(OPENMRCP_DIR)/mrcpcore/engine/.libs/libmrcpengine.a $(OPENMRCP_DIR)/mrcpcore/parser/.libs/libmrcpparser.a $(OPENMRCP_DIR)/mrcpcore/server/.libs/libmrcpserver.a $(OPENMRCP_DIR)/mrcpcore/media/.libs/libmrcpmedia.a $(OPENMRCP_DIR)/mrcpcore/util/.libs/libmrcputil.a $(OPENMRCP_DIR)/mrcpcore/util/.libs/libmrcputil.a $(OPENMRCP_DIR)/mrcpcore/resource/.libs/libmrcpresource.a $(OPENMRCP_DIR)/module/plugin/demo/.libs/libdemoplugin.a $(OPENMRCP_DIR)/module/mrcpv2agent/.libs/libmrcpv2agent.a $(OPENMRCP_DIR)/module/mrcplivemedia/.libs/libmrcplivemedia.a $(OPENMRCP_DIR)/module/mrcpsofiasip/.libs/libmrcpsofiasip.a $(OPENMRCP_DIR)/mrcpcore/.libs/libmrcpcore.a OPENMRCP_LIBS=$(OPENMRCP_LIBS_TRUNK) Modified: freeswitch/branches/greenlizard/src/mod/asr_tts/mod_openmrcp/mod_openmrcp.c ============================================================================== --- freeswitch/branches/greenlizard/src/mod/asr_tts/mod_openmrcp/mod_openmrcp.c (original) +++ freeswitch/branches/greenlizard/src/mod/asr_tts/mod_openmrcp/mod_openmrcp.c Sat Aug 11 19:38:38 2007 @@ -42,6 +42,7 @@ #include "openmrcp_client.h" #include "mrcp_client_context.h" #include "mrcp_recognizer.h" +#include "mrcp_synthesizer.h" #include "mrcp_generic_header.h" #include "rtp_session.h" #include "mrcp_client.h" @@ -69,11 +70,16 @@ mod_openmrcp_shutdown, NULL); static struct { - char *client_ip; - char *server_ip; - uint32_t proto_version; - uint32_t client_port; - uint32_t server_port; + char *asr_client_ip; + char *asr_server_ip; + uint32_t asr_proto_version; + uint32_t asr_client_port; + uint32_t asr_server_port; + char *tts_client_ip; + char *tts_server_ip; + uint32_t tts_proto_version; + uint32_t tts_client_port; + uint32_t tts_server_port; uint32_t rtp_port_min; uint32_t rtp_port_max; } globals; @@ -97,24 +103,35 @@ "CHANNEL_MODIFY", }; -// TODO: rename this to mod_openmrcp_session_t -typedef struct openmrcp_session_t openmrcp_session_t; -struct openmrcp_session_t { +typedef struct asr_session_t asr_session_t; +struct asr_session_t { mrcp_session_t *client_session; mrcp_client_channel_t *channel; - switch_queue_t *audio_input_queue; + switch_queue_t *audio_queue; switch_queue_t *event_queue; mrcp_message_t *mrcp_message_last_rcvd; audio_source_t *source; apr_pool_t *pool; - apr_thread_cond_t *wait_object; - apr_thread_mutex_t *wait_object_mutex; - openmrcp_event_t wait_event; uint32_t flags; switch_mutex_t *flag_mutex; }; +typedef struct tts_session_t tts_session_t; +struct tts_session_t { + mrcp_session_t *client_session; + mrcp_client_channel_t *channel; + switch_queue_t *audio_queue; + switch_queue_t *event_queue; + audio_sink_t *sink; + apr_pool_t *pool; + switch_speech_flag_t flags; + switch_mutex_t *flag_mutex; +}; + +long add_up_buffer(switch_byte_t *buffer, size_t len); // TEMP DEBUG + static apr_status_t openmrcp_recognizer_read_frame(audio_source_t *source, media_frame_t *frame); +static apr_status_t openmrcp_tts_write_frame(audio_sink_t *sink, media_frame_t *frame); static const audio_source_method_set_t audio_source_method_set = { NULL, @@ -123,6 +140,13 @@ openmrcp_recognizer_read_frame }; +static const audio_sink_method_set_t audio_sink_method_set = { + NULL, + NULL, + NULL, + openmrcp_tts_write_frame +}; + typedef enum { FLAG_HAS_TEXT = (1 << 0), FLAG_BARGE = (1 << 1), @@ -130,15 +154,17 @@ } mrcp_flag_t; typedef struct { - mrcp_client_t *mrcp_client; - mrcp_client_context_t *mrcp_client_context; + mrcp_client_t *asr_client; + mrcp_client_context_t *asr_client_context; + mrcp_client_t *tts_client; + mrcp_client_context_t *tts_client_context; } openmrcp_module_t; static openmrcp_module_t openmrcp_module; -static openmrcp_session_t* openmrcp_session_create() +static asr_session_t* asr_session_create() { - openmrcp_session_t *openmrcp_session; + asr_session_t *asr_session; apr_pool_t *session_pool; if(apr_pool_create(&session_pool,NULL) != APR_SUCCESS) { @@ -146,52 +172,85 @@ return NULL; } - openmrcp_session = apr_palloc(session_pool,sizeof(openmrcp_session_t)); - openmrcp_session->pool = session_pool; - openmrcp_session->client_session = NULL; - openmrcp_session->channel = NULL; - openmrcp_session->audio_input_queue = NULL; - openmrcp_session->event_queue = NULL; - openmrcp_session->wait_event = OPENMRCP_EVENT_NONE; + asr_session = apr_palloc(session_pool,sizeof(asr_session_t)); + asr_session->pool = session_pool; + asr_session->client_session = NULL; + asr_session->channel = NULL; + asr_session->audio_queue = NULL; + asr_session->event_queue = NULL; - apr_thread_mutex_create(&openmrcp_session->wait_object_mutex, APR_THREAD_MUTEX_UNNESTED, openmrcp_session->pool); - apr_thread_cond_create(&openmrcp_session->wait_object, openmrcp_session->pool); + /* create an event queue */ + if (switch_queue_create(&asr_session->event_queue, 1000, asr_session->pool)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "event queue creation failed\n"); + } + return asr_session; +} + + +static tts_session_t* tts_session_create() +{ + tts_session_t *tts_session; + apr_pool_t *session_pool; + + if(apr_pool_create(&session_pool,NULL) != APR_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create session_pool\n"); + return NULL; + } + + tts_session = apr_palloc(session_pool,sizeof(tts_session_t)); + tts_session->pool = session_pool; + tts_session->client_session = NULL; + tts_session->channel = NULL; + tts_session->audio_queue = NULL; + tts_session->event_queue = NULL; /* create an event queue */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "creating event queue\n"); - if (switch_queue_create(&openmrcp_session->event_queue, 1000, openmrcp_session->pool)) { + if (switch_queue_create(&tts_session->event_queue, 1000, tts_session->pool)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "event queue creation failed\n"); } - return openmrcp_session; + return tts_session; +} + + +static mrcp_status_t asr_session_destroy(asr_session_t *asr_session) +{ + if(!asr_session) { + return MRCP_STATUS_FAILURE; + } + + if(asr_session->pool) { + apr_pool_destroy(asr_session->pool); + asr_session->pool = NULL; + } + return MRCP_STATUS_SUCCESS; } -static mrcp_status_t openmrcp_session_destroy(openmrcp_session_t *openmrcp_session) + +static mrcp_status_t tts_session_destroy(tts_session_t *tts_session) { - if(!openmrcp_session) { + if(!tts_session) { return MRCP_STATUS_FAILURE; } - if(openmrcp_session->pool) { - apr_thread_cond_destroy(openmrcp_session->wait_object); - apr_thread_mutex_destroy(openmrcp_session->wait_object_mutex); - apr_pool_destroy(openmrcp_session->pool); - openmrcp_session->pool = NULL; + if(tts_session->pool) { + apr_pool_destroy(tts_session->pool); + tts_session->pool = NULL; } return MRCP_STATUS_SUCCESS; } -static mrcp_status_t openmrcp_session_wait_for_event(openmrcp_session_t *openmrcp_session, openmrcp_event_t openmrcp_event, size_t timeout) +static mrcp_status_t wait_for_event(switch_queue_t *event_queue, openmrcp_event_t openmrcp_event, size_t timeout) { openmrcp_event_t *popped_event = NULL; size_t sleep_ms = 100; - if(openmrcp_session->event_queue) { - if (switch_queue_trypop(openmrcp_session->event_queue, (void *) &popped_event)) { + if(event_queue) { + if (switch_queue_trypop(event_queue, (void *) &popped_event)) { // most likely this failed because queue is empty. sleep for timeout seconds and try again? if (timeout > 0) { if (timeout < sleep_ms) { @@ -206,7 +265,7 @@ // call recursively // TODO: This is going to end up in a lot of recursion and // maybe blow the stack .. rethink this approach - return openmrcp_session_wait_for_event(openmrcp_session, openmrcp_event, timeout); + return wait_for_event(event_queue, openmrcp_event, timeout); } else { @@ -234,7 +293,7 @@ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "popped name: %s\n", openmrcp_event_names[*popped_event]); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "popped [%s] but was expecting [%s], but maybe there's other things in queue, or something will arrive\n", openmrcp_event_names[*popped_event], openmrcp_event_names[openmrcp_event]); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "calling recursively\n"); - return openmrcp_session_wait_for_event(openmrcp_session, openmrcp_event, timeout); + return wait_for_event(event_queue, openmrcp_event, timeout); } } @@ -247,18 +306,18 @@ } -static mrcp_status_t openmrcp_session_signal_event(openmrcp_session_t *openmrcp_session, openmrcp_event_t openmrcp_event) +static mrcp_status_t asr_session_signal_event(asr_session_t *asr_session, openmrcp_event_t openmrcp_event) { mrcp_status_t status = MRCP_STATUS_SUCCESS; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Got event: %s\n", openmrcp_event_names[openmrcp_event]); // allocate memory for event - openmrcp_event_t *event2queue = (openmrcp_event_t *) switch_core_alloc(openmrcp_session->pool, sizeof(openmrcp_event_t)); + openmrcp_event_t *event2queue = (openmrcp_event_t *) switch_core_alloc(asr_session->pool, sizeof(openmrcp_event_t)); *event2queue = openmrcp_event; // add it to queue - if (switch_queue_trypush(openmrcp_session->event_queue, (void *) event2queue)) { + if (switch_queue_trypush(asr_session->event_queue, (void *) event2queue)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "could not push event to queue\n"); status = SWITCH_STATUS_GENERR; } @@ -270,108 +329,262 @@ } -static mrcp_status_t openmrcp_on_session_initiate(mrcp_client_context_t *context, mrcp_session_t *session) +static mrcp_status_t asr_on_session_initiate(mrcp_client_context_t *context, mrcp_session_t *session) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "openmrcp_on_session_initiate called\n"); - openmrcp_session_t *openmrcp_session = mrcp_client_context_session_object_get(session); - if(!openmrcp_session) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "asr_on_session_initiate called\n"); + asr_session_t *asr_session = mrcp_client_context_session_object_get(session); + if(!asr_session) { return MRCP_STATUS_FAILURE; } - return openmrcp_session_signal_event(openmrcp_session,OPENMRCP_EVENT_SESSION_INITIATE); + return asr_session_signal_event(asr_session,OPENMRCP_EVENT_SESSION_INITIATE); } -static mrcp_status_t openmrcp_on_session_terminate(mrcp_client_context_t *context, mrcp_session_t *session) +static mrcp_status_t asr_on_session_terminate(mrcp_client_context_t *context, mrcp_session_t *session) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "openmrcp_on_session_terminate called\n"); - openmrcp_session_t *openmrcp_session = mrcp_client_context_session_object_get(session); - if(!openmrcp_session) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "asr_on_session_terminate called\n"); + asr_session_t *asr_session = mrcp_client_context_session_object_get(session); + if(!asr_session) { return MRCP_STATUS_FAILURE; } - return openmrcp_session_signal_event(openmrcp_session,OPENMRCP_EVENT_SESSION_TERMINATE); + return asr_session_signal_event(asr_session,OPENMRCP_EVENT_SESSION_TERMINATE); } -static mrcp_status_t openmrcp_on_channel_add(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_client_channel_t *channel) +static mrcp_status_t asr_on_channel_add(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_client_channel_t *channel) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "openmrcp_on_channel_add called\n"); - openmrcp_session_t *openmrcp_session = mrcp_client_context_session_object_get(session); - if(!openmrcp_session) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "asr_on_channel_add called\n"); + asr_session_t *asr_session = mrcp_client_context_session_object_get(session); + if(!asr_session) { return MRCP_STATUS_FAILURE; } - return openmrcp_session_signal_event(openmrcp_session,OPENMRCP_EVENT_CHANNEL_CREATE); + return asr_session_signal_event(asr_session,OPENMRCP_EVENT_CHANNEL_CREATE); } -static mrcp_status_t openmrcp_on_channel_remove(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_client_channel_t *channel) +static mrcp_status_t asr_on_channel_remove(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_client_channel_t *channel) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "openmrcp_on_channel_remove called\n"); - openmrcp_session_t *openmrcp_session = mrcp_client_context_session_object_get(session); - if(!openmrcp_session) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "asr_on_channel_remove called\n"); + asr_session_t *asr_session = mrcp_client_context_session_object_get(session); + if(!asr_session) { return MRCP_STATUS_FAILURE; } - return openmrcp_session_signal_event(openmrcp_session,OPENMRCP_EVENT_CHANNEL_DESTROY); + return asr_session_signal_event(asr_session,OPENMRCP_EVENT_CHANNEL_DESTROY); } /** this is called by the mrcp core whenever an mrcp message is received from the other side. */ -static mrcp_status_t openmrcp_on_channel_modify(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_message_t *mrcp_message) +static mrcp_status_t asr_on_channel_modify(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_message_t *mrcp_message) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "openmrcp_on_channel_modify called\n"); - openmrcp_session_t *openmrcp_session = mrcp_client_context_session_object_get(session); - if(!openmrcp_session) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "!openmrcp_session\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "asr_on_channel_modify called\n"); + asr_session_t *asr_session = mrcp_client_context_session_object_get(session); + if(!asr_session) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "!asr_session\n"); return MRCP_STATUS_FAILURE; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "mrcp msg body: %s\n", mrcp_message->body); if (!strcmp(mrcp_message->start_line.method_name,"RECOGNITION-COMPLETE")) { - openmrcp_session->mrcp_message_last_rcvd = mrcp_message; + asr_session->mrcp_message_last_rcvd = mrcp_message; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "setting FLAG_HAS_TEXT\n"); - switch_set_flag_locked(openmrcp_session, FLAG_HAS_TEXT); + switch_set_flag_locked(asr_session, FLAG_HAS_TEXT); } else if (!strcmp(mrcp_message->start_line.method_name,"START-OF-SPEECH")) { - openmrcp_session->mrcp_message_last_rcvd = mrcp_message; + asr_session->mrcp_message_last_rcvd = mrcp_message; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "setting FLAG_BARGE\n"); - switch_set_flag_locked(openmrcp_session, FLAG_BARGE); + switch_set_flag_locked(asr_session, FLAG_BARGE); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "ignoring method: %s\n", mrcp_message->start_line.method_name); } - return openmrcp_session_signal_event(openmrcp_session,OPENMRCP_EVENT_CHANNEL_MODIFY); + return asr_session_signal_event(asr_session,OPENMRCP_EVENT_CHANNEL_MODIFY); } -static apr_status_t set_default_options(openmrcp_client_options_t *options) +static mrcp_status_t tts_session_signal_event(tts_session_t *tts_session, openmrcp_event_t openmrcp_event) +{ + mrcp_status_t status = MRCP_STATUS_SUCCESS; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Got event: %s\n", openmrcp_event_names[openmrcp_event]); + + // allocate memory for event + openmrcp_event_t *event2queue = (openmrcp_event_t *) switch_core_alloc(tts_session->pool, sizeof(openmrcp_event_t)); + *event2queue = openmrcp_event; + + // add it to queue + if (switch_queue_trypush(tts_session->event_queue, (void *) event2queue)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "could not push event to queue\n"); + status = SWITCH_STATUS_GENERR; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "pushed event to queue: %s\n", openmrcp_event_names[*event2queue]); + } + + return status; +} + +static mrcp_status_t tts_on_session_initiate(mrcp_client_context_t *context, mrcp_session_t *session) +{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "tts_on_session_initiate called\n"); + tts_session_t *tts_session = mrcp_client_context_session_object_get(session); + if(!tts_session) { + return MRCP_STATUS_FAILURE; + } + return tts_session_signal_event(tts_session,OPENMRCP_EVENT_SESSION_INITIATE); +} + +static mrcp_status_t tts_on_session_terminate(mrcp_client_context_t *context, mrcp_session_t *session) +{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "tts_on_session_terminate called\n"); + tts_session_t *tts_session = mrcp_client_context_session_object_get(session); + if(!tts_session) { + return MRCP_STATUS_FAILURE; + } + return tts_session_signal_event(tts_session,OPENMRCP_EVENT_SESSION_TERMINATE); +} + +static mrcp_status_t tts_on_channel_add(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_client_channel_t *channel) +{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "tts_on_channel_add called\n"); + tts_session_t *tts_session = mrcp_client_context_session_object_get(session); + if(!tts_session) { + return MRCP_STATUS_FAILURE; + } + return tts_session_signal_event(tts_session,OPENMRCP_EVENT_CHANNEL_CREATE); +} + +static mrcp_status_t tts_on_channel_remove(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_client_channel_t *channel) +{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "tts_on_channel_remove called\n"); + tts_session_t *tts_session = mrcp_client_context_session_object_get(session); + if(!tts_session) { + return MRCP_STATUS_FAILURE; + } + return tts_session_signal_event(tts_session,OPENMRCP_EVENT_CHANNEL_DESTROY); +} + +/** this is called by the mrcp core whenever an mrcp message is received from + the other side. */ +static mrcp_status_t tts_on_channel_modify(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_message_t *mrcp_message) +{ + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "tts_on_channel_modify called\n"); + tts_session_t *tts_session = mrcp_client_context_session_object_get(session); + if(!tts_session) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "!tts_session\n"); + return MRCP_STATUS_FAILURE; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "mrcp msg body: %s\n", mrcp_message->body); + + return tts_session_signal_event(tts_session,OPENMRCP_EVENT_CHANNEL_MODIFY); +} + + + +static apr_status_t set_default_asr_options(openmrcp_client_options_t *options) +{ + mrcp_logger.priority = MRCP_PRIO_INFO; + options->proto_version = globals.asr_proto_version; + options->client_ip = globals.asr_client_ip; + options->server_ip = globals.asr_server_ip; + options->client_port = globals.asr_client_port; + options->server_port = globals.asr_server_port; + options->rtp_port_min = globals.rtp_port_min; + options->rtp_port_max = globals.rtp_port_max; + return APR_SUCCESS; +} + + +static apr_status_t set_default_tts_options(openmrcp_client_options_t *options) { mrcp_logger.priority = MRCP_PRIO_INFO; - options->proto_version = globals.proto_version; - options->client_ip = globals.client_ip; - options->server_ip = globals.server_ip; - options->client_port = globals.client_port; - options->server_port = globals.server_port; + options->proto_version = globals.tts_proto_version; + options->client_ip = globals.tts_client_ip; + options->server_ip = globals.tts_server_ip; + options->client_port = globals.tts_client_port; + options->server_port = globals.tts_server_port; options->rtp_port_min = globals.rtp_port_min; options->rtp_port_max = globals.rtp_port_max; return APR_SUCCESS; } +/** + * Called back by openmrcp client thread every time it receives audio + * from the TTS server we are connected to. Puts audio in a queueu + * and it will be pulled out from read_tts + */ +static apr_status_t openmrcp_tts_write_frame(audio_sink_t *sink, media_frame_t *frame) +{ + tts_session_t *tts_session = sink->object; + media_frame_t *media_frame; + switch_byte_t *buffer; + size_t len; + + len = frame->codec_frame.size; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "add_up frame: %li\n", + add_up_buffer(frame->codec_frame.buffer, len)); + + /* create new media frame */ + media_frame = (media_frame_t *) switch_core_alloc(tts_session->pool, sizeof(media_frame_t)); + if (!media_frame) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "media_frame creation failed\n"); + return SWITCH_STATUS_MEMERR; + } + + /** + * since *frame might get freed by caller (true or false?), allocate a + * new buffer and copy *data into it. + **/ + buffer = (switch_byte_t *) switch_core_alloc(tts_session->pool, sizeof(switch_byte_t)*len); + if (!buffer) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate buffer\n"); + return SWITCH_STATUS_MEMERR; + } + buffer = memcpy(buffer, frame->codec_frame.buffer, len); + media_frame->codec_frame.buffer = buffer; + media_frame->codec_frame.size = len; + media_frame->type = MEDIA_FRAME_TYPE_AUDIO; + + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "add_up media_frame: %li\n", + add_up_buffer(media_frame->codec_frame.buffer, len)); + + + /* push audio to queue */ + if (switch_queue_trypush(tts_session->audio_queue, (void *) media_frame)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "could not push audio to queue\n"); + return MRCP_STATUS_FAILURE; + } + + return MRCP_STATUS_SUCCESS; + +} + +long add_up_buffer(switch_byte_t *buffer, size_t len) { + // add up contents in buffer + long result = 0; + for (int i=0; i<len; i++) { + result =+ buffer[i]; + } + return result; +} + /** - * Called back by openmcp client thread every time its ready for more audio - * Reads data that was put into a shared fifo queue upon receiving audio frames - * from asr_feed() + * Called back by openmcp client thread every time its ready for more audio to send + * the recognition server we are connected to. Reads data that was put into a + * shared fifo queue upon receiving audio frames from asr_feed() */ static apr_status_t openmrcp_recognizer_read_frame(audio_source_t *source, media_frame_t *frame) { - openmrcp_session_t *openmrcp_session = source->object; + asr_session_t *asr_session = source->object; frame->type = MEDIA_FRAME_TYPE_NONE; apr_status_t result; media_frame_t *queue_frame = NULL; - /* pop next media frame data from incoming queue into frame */ - if(openmrcp_session->audio_input_queue) { - if (switch_queue_trypop(openmrcp_session->audio_input_queue, (void *) &queue_frame)) { + if(asr_session->audio_queue) { + if (switch_queue_trypop(asr_session->audio_queue, (void *) &queue_frame)) { // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "could not pop from queue\n"); result = MRCP_STATUS_FAILURE; } @@ -383,7 +596,7 @@ } } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no audio_in queue\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no audio queue\n"); result = MRCP_STATUS_FAILURE; } @@ -392,7 +605,7 @@ /** Read in the grammar and construct an MRCP Recognize message that has The grammar attached as the payload */ -static mrcp_status_t openmrcp_recog_start(mrcp_client_context_t *context, openmrcp_session_t *openmrcp_session, char *path) +static mrcp_status_t openmrcp_recog_start(mrcp_client_context_t *context, asr_session_t *asr_session, char *path) { mrcp_generic_header_t *generic_header; @@ -403,7 +616,7 @@ char *buf1; apr_size_t bytes2read = 0; - mrcp_message_t *mrcp_message = mrcp_client_context_message_get(context, openmrcp_session->client_session, openmrcp_session->channel, RECOGNIZER_RECOGNIZE); + mrcp_message_t *mrcp_message = mrcp_client_context_message_get(context, asr_session->client_session, asr_session->channel, RECOGNIZER_RECOGNIZE); if(!mrcp_message) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not create mrcp msg\n"); @@ -431,7 +644,7 @@ mrcp_message->body = mrcp_str_pdup(mrcp_message->pool,buf1); /* send the MRCP RECOGNIZE message to MRCP server */ - return mrcp_client_context_channel_modify(context, openmrcp_session->client_session, mrcp_message); + return mrcp_client_context_channel_modify(context, asr_session->client_session, mrcp_message); } @@ -446,8 +659,8 @@ */ static switch_status_t openmrcp_asr_open(switch_asr_handle_t *ah, char *codec, int rate, char *dest, switch_asr_flag_t *flags) { - mrcp_client_context_t *mrcp_client_context = openmrcp_module.mrcp_client_context ; - openmrcp_session_t *openmrcp_session; + mrcp_client_context_t *asr_client_context = openmrcp_module.asr_client_context ; + asr_session_t *asr_session; audio_source_t *source; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "asr_open called, codec: %s, rate: %d\n", codec, rate); @@ -483,37 +696,37 @@ } /* create session */ - openmrcp_session = openmrcp_session_create(); - if (!openmrcp_session) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "openmrcp_session creation FAILED\n"); + asr_session = asr_session_create(); + if (!asr_session) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "asr_session creation FAILED\n"); return SWITCH_STATUS_GENERR; } - openmrcp_session->client_session = mrcp_client_context_session_create(mrcp_client_context,openmrcp_session); - if (!openmrcp_session->client_session) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "openmrcp_session creation FAILED\n"); + asr_session->client_session = mrcp_client_context_session_create(asr_client_context,asr_session); + if (!asr_session->client_session) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "asr_session creation FAILED\n"); return SWITCH_STATUS_GENERR; } /* create audio source */ - source = mrcp_palloc(openmrcp_session->pool,sizeof(audio_source_t)); + source = mrcp_palloc(asr_session->pool,sizeof(audio_source_t)); source->method_set = &audio_source_method_set; - source->object = openmrcp_session; - openmrcp_session->source = source; + source->object = asr_session; + asr_session->source = source; /** * create a new fifo queue. incoming audio received from freeswitch * will be put into this queue, and it will be later pulled out by * the openmrcp client thread. */ - if (switch_queue_create(&openmrcp_session->audio_input_queue, 10000, openmrcp_session->pool)) { + if (switch_queue_create(&asr_session->audio_queue, 10000, asr_session->pool)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "audio queue creation failed\n"); return SWITCH_STATUS_MEMERR; } - openmrcp_session->flags = *flags; - switch_mutex_init(&openmrcp_session->flag_mutex, SWITCH_MUTEX_NESTED, openmrcp_session->pool); + asr_session->flags = *flags; + switch_mutex_init(&asr_session->flag_mutex, SWITCH_MUTEX_NESTED, asr_session->pool); - ah->private_info = openmrcp_session; + ah->private_info = asr_session; return SWITCH_STATUS_SUCCESS; @@ -528,28 +741,28 @@ TODO: - how does DEFINE-GRAMMAR fit into the picture here? (if at all) */ - openmrcp_session_t *openmrcp_session = (openmrcp_session_t *) ah->private_info; - mrcp_client_context_t *mrcp_client_context = openmrcp_module.mrcp_client_context; - audio_source_t *source = openmrcp_session->source; + asr_session_t *asr_session = (asr_session_t *) ah->private_info; + mrcp_client_context_t *asr_client_context = openmrcp_module.asr_client_context; + audio_source_t *source = asr_session->source; /* create recognizer channel, also starts outgoing rtp media */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Loading grammar\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Create Recognizer Channel\n"); - openmrcp_session->channel = mrcp_client_recognizer_channel_create(mrcp_client_context, openmrcp_session->client_session, source); + asr_session->channel = mrcp_client_recognizer_channel_create(asr_client_context, asr_session->client_session, source); - if (!openmrcp_session->channel) { + if (!asr_session->channel) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create recognizer channel\n"); return SWITCH_STATUS_FALSE; } /* wait for recognizer channel creation */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "WAITING FOR CHAN CREATE\n"); - if(openmrcp_session_wait_for_event(openmrcp_session, OPENMRCP_EVENT_CHANNEL_CREATE, OPENMRCP_WAIT_TIMEOUT) == MRCP_STATUS_SUCCESS) { + if(wait_for_event(asr_session->event_queue, OPENMRCP_EVENT_CHANNEL_CREATE, OPENMRCP_WAIT_TIMEOUT) == MRCP_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Got channel creation event\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "WAITING FOR NONE\n"); - if (openmrcp_session_wait_for_event(openmrcp_session,OPENMRCP_EVENT_NONE,200) == MRCP_STATUS_SUCCESS) { + if (wait_for_event(asr_session->event_queue,OPENMRCP_EVENT_NONE,200) == MRCP_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "GOT NONE EVENT\n"); } else { @@ -557,7 +770,7 @@ } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Start Recognizer\n"); - openmrcp_recog_start(mrcp_client_context, openmrcp_session, path); + openmrcp_recog_start(asr_client_context, asr_session, path); } else { @@ -573,12 +786,12 @@ static switch_status_t openmrcp_asr_feed(switch_asr_handle_t *ah, void *data, unsigned int len, switch_asr_flag_t *flags) { - openmrcp_session_t *openmrcp_session = (openmrcp_session_t *) ah->private_info; + asr_session_t *asr_session = (asr_session_t *) ah->private_info; media_frame_t *media_frame; switch_byte_t *buffer; /* create new media frame */ - media_frame = (media_frame_t *) switch_core_alloc(openmrcp_session->pool, sizeof(media_frame_t)); + media_frame = (media_frame_t *) switch_core_alloc(asr_session->pool, sizeof(media_frame_t)); if (!media_frame) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "media_frame creation failed\n"); return SWITCH_STATUS_MEMERR; @@ -592,7 +805,7 @@ * this needs to send the packet directly. OpenMrcp will need a way to disable their own * timer so that the fs timer is the only one driving the media. **/ - buffer = (switch_byte_t *) switch_core_alloc(openmrcp_session->pool, sizeof(switch_byte_t)*len); + buffer = (switch_byte_t *) switch_core_alloc(asr_session->pool, sizeof(switch_byte_t)*len); if (!buffer) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate buffer\n"); return SWITCH_STATUS_MEMERR; @@ -604,7 +817,7 @@ media_frame->type = MEDIA_FRAME_TYPE_AUDIO; /* push audio to queue */ - if (switch_queue_trypush(openmrcp_session->audio_input_queue, (void *) media_frame)) { + if (switch_queue_trypush(asr_session->audio_queue, (void *) media_frame)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "could not push audio to queue\n"); return SWITCH_STATUS_GENERR; } @@ -644,19 +857,19 @@ */ static switch_status_t openmrcp_asr_close(switch_asr_handle_t *ah, switch_asr_flag_t *flags) { - openmrcp_session_t *openmrcp_session = (openmrcp_session_t *) ah->private_info; + asr_session_t *asr_session = (asr_session_t *) ah->private_info; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "openmrcp_asr_close()\n"); - mrcp_client_context_t *context = openmrcp_module.mrcp_client_context; + mrcp_client_context_t *context = openmrcp_module.asr_client_context; // TODO!! should we do a switch_pool_clear(switch_memory_pool_t *p) on the pool held - // by openmrcp_session? + // by asr_session? // destroy channel switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Going to DESTROY CHANNEL\n"); - mrcp_client_context_channel_destroy(context, openmrcp_session->client_session, openmrcp_session->channel); - if (openmrcp_session_wait_for_event(openmrcp_session,OPENMRCP_EVENT_CHANNEL_DESTROY,10000) == MRCP_STATUS_SUCCESS) { + mrcp_client_context_channel_destroy(context, asr_session->client_session, asr_session->channel); + if (wait_for_event(asr_session->event_queue,OPENMRCP_EVENT_CHANNEL_DESTROY,10000) == MRCP_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "OPENMRCP_EVENT_CHANNEL_DESTROY received\n"); } else { @@ -665,8 +878,8 @@ // terminate client session switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Going to TERMINATE SESSION\n"); - mrcp_client_context_session_terminate(context, openmrcp_session->client_session); - if (openmrcp_session_wait_for_event(openmrcp_session,OPENMRCP_EVENT_SESSION_TERMINATE,10000) == MRCP_STATUS_SUCCESS) { + mrcp_client_context_session_terminate(context, asr_session->client_session); + if (wait_for_event(asr_session->event_queue,OPENMRCP_EVENT_SESSION_TERMINATE,10000) == MRCP_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "OPENMRCP_EVENT_SESSION_TERMINATE recevied\n"); } else { @@ -675,10 +888,10 @@ // destroy client session (NOTE: this sends a BYE to the other side) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Going to DESTROY SESSION\n"); - mrcp_client_context_session_destroy(context, openmrcp_session->client_session); + mrcp_client_context_session_destroy(context, asr_session->client_session); - // destroys the openmrcp_session struct - openmrcp_session_destroy(openmrcp_session); + // destroys the asr_session struct + asr_session_destroy(asr_session); switch_set_flag(ah, SWITCH_ASR_FLAG_CLOSED); @@ -694,9 +907,9 @@ */ static switch_status_t openmrcp_asr_check_results(switch_asr_handle_t *ah, switch_asr_flag_t *flags) { - openmrcp_session_t *openmrcp_session = (openmrcp_session_t *) ah->private_info; + asr_session_t *asr_session = (asr_session_t *) ah->private_info; - switch_status_t rv = (switch_test_flag(openmrcp_session, FLAG_HAS_TEXT) || switch_test_flag(openmrcp_session, FLAG_BARGE)) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; + switch_status_t rv = (switch_test_flag(asr_session, FLAG_HAS_TEXT) || switch_test_flag(asr_session, FLAG_BARGE)) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; return rv; } @@ -704,16 +917,16 @@ /*! This will be called after asr_check_results returns SUCCESS */ static switch_status_t openmrcp_asr_get_results(switch_asr_handle_t *ah, char **xmlstr, switch_asr_flag_t *flags) { - openmrcp_session_t *openmrcp_session = (openmrcp_session_t *) ah->private_info; + asr_session_t *asr_session = (asr_session_t *) ah->private_info; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "openmrcp_asr_get_results called\n"); switch_status_t ret = SWITCH_STATUS_SUCCESS; - if (switch_test_flag(openmrcp_session, FLAG_BARGE)) { - switch_clear_flag_locked(openmrcp_session, FLAG_BARGE); + if (switch_test_flag(asr_session, FLAG_BARGE)) { + switch_clear_flag_locked(asr_session, FLAG_BARGE); ret = SWITCH_STATUS_BREAK; } - if (switch_test_flag(openmrcp_session, FLAG_HAS_TEXT)) { + if (switch_test_flag(asr_session, FLAG_HAS_TEXT)) { /*! we have to extract the XML but stripping off the <?xml version="1.0"?> header. the body looks like: @@ -724,16 +937,15 @@ <?xml version="1.0"?> <result xmlns="http://www.ietf.org/xml/ns/mrcpv2" xmlns:ex="http://www.example.com/example" score="100" grammar="session:request1@form-level.store"> - <interpretation> - <input mode="speech">open a</input> + <interpretation> <input mode="speech">open a</input> </interpretation> </result> */ char *marker = "?>"; // FIXME -- lame and brittle way of doing this. use regex or better. - char *position = strstr(openmrcp_session->mrcp_message_last_rcvd->body, marker); + char *position = strstr(asr_session->mrcp_message_last_rcvd->body, marker); if (!position) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bad result received from mrcp server: %s", openmrcp_session->mrcp_message_last_rcvd->body); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bad result received from mrcp server: %s", asr_session->mrcp_message_last_rcvd->body); ret = SWITCH_STATUS_FALSE; } else { @@ -743,12 +955,236 @@ // since we are returning our result here, future calls to check_results // should return False - switch_clear_flag_locked(openmrcp_session, FLAG_HAS_TEXT); + switch_clear_flag_locked(asr_session, FLAG_HAS_TEXT); ret = SWITCH_STATUS_SUCCESS; } return ret; } + +static mrcp_status_t synth_speak(mrcp_client_context_t *context, tts_session_t *tts_session, char *text) +{ + + //buffer = (switch_byte_t *) switch_core_alloc(asr_session->pool, sizeof(switch_byte_t)*len); + char *text2speak; + const char xml_head[] = + "<?xml version=\"1.0\"?>\r\n" + "<speak>\r\n" + "<paragraph>\r\n" + " <sentence>"; + + const char xml_tail[] = "</sentence>\r\n" + "</paragraph>\r\n" + "</speak>\r\n"; + + size_t len = sizeof(xml_head) + sizeof(text) + sizeof(xml_tail); + text2speak = (char *) switch_core_alloc(tts_session->pool, len); + strcat(text2speak, xml_head); + strcat(text2speak, text); + strcat(text2speak, xml_tail); + + mrcp_generic_header_t *generic_header; + mrcp_message_t *mrcp_message = mrcp_client_context_message_get(context,tts_session->client_session,tts_session->channel,SYNTHESIZER_SPEAK); + if(!mrcp_message) { + return MRCP_STATUS_FAILURE; + } + + generic_header = mrcp_generic_header_prepare(mrcp_message); + if(!generic_header) { + return MRCP_STATUS_FAILURE; + } + + generic_header->content_type = mrcp_str_pdup(mrcp_message->pool,"application/synthesis+ssml"); + mrcp_generic_header_property_add(mrcp_message,GENERIC_HEADER_CONTENT_TYPE); + mrcp_message->body = mrcp_str_pdup(mrcp_message->pool,text2speak); + + return mrcp_client_context_channel_modify(context,tts_session->client_session,mrcp_message); +} + +static mrcp_status_t synth_stop(mrcp_client_context_t *context, tts_session_t *tts_session) +{ + mrcp_message_t *mrcp_message = mrcp_client_context_message_get(context,tts_session->client_session,tts_session->channel,SYNTHESIZER_STOP); + if(!mrcp_message) { + return MRCP_STATUS_FAILURE; + } + + return mrcp_client_context_channel_modify(context,tts_session->client_session,mrcp_message); +} + + +static switch_status_t openmrcp_tts_open(switch_speech_handle_t *sh, char *voice_name, int rate, switch_speech_flag_t *flags) +{ + + tts_session_t *tts_session; + audio_sink_t *sink; + mrcp_client_context_t *tts_client_context = openmrcp_module.tts_client_context ; + + /* create session */ + tts_session = tts_session_create(); + if (!tts_session) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "tts_session creation FAILED\n"); + return SWITCH_STATUS_GENERR; + } + tts_session->client_session = mrcp_client_context_session_create(tts_client_context,tts_session); + if (!tts_session->client_session) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "tts_session creation FAILED\n"); + return SWITCH_STATUS_GENERR; + } + + + /* create audio sink */ + sink = mrcp_palloc(tts_session->pool,sizeof(audio_sink_t)); + sink->method_set = &audio_sink_method_set; + sink->object = tts_session; + tts_session->sink = sink; + + + /** + * create a new fifo queue. + */ + if (switch_queue_create(&tts_session->audio_queue, 10000, tts_session->pool)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "audio queue creation failed\n"); + return SWITCH_STATUS_MEMERR; + } + + + tts_session->flags = *flags; + switch_mutex_init(&tts_session->flag_mutex, SWITCH_MUTEX_NESTED, tts_session->pool); + + sh->private_info = tts_session; + + return SWITCH_STATUS_SUCCESS; + +} + +static switch_status_t openmrcp_tts_close(switch_speech_handle_t *sh, switch_speech_flag_t *flags) +{ + tts_session_t *tts_session = (tts_session_t *) sh->private_info; + mrcp_client_context_t *tts_client_context = openmrcp_module.tts_client_context ; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "synth_stop\n"); + synth_stop(tts_client_context,tts_session); // TODO + wait_for_event(tts_session->event_queue,OPENMRCP_EVENT_CHANNEL_MODIFY,5000); + + /* terminate tts session */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Terminate tts_session\n"); + mrcp_client_context_session_terminate(tts_client_context,tts_session->client_session); + /* wait for tts session termination */ + wait_for_event(tts_session->event_queue,OPENMRCP_EVENT_SESSION_TERMINATE,10000); + + /* destroy demo session */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "destroy tts_session\n"); + mrcp_client_context_session_destroy(tts_client_context,tts_session->client_session); + tts_session_destroy(tts_session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t openmrcp_feed_tts(switch_speech_handle_t *sh, char *text, switch_speech_flag_t *flags) +{ + + tts_session_t *tts_session = (tts_session_t *) sh->private_info; + mrcp_client_context_t *tts_client_context = openmrcp_module.tts_client_context ; + audio_sink_t *sink = tts_session->sink; + + /* create synthesizer channel */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Create Synthesizer Channel\n"); + tts_session->channel = mrcp_client_synthesizer_channel_create(tts_client_context,tts_session->client_session,sink); + /* wait for synthesizer channel creation */ + if(wait_for_event(tts_session->event_queue,OPENMRCP_EVENT_CHANNEL_CREATE,5000) == MRCP_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got channel create event\n"); + wait_for_event(tts_session->event_queue,OPENMRCP_EVENT_NONE,1000); + /* speak */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Going to speak\n"); + synth_speak(tts_client_context,tts_session, text); + // wait_for_event(tts_session->event_queue,OPENMRCP_EVENT_CHANNEL_MODIFY,5000); + + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Never got channel create event.\n"); + return SWITCH_STATUS_FALSE; + } + + + + return SWITCH_STATUS_SUCCESS; +} + +static void openmrcp_flush_tts(switch_speech_handle_t *sh) +{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "flush_tts called\n"); +} + +/** + * Freeswitch calls this when its ready to read datalen bytes of data. + * + * TODO: check the blocking flag and act accordingly + */ +static switch_status_t openmrcp_read_tts(switch_speech_handle_t *sh, void *data, size_t *datalen, uint32_t *rate, switch_speech_flag_t *flags) +{ + media_frame_t *queue_frame = NULL; + tts_session_t *tts_session = (tts_session_t *) sh->private_info; + size_t len = *datalen; + size_t x = 0; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "openmrcp_read_tts, datalen: %d\n", len); + + if (switch_queue_trypop(tts_session->audio_queue, (void *) &queue_frame)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "could not pop from queue\n"); + //return SWITCH_STATUS_FALSE; + return SWITCH_STATUS_SUCCESS; + } + else { + + if (queue_frame->codec_frame.size != len) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "You must recompile openmrcp with #define CODEC_FRAME_TIME_BASE 20\n"); + return SWITCH_STATUS_FALSE; + } + + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "add_up queue_frame: %li\n", + add_up_buffer(queue_frame->codec_frame.buffer, len)); + + + + switch_byte_t *bytedata = (switch_byte_t *) data; + switch_byte_t *sourcedata = (switch_byte_t *) queue_frame->codec_frame.buffer; + + // memcpy(data, queue_frame->codec_frame.buffer, len); + for (int i=0; i<len; i++) { + *(bytedata + i) = sourcedata[i]; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "add_up bytedata: %li\n", + add_up_buffer(bytedata, len)); + + + + // assume openmrcp is using 8kz for now + *rate = 8000; + + return SWITCH_STATUS_SUCCESS; + } + + + return SWITCH_STATUS_FALSE; +} + +static void openmrcp_text_param_tts(switch_speech_handle_t *sh, char *param, char *val) +{ + +} + +static void openmrcp_numeric_param_tts(switch_speech_handle_t *sh, char *param, int val) +{ + +} + +static void openmrcp_float_param_tts(switch_speech_handle_t *sh, char *param, double val) +{ + +} + static switch_asr_interface_t openmrcp_asr_interface = { /*.interface_name*/ "openmrcp", /*.asr_open*/ openmrcp_asr_open, @@ -762,6 +1198,19 @@ /*.asr_get_results*/ openmrcp_asr_get_results }; +static switch_speech_interface_t openmrcp_tts_interface = { + /*.interface_name*/ "openmrcp", + /*.speech_open*/ openmrcp_tts_open, + /*.speech_close*/ openmrcp_tts_close, + /*.speech_feed_tts*/ openmrcp_feed_tts, + /*.speech_read_tts*/ openmrcp_read_tts, + /*.speech_flush_tts*/ openmrcp_flush_tts, + /*.speech_text_param_tts*/ openmrcp_text_param_tts, + /*.speech_numeric_param_tts*/ openmrcp_numeric_param_tts, + /*.speech_float_param_tts*/ openmrcp_float_param_tts, + +}; + static switch_loadable_module_interface_t openmrcp_module_interface = { /*.module_name */ modname, /*.endpoint_interface */ NULL, @@ -771,7 +1220,7 @@ /*.application_interface */ NULL, /*.api_interface */ NULL, /*.file_interface */ NULL, - /*.speech_interface */ NULL, + /*.speech_interface */ &openmrcp_tts_interface, /*.directory_interface */ NULL, /*.chat_interface */ NULL, /*.say_interface */ NULL, @@ -796,16 +1245,26 @@ char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); - if (!strcasecmp(var, "client_ip")) { - globals.client_ip = val; - } else if (!strcasecmp(var, "server_ip")) { - globals.server_ip = val; - } else if (!strcasecmp(var, "proto_version")) { - globals.proto_version =(uint32_t) atoi(val); - } else if (!strcasecmp(var, "client_port")) { - globals.client_port = (uint32_t) atoi(val); - } else if (!strcasecmp(var, "server_port")) { - globals.server_port = (uint32_t) atoi(val); + if (!strcasecmp(var, "asr_client_ip")) { + globals.asr_client_ip = val; + } else if (!strcasecmp(var, "asr_server_ip")) { + globals.asr_server_ip = val; + } else if (!strcasecmp(var, "asr_proto_version")) { + globals.asr_proto_version =(uint32_t) atoi(val); + } else if (!strcasecmp(var, "asr_client_port")) { + globals.asr_client_port = (uint32_t) atoi(val); + } else if (!strcasecmp(var, "asr_server_port")) { + globals.asr_server_port = (uint32_t) atoi(val); + } else if (!strcasecmp(var, "tts_client_ip")) { + globals.tts_client_ip = val; + } else if (!strcasecmp(var, "tts_server_ip")) { + globals.tts_server_ip = val; + } else if (!strcasecmp(var, "tts_proto_version")) { + globals.tts_proto_version =(uint32_t) atoi(val); + } else if (!strcasecmp(var, "tts_client_port")) { + globals.tts_client_port = (uint32_t) atoi(val); + } else if (!strcasecmp(var, "tts_server_port")) { + globals.tts_server_port = (uint32_t) atoi(val); } else if (!strcasecmp(var, "rtp_port_min")) { globals.rtp_port_min = (uint32_t) atoi(val); } else if (!strcasecmp(var, "rtp_port_max")) { @@ -822,44 +1281,86 @@ static switch_status_t mrcp_init() { /*! - Perform one-time initialization of client library + Perform one-time initialization of asr client library */ mrcp_mem_pool_t *pool; - mrcp_client_event_handler_t *client_event_handler; - mrcp_client_t *mrcp_client; - mrcp_client_context_t *mrcp_client_context; - openmrcp_client_options_t *options; + mrcp_client_event_handler_t *asr_event_handler; + mrcp_client_t *asr_client; + mrcp_client_context_t *asr_client_context; + openmrcp_client_options_t *asr_options; + + pool = mrcp_global_pool_get(); + asr_options = mrcp_palloc(pool,sizeof(openmrcp_client_options_t)); + asr_event_handler = mrcp_palloc(pool,sizeof(mrcp_client_event_handler_t)); + set_default_asr_options(asr_options); + + asr_event_handler->on_session_initiate = asr_on_session_initiate; + asr_event_handler->on_session_terminate = asr_on_session_terminate; + asr_event_handler->on_channel_add = asr_on_channel_add; + asr_event_handler->on_channel_remove = asr_on_channel_remove; + asr_event_handler->on_channel_modify = asr_on_channel_modify; + + // create asr client context, which to must be passed to client engine + asr_client_context = mrcp_client_context_create(&openmrcp_module,asr_event_handler); + if(!asr_client_context) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "asr_client_context creation failed\n"); + return SWITCH_STATUS_GENERR; + } + openmrcp_module.asr_client_context = asr_client_context; + + // this basically starts a thread that pulls events from the event queue + // and handles them + asr_client = openmrcp_client_start(asr_options,asr_client_context); + if(!asr_client) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "openasr_client_start FAILED\n"); + mrcp_client_context_destroy(asr_client_context); + return SWITCH_STATUS_GENERR; + } + + openmrcp_module.asr_client = asr_client; + + + /*! + Perform one-time initialization of tts client library + */ + + mrcp_client_event_handler_t *tts_event_handler; + mrcp_client_t *tts_client; + mrcp_client_context_t *tts_client_context; + openmrcp_client_options_t *tts_options; pool = mrcp_global_pool_get(); - options = mrcp_palloc(pool,sizeof(openmrcp_client_options_t)); - client_event_handler = mrcp_palloc(pool,sizeof(mrcp_client_event_handler_t)); - set_default_options(options); - - client_event_handler->on_session_initiate = openmrcp_on_session_initiate; - client_event_handler->on_session_terminate = openmrcp_on_session_terminate; - client_event_handler->on_channel_add = openmrcp_on_channel_add; - client_event_handler->on_channel_remove = openmrcp_on_channel_remove; - client_event_handler->on_channel_modify = openmrcp_on_channel_modify; - - // create client context, which to must be passed to client engine - mrcp_client_context = mrcp_client_context_create(&openmrcp_module,client_event_handler); - if(!mrcp_client_context) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mrcp_client_context creation failed\n"); + tts_options = mrcp_palloc(pool,sizeof(openmrcp_client_options_t)); + tts_event_handler = mrcp_palloc(pool,sizeof(mrcp_client_event_handler_t)); + set_default_tts_options(tts_options); + + tts_event_handler->on_session_initiate = tts_on_session_initiate; + tts_event_handler->on_session_terminate = tts_on_session_terminate; + tts_event_handler->on_channel_add = tts_on_channel_add; + tts_event_handler->on_channel_remove = tts_on_channel_remove; + tts_event_handler->on_channel_modify = tts_on_channel_modify; + + // create tts client context, which to must be passed to client engine + tts_client_context = mrcp_client_context_create(&openmrcp_module,tts_event_handler); + if(!tts_client_context) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "tts_client_context creation failed\n"); return SWITCH_STATUS_GENERR; } - openmrcp_module.mrcp_client_context = mrcp_client_context; + openmrcp_module.tts_client_context = tts_client_context; // this basically starts a thread that pulls events from the event queue // and handles them - mrcp_client = openmrcp_client_start(options,mrcp_client_context); - if(!mrcp_client) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "openmrcp_client_start FAILED\n"); - mrcp_client_context_destroy(mrcp_client_context); + tts_client = openmrcp_client_start(tts_options,tts_client_context); + if(!tts_client) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "opentts_client_start FAILED\n"); + mrcp_client_context_destroy(tts_client_context); return SWITCH_STATUS_GENERR; } - openmrcp_module.mrcp_client = mrcp_client; + openmrcp_module.tts_client = tts_client; + + return SWITCH_STATUS_SUCCESS; }
participants (1)
-
Freeswitch SVN