MERGE: OpenMethods ASR enhancements: multiple concurrent grammars and dialplan access to start-input-timers

This commit is contained in:
Luke Dashjr 2011-01-26 14:54:36 -06:00
commit 89253a1391
7 changed files with 390 additions and 27 deletions

View File

@ -24,6 +24,7 @@
* Contributor(s): * Contributor(s):
* *
* Anthony Minessale II <anthm@freeswitch.org> * Anthony Minessale II <anthm@freeswitch.org>
* Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
* *
* *
* switch_core.h -- Core Library * switch_core.h -- Core Library
@ -1768,6 +1769,29 @@ SWITCH_DECLARE(switch_status_t) switch_core_asr_load_grammar(switch_asr_handle_t
*/ */
SWITCH_DECLARE(switch_status_t) switch_core_asr_unload_grammar(switch_asr_handle_t *ah, const char *name); SWITCH_DECLARE(switch_status_t) switch_core_asr_unload_grammar(switch_asr_handle_t *ah, const char *name);
/*!
\brief Enable a grammar from an asr handle
\param ah the handle to enable the grammar from
\param name the name of the grammar to enable
\return SWITCH_STATUS_SUCCESS
*/
SWITCH_DECLARE(switch_status_t) switch_core_asr_enable_grammar(switch_asr_handle_t *ah, const char *name);
/*!
\brief Disable a grammar from an asr handle
\param ah the handle to disable the grammar from
\param name the name of the grammar to disable
\return SWITCH_STATUS_SUCCESS
*/
SWITCH_DECLARE(switch_status_t) switch_core_asr_disable_grammar(switch_asr_handle_t *ah, const char *name);
/*!
\brief Disable all grammars from an asr handle
\param ah the handle to disable the grammars from
\return SWITCH_STATUS_SUCCESS
*/
SWITCH_DECLARE(switch_status_t) switch_core_asr_disable_all_grammars(switch_asr_handle_t *ah);
/*! /*!
\brief Pause detection on an asr handle \brief Pause detection on an asr handle
\param ah the handle to pause \param ah the handle to pause

View File

@ -26,6 +26,7 @@
* Anthony Minessale II <anthm@freeswitch.org> * Anthony Minessale II <anthm@freeswitch.org>
* Neal Horman <neal at wanlink dot com> * Neal Horman <neal at wanlink dot com>
* Bret McDanel <trixter AT 0xdecafbad dot com> * Bret McDanel <trixter AT 0xdecafbad dot com>
* Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
* *
* switch_ivr.h -- IVR Library * switch_ivr.h -- IVR Library
* *
@ -198,8 +199,38 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_load_grammar(switch_cor
*/ */
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_unload_grammar(switch_core_session_t *session, const char *name); SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_unload_grammar(switch_core_session_t *session, const char *name);
/*!
\brief Enable a grammar on a background speech detection handle
\param session The session to change the grammar on
\param name the grammar name
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_enable_grammar(switch_core_session_t *session, const char *name);
/*!
\brief Disable a grammar on a background speech detection handle
\param session The session to change the grammar on
\param name the grammar name
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_disable_grammar(switch_core_session_t *session, const char *name);
/*!
\brief Disable all grammars on a background speech detection handle
\param session The session to change the grammar on
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_disable_all_grammars(switch_core_session_t *session);
SWITCH_DECLARE(switch_status_t) switch_ivr_set_param_detect_speech(switch_core_session_t *session, const char *name, const char *val); SWITCH_DECLARE(switch_status_t) switch_ivr_set_param_detect_speech(switch_core_session_t *session, const char *name, const char *val);
/*!
\brief Start input timers on a background speech detection handle
\param session The session to start the timers on
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_start_input_timers(switch_core_session_t *session);
/*! /*!
\brief Record a session to disk \brief Record a session to disk
\param session the session to record \param session the session to record

View File

@ -24,6 +24,7 @@
* Contributor(s): * Contributor(s):
* *
* Anthony Minessale II <anthm@freeswitch.org> * Anthony Minessale II <anthm@freeswitch.org>
* Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
* *
* *
* switch_module_interfaces.h -- Module Interface Definitions * switch_module_interfaces.h -- Module Interface Definitions
@ -396,6 +397,12 @@ struct switch_asr_interface {
switch_mutex_t *reflock; switch_mutex_t *reflock;
switch_loadable_module_interface_t *parent; switch_loadable_module_interface_t *parent;
struct switch_asr_interface *next; struct switch_asr_interface *next;
/*! function to enable a grammar to the asr interface */
switch_status_t (*asr_enable_grammar) (switch_asr_handle_t *ah, const char *name);
/*! function to disable a grammar to the asr interface */
switch_status_t (*asr_disable_grammar) (switch_asr_handle_t *ah, const char *name);
/*! function to disable all grammars to the asr interface */
switch_status_t (*asr_disable_all_grammars) (switch_asr_handle_t *ah);
}; };
/*! an abstract representation of an asr speech interface. */ /*! an abstract representation of an asr speech interface. */

View File

@ -28,6 +28,7 @@
* Michael Murdock <mike at mmurdock dot org> * Michael Murdock <mike at mmurdock dot org>
* Neal Horman <neal at wanlink dot com> * Neal Horman <neal at wanlink dot com>
* Bret McDanel <trixter AT 0xdecafbad dot com> * Bret McDanel <trixter AT 0xdecafbad dot com>
* Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
* *
* mod_dptools.c -- Raw Audio File Streaming Application Module * mod_dptools.c -- Raw Audio File Streaming Application Module
* *
@ -269,7 +270,7 @@ SWITCH_STANDARD_APP(bind_digit_action_function)
} }
#define DETECT_SPEECH_SYNTAX "<mod_name> <gram_name> <gram_path> [<addr>] OR grammar <gram_name> [<path>] OR nogrammar <gram_name> OR pause OR resume OR stop OR param <name> <value>" #define DETECT_SPEECH_SYNTAX "<mod_name> <gram_name> <gram_path> [<addr>] OR grammar <gram_name> [<path>] OR nogrammar <gram_name> OR grammaron/grammaroff <gram_name> OR grammarsalloff OR pause OR resume OR start_input_timers OR stop OR param <name> <value>"
SWITCH_STANDARD_APP(detect_speech_function) SWITCH_STANDARD_APP(detect_speech_function)
{ {
char *argv[4]; char *argv[4];
@ -282,6 +283,12 @@ SWITCH_STANDARD_APP(detect_speech_function)
switch_ivr_detect_speech_load_grammar(session, argv[1], argv[2]); switch_ivr_detect_speech_load_grammar(session, argv[1], argv[2]);
} else if (!strcasecmp(argv[0], "nogrammar")) { } else if (!strcasecmp(argv[0], "nogrammar")) {
switch_ivr_detect_speech_unload_grammar(session, argv[1]); switch_ivr_detect_speech_unload_grammar(session, argv[1]);
} else if (!strcasecmp(argv[0], "grammaron")) {
switch_ivr_detect_speech_enable_grammar(session, argv[1]);
} else if (!strcasecmp(argv[0], "grammaroff")) {
switch_ivr_detect_speech_disable_grammar(session, argv[1]);
} else if (!strcasecmp(argv[0], "grammarsalloff")) {
switch_ivr_detect_speech_disable_all_grammars(session);
} else if (!strcasecmp(argv[0], "pause")) { } else if (!strcasecmp(argv[0], "pause")) {
switch_ivr_pause_detect_speech(session); switch_ivr_pause_detect_speech(session);
} else if (!strcasecmp(argv[0], "resume")) { } else if (!strcasecmp(argv[0], "resume")) {
@ -290,6 +297,8 @@ SWITCH_STANDARD_APP(detect_speech_function)
switch_ivr_stop_detect_speech(session); switch_ivr_stop_detect_speech(session);
} else if (!strcasecmp(argv[0], "param")) { } else if (!strcasecmp(argv[0], "param")) {
switch_ivr_set_param_detect_speech(session, argv[1], argv[2]); switch_ivr_set_param_detect_speech(session, argv[1], argv[2]);
} else if (!strcasecmp(argv[0], "start_input_timers")) {
switch_ivr_detect_speech_start_input_timers(session);
} else if (argc >= 3) { } else if (argc >= 3) {
switch_ivr_detect_speech(session, argv[0], argv[1], argv[2], argv[3], NULL); switch_ivr_detect_speech(session, argv[0], argv[1], argv[2], argv[3], NULL);
} }

View File

@ -26,6 +26,7 @@
* *
* Brian West <brian@freeswitch.org> * Brian West <brian@freeswitch.org>
* Christopher M. Rienzo <chris@rienzo.net> * Christopher M. Rienzo <chris@rienzo.net>
* Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
* *
* mod_unimrcp.c -- UniMRCP module (MRCP client) * mod_unimrcp.c -- UniMRCP module (MRCP client)
* *
@ -433,8 +434,8 @@ static const char *grammar_type_to_mime(grammar_type_t type, profile_t *profile)
struct recognizer_data { struct recognizer_data {
/** the available grammars */ /** the available grammars */
switch_hash_t *grammars; switch_hash_t *grammars;
/** the last grammar used (for pause/resume) */ /** the enabled grammars */
grammar_t *last_grammar; switch_hash_t *enabled_grammars;
/** recognize result */ /** recognize result */
char *result; char *result;
/** true, if voice has started */ /** true, if voice has started */
@ -451,6 +452,9 @@ static switch_status_t recog_shutdown();
static switch_status_t recog_asr_open(switch_asr_handle_t *ah, const char *codec, int rate, const char *dest, switch_asr_flag_t *flags); static switch_status_t recog_asr_open(switch_asr_handle_t *ah, const char *codec, int rate, const char *dest, switch_asr_flag_t *flags);
static switch_status_t recog_asr_load_grammar(switch_asr_handle_t *ah, const char *grammar, const char *name); static switch_status_t recog_asr_load_grammar(switch_asr_handle_t *ah, const char *grammar, const char *name);
static switch_status_t recog_asr_unload_grammar(switch_asr_handle_t *ah, const char *name); static switch_status_t recog_asr_unload_grammar(switch_asr_handle_t *ah, const char *name);
static switch_status_t recog_asr_enable_grammar(switch_asr_handle_t *ah, const char *name);
static switch_status_t recog_asr_disable_grammar(switch_asr_handle_t *ah, const char *name);
static switch_status_t recog_asr_disable_all_grammars(switch_asr_handle_t *ah);
static switch_status_t recog_asr_close(switch_asr_handle_t *ah, switch_asr_flag_t *flags); static switch_status_t recog_asr_close(switch_asr_handle_t *ah, switch_asr_flag_t *flags);
static switch_status_t recog_asr_feed(switch_asr_handle_t *ah, void *data, unsigned int len, switch_asr_flag_t *flags); static switch_status_t recog_asr_feed(switch_asr_handle_t *ah, void *data, unsigned int len, switch_asr_flag_t *flags);
#if 0 #if 0
@ -471,9 +475,12 @@ static apt_bool_t recog_on_message_receive(mrcp_application_t *application, mrcp
static apt_bool_t recog_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame); static apt_bool_t recog_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame);
/* recognizer specific speech_channel_funcs */ /* recognizer specific speech_channel_funcs */
static switch_status_t recog_channel_start(speech_channel_t *schannel, const char *name); static switch_status_t recog_channel_start(speech_channel_t *schannel);
static switch_status_t recog_channel_load_grammar(speech_channel_t *schannel, const char *name, grammar_type_t type, const char *data); static switch_status_t recog_channel_load_grammar(speech_channel_t *schannel, const char *name, grammar_type_t type, const char *data);
static switch_status_t recog_channel_unload_grammar(speech_channel_t *schannel, const char *name); static switch_status_t recog_channel_unload_grammar(speech_channel_t *schannel, const char *name);
static switch_status_t recog_channel_enable_grammar(speech_channel_t *schannel, const char *name);
static switch_status_t recog_channel_disable_grammar(speech_channel_t *schannel, const char *name);
static switch_status_t recog_channel_disable_all_grammars(speech_channel_t *schannel);
static switch_status_t recog_channel_check_results(speech_channel_t *schannel); 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_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_start_input_timers(speech_channel_t *schannel);
@ -2055,19 +2062,24 @@ static const char *grammar_type_to_mime(grammar_type_t type, profile_t *profile)
* Start RECOGNIZE request * Start RECOGNIZE request
* *
* @param schannel the channel to start * @param schannel the channel to start
* @param name the name of the grammar to use or NULL if to reuse the last grammar
* @return SWITCH_STATUS_SUCCESS if successful * @return SWITCH_STATUS_SUCCESS if successful
*/ */
static switch_status_t recog_channel_start(speech_channel_t *schannel, const char *name) static switch_status_t recog_channel_start(speech_channel_t *schannel)
{ {
switch_status_t status = SWITCH_STATUS_SUCCESS; switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_hash_index_t *egk;
mrcp_message_t *mrcp_message; mrcp_message_t *mrcp_message;
mrcp_recog_header_t *recog_header; mrcp_recog_header_t *recog_header;
mrcp_generic_header_t *generic_header; mrcp_generic_header_t *generic_header;
recognizer_data_t *r; recognizer_data_t *r;
char *start_input_timers; char *start_input_timers;
const char *mime_type; const char *mime_type;
grammar_t *grammar = NULL; char *key;
switch_size_t len;
grammar_t *grammar;
switch_size_t grammar_uri_count = 0;
switch_size_t grammar_uri_list_len = 0;
char *grammar_uri_list = NULL;
switch_mutex_lock(schannel->mutex); switch_mutex_lock(schannel->mutex);
if (schannel->state != SPEECH_CHANNEL_READY) { if (schannel->state != SPEECH_CHANNEL_READY) {
@ -2088,22 +2100,56 @@ static switch_status_t recog_channel_start(speech_channel_t *schannel, const cha
start_input_timers = (char *) switch_core_hash_find(schannel->params, "start-input-timers"); start_input_timers = (char *) switch_core_hash_find(schannel->params, "start-input-timers");
r->timers_started = zstr(start_input_timers) || strcasecmp(start_input_timers, "false"); r->timers_started = zstr(start_input_timers) || strcasecmp(start_input_timers, "false");
/* get the cached grammar */ /* count enabled grammars */
if (zstr(name)) { for (egk = switch_hash_first(NULL, r->enabled_grammars); egk; egk = switch_hash_next(egk)) {
grammar = r->last_grammar; // NOTE: This postponed type check is necessary to allow a non-URI-list grammar to execute alone
} else { if (grammar_uri_count == 1 && grammar->type != GRAMMAR_TYPE_URI)
grammar = (grammar_t *) switch_core_hash_find(r->grammars, name); goto no_grammar_alone;
r->last_grammar = grammar; ++grammar_uri_count;
} switch_hash_this(egk, (void *) &key, NULL, (void *) &grammar);
if (grammar == NULL) { if (grammar->type != GRAMMAR_TYPE_URI && grammar_uri_count != 1) {
if (name) { no_grammar_alone:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "(%s) Undefined grammar, %s\n", schannel->name, name); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "(%s) Grammar '%s' can only be used alone (not a URI list)\n", schannel->name, key);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "(%s) No grammar specified\n", schannel->name);
}
status = SWITCH_STATUS_FALSE; status = SWITCH_STATUS_FALSE;
goto done; goto done;
} }
len = strlen(grammar->data);
if (!len)
continue;
grammar_uri_list_len += len;
if (grammar->data[len - 1] != '\n')
grammar_uri_list_len += 2;
}
switch (grammar_uri_count) {
case 0:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "(%s) No grammar specified\n", schannel->name);
status = SWITCH_STATUS_FALSE;
goto done;
case 1:
/* grammar should already be the unique grammar */
break;
default:
/* get the enabled grammars list */
grammar_uri_list = switch_core_alloc(schannel->memory_pool, grammar_uri_list_len + 1);
grammar_uri_list_len = 0;
for (egk = switch_hash_first(NULL, r->enabled_grammars); egk; egk = switch_hash_next(egk)) {
switch_hash_this(egk, (void *) &key, NULL, (void *) &grammar);
len = strlen(grammar->data);
if (!len)
continue;
memcpy(&(grammar_uri_list[grammar_uri_list_len]), grammar->data, len);
grammar_uri_list_len += len;
if (grammar_uri_list[grammar_uri_list_len - 1] != '\n')
{
grammar_uri_list_len += 2;
grammar_uri_list[grammar_uri_list_len - 2] = '\r';
grammar_uri_list[grammar_uri_list_len - 1] = '\n';
}
}
grammar_uri_list[grammar_uri_list_len++] = '\0';
grammar = NULL;
}
/* create MRCP message */ /* create MRCP message */
mrcp_message = mrcp_application_message_create(schannel->unimrcp_session, schannel->unimrcp_channel, RECOGNIZER_RECOGNIZE); mrcp_message = mrcp_application_message_create(schannel->unimrcp_session, schannel->unimrcp_channel, RECOGNIZER_RECOGNIZE);
@ -2120,7 +2166,7 @@ static switch_status_t recog_channel_start(speech_channel_t *schannel, const cha
} }
/* set Content-Type */ /* set Content-Type */
mime_type = grammar_type_to_mime(grammar->type, schannel->profile); mime_type = grammar_type_to_mime(grammar ? grammar->type : GRAMMAR_TYPE_URI, schannel->profile);
if (zstr(mime_type)) { if (zstr(mime_type)) {
status = SWITCH_STATUS_FALSE; status = SWITCH_STATUS_FALSE;
goto done; goto done;
@ -2129,7 +2175,7 @@ static switch_status_t recog_channel_start(speech_channel_t *schannel, const cha
mrcp_generic_header_property_add(mrcp_message, GENERIC_HEADER_CONTENT_TYPE); mrcp_generic_header_property_add(mrcp_message, GENERIC_HEADER_CONTENT_TYPE);
/* set Content-ID for inline grammars */ /* set Content-ID for inline grammars */
if (grammar->type != GRAMMAR_TYPE_URI) { if (grammar && grammar->type != GRAMMAR_TYPE_URI) {
apt_string_assign(&generic_header->content_id, grammar->name, mrcp_message->pool); apt_string_assign(&generic_header->content_id, grammar->name, mrcp_message->pool);
mrcp_generic_header_property_add(mrcp_message, GENERIC_HEADER_CONTENT_ID); mrcp_generic_header_property_add(mrcp_message, GENERIC_HEADER_CONTENT_ID);
} }
@ -2151,7 +2197,7 @@ static switch_status_t recog_channel_start(speech_channel_t *schannel, const cha
recog_channel_set_params(schannel, mrcp_message, generic_header, recog_header); recog_channel_set_params(schannel, mrcp_message, generic_header, recog_header);
/* set message body */ /* set message body */
apt_string_assign(&mrcp_message->body, grammar->data, mrcp_message->pool); apt_string_assign(&mrcp_message->body, grammar ? grammar->data : grammar_uri_list, mrcp_message->pool);
/* Empty audio queue and send RECOGNIZE to MRCP server */ /* Empty audio queue and send RECOGNIZE to MRCP server */
audio_queue_clear(schannel->audio_queue); audio_queue_clear(schannel->audio_queue);
@ -2286,12 +2332,84 @@ static switch_status_t recog_channel_unload_grammar(speech_channel_t *schannel,
} else { } else {
recognizer_data_t *r = (recognizer_data_t *) schannel->data; recognizer_data_t *r = (recognizer_data_t *) schannel->data;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) Unloading grammar %s\n", schannel->name, grammar_name); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) Unloading grammar %s\n", schannel->name, grammar_name);
switch_core_hash_delete(r->enabled_grammars, grammar_name);
switch_core_hash_delete(r->grammars, grammar_name); switch_core_hash_delete(r->grammars, grammar_name);
} }
return status; return status;
} }
/**
* Enable speech recognition grammar
*
* @param schannel the recognizer channel
* @param grammar_name the name of the grammar to enable
* @return SWITCH_STATUS_SUCCESS if successful
*/
static switch_status_t recog_channel_enable_grammar(speech_channel_t *schannel, const char *grammar_name)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
if (zstr(grammar_name)) {
status = SWITCH_STATUS_FALSE;
} else {
recognizer_data_t *r = (recognizer_data_t *) schannel->data;
grammar_t *grammar;
grammar = (grammar_t *) switch_core_hash_find(r->grammars, grammar_name);
if (grammar == NULL)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "(%s) Undefined grammar, %s\n", schannel->name, grammar_name);
status = SWITCH_STATUS_FALSE;
}
else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) Enabling grammar %s\n", schannel->name, grammar_name);
switch_core_hash_insert(r->enabled_grammars, grammar_name, grammar);
}
}
return status;
}
/**
* Disable speech recognition grammar
*
* @param schannel the recognizer channel
* @param grammar_name the name of the grammar to disable
* @return SWITCH_STATUS_SUCCESS if successful
*/
static switch_status_t recog_channel_disable_grammar(speech_channel_t *schannel, const char *grammar_name)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
if (zstr(grammar_name)) {
status = SWITCH_STATUS_FALSE;
} else {
recognizer_data_t *r = (recognizer_data_t *) schannel->data;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) Disabling grammar %s\n", schannel->name, grammar_name);
switch_core_hash_delete(r->enabled_grammars, grammar_name);
}
return status;
}
/**
* Disable all speech recognition grammars
*
* @param schannel the recognizer channel
* @return SWITCH_STATUS_SUCCESS if successful
*/
static switch_status_t recog_channel_disable_all_grammars(speech_channel_t *schannel)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
recognizer_data_t *r = (recognizer_data_t *) schannel->data;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) Disabling all grammars\n", schannel->name);
switch_core_hash_destroy(&r->enabled_grammars);
switch_core_hash_init(&r->enabled_grammars, schannel->memory_pool);
return status;
}
/** /**
* Check if recognition is complete * Check if recognition is complete
* *
@ -2451,6 +2569,8 @@ static switch_status_t recog_channel_set_params(speech_channel_t *schannel, mrcp
if (id) { if (id) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) \"%s\": \"%s\"\n", schannel->name, param_name, param_val); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) \"%s\": \"%s\"\n", schannel->name, param_name, param_val);
recog_channel_set_header(schannel, id->id, param_val, msg, recog_hdr); recog_channel_set_header(schannel, id->id, param_val, msg, recog_hdr);
} else if (!strcasecmp(param_name, "start-recognize")) {
// This parameter is used internally only, not in MRCP headers
} else { } else {
/* this is probably a vendor-specific MRCP param */ /* this is probably a vendor-specific MRCP param */
apt_str_t apt_param_name = { 0 }; apt_str_t apt_param_name = { 0 };
@ -2737,6 +2857,7 @@ static switch_status_t recog_asr_open(switch_asr_handle_t *ah, const char *codec
schannel->data = r; schannel->data = r;
memset(r, 0, sizeof(recognizer_data_t)); memset(r, 0, sizeof(recognizer_data_t));
switch_core_hash_init(&r->grammars, ah->memory_pool); switch_core_hash_init(&r->grammars, ah->memory_pool);
switch_core_hash_init(&r->enabled_grammars, ah->memory_pool);
/* Open the channel */ /* Open the channel */
if (zstr(profile_name)) { if (zstr(profile_name)) {
@ -2782,6 +2903,7 @@ static switch_status_t recog_asr_load_grammar(switch_asr_handle_t *ah, const cha
speech_channel_t *schannel = (speech_channel_t *) ah->private_info; speech_channel_t *schannel = (speech_channel_t *) ah->private_info;
const char *grammar_data = NULL; const char *grammar_data = NULL;
char *grammar_file_data = NULL; char *grammar_file_data = NULL;
char *start_recognize;
switch_file_t *grammar_file = NULL; switch_file_t *grammar_file = NULL;
switch_size_t grammar_file_size = 0, to_read = 0; switch_size_t grammar_file_size = 0, to_read = 0;
grammar_type_t type = GRAMMAR_TYPE_UNKNOWN; grammar_type_t type = GRAMMAR_TYPE_UNKNOWN;
@ -2886,7 +3008,19 @@ static switch_status_t recog_asr_load_grammar(switch_asr_handle_t *ah, const cha
goto done; goto done;
} }
status = recog_channel_start(schannel, name); start_recognize = (char *) switch_core_hash_find(schannel->params, "start-recognize");
if (zstr(start_recognize) || strcasecmp(start_recognize, "false"))
{
if (recog_channel_disable_all_grammars(schannel) != SWITCH_STATUS_SUCCESS) {
status = SWITCH_STATUS_FALSE;
goto done;
}
if (recog_channel_enable_grammar(schannel, name) != SWITCH_STATUS_SUCCESS) {
status = SWITCH_STATUS_FALSE;
goto done;
}
status = recog_channel_start(schannel);
}
done: done:
@ -2914,6 +3048,57 @@ static switch_status_t recog_asr_unload_grammar(switch_asr_handle_t *ah, const c
return status; return status;
} }
/**
* Process asr_enable_grammar request from FreeSWITCH.
*
* FreeSWITCH sends this request to enable recognition on this grammar.
* @param ah the FreeSWITCH speech recognition handle
* @param name the grammar name.
*/
static switch_status_t recog_asr_enable_grammar(switch_asr_handle_t *ah, const char *name)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
speech_channel_t *schannel = (speech_channel_t *) ah->private_info;
if (zstr(name) || speech_channel_stop(schannel) != SWITCH_STATUS_SUCCESS || recog_channel_enable_grammar(schannel, name) != SWITCH_STATUS_SUCCESS) {
status = SWITCH_STATUS_FALSE;
}
return status;
}
/**
* Process asr_disable_grammar request from FreeSWITCH.
*
* FreeSWITCH sends this request to disable recognition on this grammar.
* @param ah the FreeSWITCH speech recognition handle
* @param name the grammar name.
*/
static switch_status_t recog_asr_disable_grammar(switch_asr_handle_t *ah, const char *name)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
speech_channel_t *schannel = (speech_channel_t *) ah->private_info;
if (zstr(name) || speech_channel_stop(schannel) != SWITCH_STATUS_SUCCESS || recog_channel_disable_grammar(schannel, name) != SWITCH_STATUS_SUCCESS) {
status = SWITCH_STATUS_FALSE;
}
return status;
}
/**
* Process asr_disable_all_grammars request from FreeSWITCH.
*
* FreeSWITCH sends this request to disable recognition of all grammars.
* @param ah the FreeSWITCH speech recognition handle
* @param name the grammar name.
*/
static switch_status_t recog_asr_disable_all_grammars(switch_asr_handle_t *ah)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
speech_channel_t *schannel = (speech_channel_t *) ah->private_info;
if (speech_channel_stop(schannel) != SWITCH_STATUS_SUCCESS || recog_channel_disable_all_grammars(schannel) != SWITCH_STATUS_SUCCESS) {
status = SWITCH_STATUS_FALSE;
}
return status;
}
/** /**
* Process asr_close request from FreeSWITCH * Process asr_close request from FreeSWITCH
* *
@ -2928,6 +3113,7 @@ static switch_status_t recog_asr_close(switch_asr_handle_t *ah, switch_asr_flag_
speech_channel_stop(schannel); speech_channel_stop(schannel);
speech_channel_destroy(schannel); speech_channel_destroy(schannel);
switch_core_hash_destroy(&r->grammars); switch_core_hash_destroy(&r->grammars);
switch_core_hash_destroy(&r->enabled_grammars);
/* this lets FreeSWITCH's speech_thread know the handle is closed */ /* this lets FreeSWITCH's speech_thread know the handle is closed */
switch_set_flag(ah, SWITCH_ASR_FLAG_CLOSED); switch_set_flag(ah, SWITCH_ASR_FLAG_CLOSED);
@ -2952,14 +3138,13 @@ static switch_status_t recog_asr_feed(switch_asr_handle_t *ah, void *data, unsig
/** /**
* Process asr_start request from FreeSWITCH * Process asr_start request from FreeSWITCH
* @param ah the FreeSWITCH speech recognition handle * @param ah the FreeSWITCH speech recognition handle
* @param name name of the grammar to use
* @return SWITCH_STATUS_SUCCESS if successful * @return SWITCH_STATUS_SUCCESS if successful
*/ */
static switch_status_t recog_asr_start(switch_asr_handle_t *ah, const char *name) static switch_status_t recog_asr_start(switch_asr_handle_t *ah)
{ {
switch_status_t status; switch_status_t status;
speech_channel_t *schannel = (speech_channel_t *) ah->private_info; speech_channel_t *schannel = (speech_channel_t *) ah->private_info;
status = recog_channel_start(schannel, name); status = recog_channel_start(schannel);
return status; return status;
} }
#endif #endif
@ -2972,7 +3157,7 @@ static switch_status_t recog_asr_start(switch_asr_handle_t *ah, const char *name
static switch_status_t recog_asr_resume(switch_asr_handle_t *ah) static switch_status_t recog_asr_resume(switch_asr_handle_t *ah)
{ {
speech_channel_t *schannel = (speech_channel_t *) ah->private_info; speech_channel_t *schannel = (speech_channel_t *) ah->private_info;
return recog_channel_start(schannel, NULL); return recog_channel_start(schannel);
} }
/** /**
@ -3231,6 +3416,9 @@ static switch_status_t recog_load(switch_loadable_module_interface_t *module_int
asr_interface->asr_open = recog_asr_open; asr_interface->asr_open = recog_asr_open;
asr_interface->asr_load_grammar = recog_asr_load_grammar; asr_interface->asr_load_grammar = recog_asr_load_grammar;
asr_interface->asr_unload_grammar = recog_asr_unload_grammar; asr_interface->asr_unload_grammar = recog_asr_unload_grammar;
asr_interface->asr_enable_grammar = recog_asr_enable_grammar;
asr_interface->asr_disable_grammar = recog_asr_disable_grammar;
asr_interface->asr_disable_all_grammars = recog_asr_disable_all_grammars;
asr_interface->asr_close = recog_asr_close; asr_interface->asr_close = recog_asr_close;
asr_interface->asr_feed = recog_asr_feed; asr_interface->asr_feed = recog_asr_feed;
#if 0 #if 0

View File

@ -27,6 +27,7 @@
* Michael Jerris <mike@jerris.com> * Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org> * Paul D. Tinsley <pdt at jackhammer.org>
* Christopher M. Rienzo <chris@rienzo.net> * Christopher M. Rienzo <chris@rienzo.net>
* Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
* *
* *
* switch_core_asr.c -- Main Core Library (Speech Detection Interface) * switch_core_asr.c -- Main Core Library (Speech Detection Interface)
@ -160,6 +161,45 @@ SWITCH_DECLARE(switch_status_t) switch_core_asr_unload_grammar(switch_asr_handle
return status; return status;
} }
SWITCH_DECLARE(switch_status_t) switch_core_asr_enable_grammar(switch_asr_handle_t *ah, const char *name)
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_assert(ah != NULL);
if (ah->asr_interface->asr_enable_grammar) {
status = ah->asr_interface->asr_enable_grammar(ah, name);
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_asr_disable_grammar(switch_asr_handle_t *ah, const char *name)
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_assert(ah != NULL);
if (ah->asr_interface->asr_disable_grammar) {
status = ah->asr_interface->asr_disable_grammar(ah, name);
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_asr_disable_all_grammars(switch_asr_handle_t *ah)
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_assert(ah != NULL);
if (ah->asr_interface->asr_disable_all_grammars) {
status = ah->asr_interface->asr_disable_all_grammars(ah);
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_asr_pause(switch_asr_handle_t *ah) SWITCH_DECLARE(switch_status_t) switch_core_asr_pause(switch_asr_handle_t *ah)
{ {
switch_assert(ah != NULL); switch_assert(ah != NULL);

View File

@ -26,6 +26,7 @@
* Anthony Minessale II <anthm@freeswitch.org> * Anthony Minessale II <anthm@freeswitch.org>
* Michael Jerris <mike@jerris.com> * Michael Jerris <mike@jerris.com>
* Bret McDanel <bret AT 0xdecafbad dot com> * Bret McDanel <bret AT 0xdecafbad dot com>
* Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
* *
* switch_ivr_async.c -- IVR Library (async operations) * switch_ivr_async.c -- IVR Library (async operations)
* *
@ -3276,6 +3277,18 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_set_param_detect_speech(switch_core_s
return status; return status;
} }
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_start_input_timers(switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY);
if (sth) {
switch_core_asr_start_input_timers(sth->ah);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_unload_grammar(switch_core_session_t *session, const char *name) SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_unload_grammar(switch_core_session_t *session, const char *name)
{ {
switch_channel_t *channel = switch_core_session_get_channel(session); switch_channel_t *channel = switch_core_session_get_channel(session);
@ -3293,6 +3306,57 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_unload_grammar(switch_c
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
} }
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_enable_grammar(switch_core_session_t *session, const char *name)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY);
switch_status_t status;
if (sth) {
if ((status = switch_core_asr_enable_grammar(sth->ah, name)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error enabling Grammar\n");
switch_core_asr_close(sth->ah, &flags);
}
return status;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_disable_grammar(switch_core_session_t *session, const char *name)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY);
switch_status_t status;
if (sth) {
if ((status = switch_core_asr_disable_grammar(sth->ah, name)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error disabling Grammar\n");
switch_core_asr_close(sth->ah, &flags);
}
return status;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_disable_all_grammars(switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY);
switch_status_t status;
if (sth) {
if ((status = switch_core_asr_disable_all_grammars(sth->ah)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error disabling all Grammars\n");
switch_core_asr_close(sth->ah, &flags);
}
return status;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech(switch_core_session_t *session, SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech(switch_core_session_t *session,
const char *mod_name, const char *mod_name,
const char *grammar, const char *name, const char *dest, switch_asr_handle_t *ah) const char *grammar, const char *name, const char *dest, switch_asr_handle_t *ah)