]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-5583 --resolve
authorAnthony Minessale <anthm@freeswitch.org>
Fri, 19 Jul 2013 19:02:58 +0000 (14:02 -0500)
committerAnthony Minessale <anthm@freeswitch.org>
Fri, 19 Jul 2013 19:02:58 +0000 (14:02 -0500)
src/include/switch_core.h
src/include/switch_module_interfaces.h
src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c
src/switch_core_asr.c
src/switch_ivr_async.c

index c3583e95556d9c27ac8d15b62cf1c831eb73847d..dfa1d39d7c08cc589346f8568816654c288e4749 100644 (file)
@@ -1967,6 +1967,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_asr_check_results(switch_asr_handle_
 */
 SWITCH_DECLARE(switch_status_t) switch_core_asr_get_results(switch_asr_handle_t *ah, char **xmlstr, switch_asr_flag_t *flags);
 
+/*!
+  \brief Get result headers from an asr handle
+  \param ah the handle to get results from
+  \param headers a pointer to dynamically allocate an switch_event_t result to
+  \param flags flags to influence behaviour
+  \return SWITCH_STATUS_SUCCESS
+*/
+SWITCH_DECLARE(switch_status_t) switch_core_asr_get_result_headers(switch_asr_handle_t *ah, switch_event_t **headers, switch_asr_flag_t *flags);
+
 /*!
   \brief Load a grammar to an asr handle
   \param ah the handle to load to
index cdfb9eb2e97bce91c60506a3824ce67d35720c30..b4ea5a4bc8b26d057e40d95d861bfc34d5f3c6ce 100644 (file)
@@ -377,6 +377,8 @@ struct switch_asr_interface {
        switch_status_t (*asr_check_results) (switch_asr_handle_t *ah, switch_asr_flag_t *flags);
        /*! function to read results from the ASR */
        switch_status_t (*asr_get_results) (switch_asr_handle_t *ah, char **xmlstr, switch_asr_flag_t *flags);
+       /*! function to read result headers from the ASR */
+       switch_status_t (*asr_get_result_headers) (switch_asr_handle_t *ah, switch_event_t **headers, switch_asr_flag_t *flags);
        /*! function to start ASR input timers */
        switch_status_t (*asr_start_input_timers) (switch_asr_handle_t *ah);
        void (*asr_text_param) (switch_asr_handle_t *ah, char *param, const char *val);
index d5007ee020d59536f43c30b04804ab632e1c9cf5..600ce37fe5f6b85d17cba6ba7608b54af5f3ce8d 100644 (file)
@@ -450,6 +450,8 @@ struct recognizer_data {
        switch_hash_t *enabled_grammars;
        /** recognize result */
        char *result;
+       /** recognize result headers */
+       switch_event_t *result_headers;
        /** true, if voice has started */
        int start_of_input;
        /** true, if input timers have started */
@@ -483,6 +485,7 @@ static switch_status_t recog_asr_resume(switch_asr_handle_t *ah);
 static switch_status_t recog_asr_pause(switch_asr_handle_t *ah);
 static switch_status_t recog_asr_check_results(switch_asr_handle_t *ah, switch_asr_flag_t *flags);
 static switch_status_t recog_asr_get_results(switch_asr_handle_t *ah, char **xmlstr, switch_asr_flag_t *flags);
+static switch_status_t recog_asr_get_result_headers(switch_asr_handle_t *ah, switch_event_t **headers, switch_asr_flag_t *flags);
 static switch_status_t recog_asr_start_input_timers(switch_asr_handle_t *ah);
 static void recog_asr_text_param(switch_asr_handle_t *ah, char *param, const char *val);
 static void recog_asr_numeric_param(switch_asr_handle_t *ah, char *param, int val);
@@ -505,7 +508,9 @@ static switch_status_t recog_channel_check_results(speech_channel_t *schannel);
 static switch_status_t recog_channel_set_start_of_input(speech_channel_t *schannel);
 static switch_status_t recog_channel_start_input_timers(speech_channel_t *schannel);
 static switch_status_t recog_channel_set_results(speech_channel_t *schannel, const char *results);
+static switch_status_t recog_channel_set_result_headers(speech_channel_t *schannel, mrcp_recog_header_t *recog_hdr);
 static switch_status_t recog_channel_get_results(speech_channel_t *schannel, char **results);
+static switch_status_t recog_channel_get_result_headers(speech_channel_t *schannel, switch_event_t **result_headers);
 static switch_status_t recog_channel_set_params(speech_channel_t *schannel, mrcp_message_t *msg, mrcp_generic_header_t *gen_hdr,
                                                                                                mrcp_recog_header_t *recog_hdr);
 static switch_status_t recog_channel_set_header(speech_channel_t *schannel, int id, char *val, mrcp_message_t *msg, mrcp_recog_header_t *recog_hdr);
@@ -2156,9 +2161,9 @@ static switch_status_t recog_channel_start(speech_channel_t *schannel)
        recognizer_data_t *r;
        char *start_input_timers;
        const char *mime_type;
-       char *key;
+       char *key = NULL;
        switch_size_t len;
-       grammar_t *grammar;
+       grammar_t *grammar = NULL;
        switch_size_t grammar_uri_count = 0;
        switch_size_t grammar_uri_list_len = 0;
        char *grammar_uri_list = NULL;
@@ -2176,6 +2181,9 @@ static switch_status_t recog_channel_start(speech_channel_t *schannel)
        }
        r = (recognizer_data_t *) schannel->data;
        r->result = NULL;
+       if (r->result_headers) {
+               switch_event_destroy(&r->result_headers);
+       }
        r->start_of_input = 0;
 
        /* input timers are started by default unless the start-input-timers=false param is set */
@@ -2598,6 +2606,141 @@ static switch_status_t recog_channel_set_results(speech_channel_t *schannel, con
        return status;
 }
 
+/**
+ * Find a parameter from a ;-separated string
+ *
+ * @param str the input string to find data in
+ * @param param the parameter to to look for
+ * @return a pointer in the str if successful, or NULL.
+ */
+static char *find_parameter(const char *str, const char *param)
+{
+       char *ptr = (char *) str;
+
+       while (ptr) {
+               if (!strncasecmp(ptr, param, strlen(param)))
+                       return ptr;
+
+               if ((ptr = strchr(ptr, ';')))
+                       ptr++;
+
+               while (ptr && *ptr == ' ') {
+                       ptr++;
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * Get a parameter value from a ;-separated string
+ *
+ * @param str the input string to parse data from
+ * @param param the parameter to to look for
+ * @return a malloc'ed char* if successful, or NULL.
+ */
+static char *get_parameter_value(const char *str, const char *param)
+{
+       const char *param_ptr;
+       char *param_value = NULL;
+       char *tmp;
+       switch_size_t param_len;
+       char *param_tmp;
+
+       if (zstr(str) || zstr(param)) return NULL;
+
+       /* Append "=" to the end of the string */
+       param_tmp = switch_mprintf("%s=", param);
+       if (!param_tmp) return NULL;
+       param = param_tmp;
+
+       param_len = strlen(param);
+       param_ptr = find_parameter(str, param);
+
+       if (zstr(param_ptr)) goto fail;
+
+       param_value = strdup(param_ptr + param_len);
+
+       if (zstr(param_value)) goto fail;
+
+       if ((tmp = strchr(param_value, ';'))) *tmp = '\0';
+
+       switch_safe_free(param_tmp);
+       return param_value;
+
+  fail:
+       switch_safe_free(param_tmp);
+       switch_safe_free(param_value);
+       return NULL;
+}
+
+/**
+ * Set the recognition result headers
+ *
+ * @param schannel the channel whose results are set
+ * @param recog_hdr the recognition headers
+ * @return SWITCH_STATUS_SUCCESS if successful
+ */
+static switch_status_t recog_channel_set_result_headers(speech_channel_t *schannel, mrcp_recog_header_t *recog_hdr)
+{
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+       recognizer_data_t *r;
+
+       switch_mutex_lock(schannel->mutex);
+
+       r = (recognizer_data_t *) schannel->data;
+
+       if (r->result_headers) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) result headers are already set\n", schannel->name);
+               status = SWITCH_STATUS_FALSE;
+               goto done;
+       }
+
+       if (!recog_hdr) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) result headers are NULL\n", schannel->name);
+               status = SWITCH_STATUS_FALSE;
+               goto done;
+       }
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) ASR adding result headers\n", schannel->name);
+
+       if ((status = switch_event_create(&r->result_headers, SWITCH_EVENT_CLONE)) == SWITCH_STATUS_SUCCESS) {
+
+               switch_event_add_header(r->result_headers, SWITCH_STACK_BOTTOM, "ASR-Completion-Cause", "%d", recog_hdr->completion_cause);
+
+               if (!zstr(recog_hdr->completion_reason.buf)) {
+                       switch_event_add_header_string(r->result_headers, SWITCH_STACK_BOTTOM, "ASR-Completion-Reason", recog_hdr->completion_reason.buf);
+               }
+
+               if (!zstr(recog_hdr->waveform_uri.buf)) {
+                       char *tmp;
+
+                       if ((tmp = strdup(recog_hdr->waveform_uri.buf))) {
+                               char *tmp2;
+                               if ((tmp2 = strchr(tmp, ';'))) *tmp2 = '\0';
+                               switch_event_add_header_string(r->result_headers, SWITCH_STACK_BOTTOM, "ASR-Waveform-URI", tmp);
+                               free(tmp);
+                       }
+
+                       if ((tmp = get_parameter_value(recog_hdr->waveform_uri.buf, "size"))) {
+                               switch_event_add_header_string(r->result_headers, SWITCH_STACK_BOTTOM, "ASR-Waveform-Size", tmp);
+                               free(tmp);
+                       }
+
+                       if ((tmp = get_parameter_value(recog_hdr->waveform_uri.buf, "duration"))) {
+                               switch_event_add_header_string(r->result_headers, SWITCH_STACK_BOTTOM, "ASR-Waveform-Duration", tmp);
+                               free(tmp);
+                       }
+               }
+       }
+
+  done:
+
+       switch_mutex_unlock(schannel->mutex);
+
+       return status;
+}
+
 /**
  * Get the recognition results.
  *
@@ -2627,6 +2770,29 @@ static switch_status_t recog_channel_get_results(speech_channel_t *schannel, cha
        return status;
 }
 
+/**
+ * Get the recognition result headers.
+ *
+ * @param schannel the channel to get results from
+ * @param result_headers the recognition result headers. switch_event_destroy() the results when finished with them.
+ * @return SWITCH_STATUS_SUCCESS will always be returned, since this is just optional data.
+ */
+static switch_status_t recog_channel_get_result_headers(speech_channel_t *schannel, switch_event_t **result_headers)
+{
+       recognizer_data_t *r = (recognizer_data_t *) schannel->data;
+
+       switch_mutex_lock(schannel->mutex);
+
+       if (r->result_headers && result_headers) {
+               *result_headers = r->result_headers;
+               r->result_headers = NULL;
+       }
+
+       switch_mutex_unlock(schannel->mutex);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
 /**
  * Set parameters in a recognizer MRCP header
  *
@@ -3207,6 +3373,9 @@ static switch_status_t recog_asr_close(switch_asr_handle_t *ah, switch_asr_flag_
                        r->dtmf_generator_active = 0;
                        mpf_dtmf_generator_destroy(r->dtmf_generator);
                }
+               if (r->result_headers) {
+                       switch_event_destroy(&r->result_headers);
+               }
                switch_mutex_unlock(schannel->mutex);
                speech_channel_destroy(schannel);
        }
@@ -3326,6 +3495,19 @@ static switch_status_t recog_asr_get_results(switch_asr_handle_t *ah, char **xml
        return recog_channel_get_results(schannel, xmlstr);
 }
 
+/**
+ * Process asr_get_result_headers request from FreeSWITCH.  Return the headers back
+ * to FreeSWITCH.  FreeSWITCH will switch_event_destroy() the headers.
+ *
+ * @param ah the FreeSWITCH speech recognition handle
+ * @param flags other flags
+ */
+static switch_status_t recog_asr_get_result_headers(switch_asr_handle_t *ah, switch_event_t **headers, switch_asr_flag_t *flags)
+{
+       speech_channel_t *schannel = (speech_channel_t *) ah->private_info;
+       return recog_channel_get_result_headers(schannel, headers);
+}
+
 /**
  * Send START-INPUT-TIMERS to executing recognition request
  * @param ah the handle to start timers on
@@ -3473,6 +3655,7 @@ static apt_bool_t recog_on_message_receive(mrcp_application_t *application, mrcp
                                                          recog_hdr->completion_cause);
                        if (message->body.length > 0) {
                                if (message->body.buf[message->body.length - 1] == '\0') {
+                                       recog_channel_set_result_headers(schannel, recog_hdr);
                                        recog_channel_set_results(schannel, message->body.buf);
                                } else {
                                        /* string is not null terminated */
@@ -3481,11 +3664,13 @@ static apt_bool_t recog_on_message_receive(mrcp_application_t *application, mrcp
                                                                          "(%s) Recognition result is not null-terminated.  Appending null terminator.\n", schannel->name);
                                        strncpy(result, message->body.buf, message->body.length);
                                        result[message->body.length] = '\0';
+                                       recog_channel_set_result_headers(schannel, recog_hdr);
                                        recog_channel_set_results(schannel, result);
                                }
                        } else {
                                char *completion_cause = switch_mprintf("Completion-Cause: %03d", recog_hdr->completion_cause);
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) No result\n", schannel->name);
+                               recog_channel_set_result_headers(schannel, recog_hdr);
                                recog_channel_set_results(schannel, completion_cause);
                                switch_safe_free(completion_cause);
                        }
@@ -3584,6 +3769,7 @@ static switch_status_t recog_load(switch_loadable_module_interface_t *module_int
        asr_interface->asr_pause = recog_asr_pause;
        asr_interface->asr_check_results = recog_asr_check_results;
        asr_interface->asr_get_results = recog_asr_get_results;
+       asr_interface->asr_get_result_headers = recog_asr_get_result_headers;
        asr_interface->asr_start_input_timers = recog_asr_start_input_timers;
        asr_interface->asr_text_param = recog_asr_text_param;
        asr_interface->asr_numeric_param = recog_asr_numeric_param;
@@ -3620,7 +3806,7 @@ static switch_status_t recog_load(switch_loadable_module_interface_t *module_int
        switch_core_hash_insert(globals.recog.param_id_map, "N-Best-List-Length", unimrcp_param_id_create(RECOGNIZER_HEADER_N_BEST_LIST_LENGTH, pool));
        switch_core_hash_insert(globals.recog.param_id_map, "No-Input-Timeout", unimrcp_param_id_create(RECOGNIZER_HEADER_NO_INPUT_TIMEOUT, pool));
        switch_core_hash_insert(globals.recog.param_id_map, "Recognition-Timeout", unimrcp_param_id_create(RECOGNIZER_HEADER_RECOGNITION_TIMEOUT, pool));
-       switch_core_hash_insert(globals.recog.param_id_map, "Waveform-Url", unimrcp_param_id_create(RECOGNIZER_HEADER_WAVEFORM_URI, pool));
+       switch_core_hash_insert(globals.recog.param_id_map, "Waveform-Uri", unimrcp_param_id_create(RECOGNIZER_HEADER_WAVEFORM_URI, pool));
        switch_core_hash_insert(globals.recog.param_id_map, "Completion-Cause", unimrcp_param_id_create(RECOGNIZER_HEADER_COMPLETION_CAUSE, pool));
        switch_core_hash_insert(globals.recog.param_id_map, "Recognizer-Context-Block",
                                                        unimrcp_param_id_create(RECOGNIZER_HEADER_RECOGNIZER_CONTEXT_BLOCK, pool));
index 6c13c7b697c25929cb352f653f3705b918837d06..08590d6a3d9f65fe506dda54bf45bb3231b41e62 100644 (file)
@@ -299,6 +299,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_asr_get_results(switch_asr_handle_t
        return ah->asr_interface->asr_get_results(ah, xmlstr, flags);
 }
 
+SWITCH_DECLARE(switch_status_t) switch_core_asr_get_result_headers(switch_asr_handle_t *ah, switch_event_t **headers, switch_asr_flag_t *flags)
+{
+       switch_assert(ah != NULL);
+
+       if (ah->asr_interface->asr_get_result_headers) {
+               return ah->asr_interface->asr_get_result_headers(ah, headers, flags);
+       } else {
+               /* Since this is not always implemented, return success if the function can't be called */
+               return SWITCH_STATUS_SUCCESS;
+       }
+}
+
 SWITCH_DECLARE(switch_status_t) switch_core_asr_start_input_timers(switch_asr_handle_t *ah)
 {
        switch_status_t status = SWITCH_STATUS_SUCCESS;
index 8e5a451e7ebc2c99824cdb6d357dae2200cf2ac1..b36e7dfa7283c8775b824540922ead1a860d8ed5 100644 (file)
@@ -3791,6 +3791,7 @@ static void *SWITCH_THREAD_FUNC speech_thread(switch_thread_t *thread, void *obj
 
        while (switch_channel_up_nosig(channel) && !switch_test_flag(sth->ah, SWITCH_ASR_FLAG_CLOSED)) {
                char *xmlstr = NULL;
+               switch_event_t *headers = NULL;
 
                switch_thread_cond_wait(sth->cond, sth->mutex);
 
@@ -3804,6 +3805,9 @@ static void *SWITCH_THREAD_FUNC speech_thread(switch_thread_t *thread, void *obj
 
                        if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
                                goto done;
+                       } else if (status == SWITCH_STATUS_SUCCESS) {
+                               /* Try to fetch extra information for this result, the return value doesn't really matter here - it's just optional data. */
+                               switch_core_asr_get_result_headers(sth->ah, &headers, &flags);
                        }
 
                        if (status == SWITCH_STATUS_SUCCESS && switch_true(switch_channel_get_variable(channel, "asr_intercept_dtmf"))) {
@@ -3853,6 +3857,11 @@ static void *SWITCH_THREAD_FUNC speech_thread(switch_thread_t *thread, void *obj
                        if (switch_event_create(&event, SWITCH_EVENT_DETECTED_SPEECH) == SWITCH_STATUS_SUCCESS) {
                                if (status == SWITCH_STATUS_SUCCESS) {
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "detected-speech");
+
+                                       if (headers) {
+                                               switch_event_merge(event, headers);
+                                       }
+
                                        switch_event_add_body(event, "%s", xmlstr);
                                } else {
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "begin-speaking");
@@ -3876,6 +3885,10 @@ static void *SWITCH_THREAD_FUNC speech_thread(switch_thread_t *thread, void *obj
                        }
 
                        switch_safe_free(xmlstr);
+
+                       if (headers) {
+                               switch_event_destroy(&headers);
+                       }
                }
        }
   done: