提交 96eba0d6 authored 作者: Chris Rienzo's avatar Chris Rienzo

mod_rayo: add support for speech recognizers other than pocketsphinx, fixed some…

mod_rayo: add support for speech recognizers other than pocketsphinx, fixed some input component bugs, allow simultaneous dtmf and voice input.
上级 8859df67
......@@ -11,6 +11,11 @@
<param name="record-file-prefix" value="$${recordings_dir}/"/>
</record>
<!-- input component params -->
<input>
<param name="default-recognizer" value="pocketsphinx"/>
</input>
<!-- XMPP server domain -->
<domain name="$${rayo_domain_name}" shared-secret="ClueCon">
<!-- use this instead if you want secure XMPP client to server connections. Put .crt and .key file in freeswitch/certs -->
......
......@@ -11,6 +11,11 @@
<param name="record-file-prefix" value="$${recordings_dir}/"/>
</record>
<!-- input component params -->
<input>
<param name="default-recognizer" value="pocketsphinx"/>
</input>
<!-- XMPP server domain -->
<domain name="$${rayo_domain_name}" shared-secret="ClueCon">
<!-- use this instead if you want secure XMPP client to server connections. Put .crt and .key file in freeswitch/certs -->
......
......@@ -216,6 +216,17 @@ double iks_find_decimal_attrib(iks *xml, const char *attrib)
return atof(iks_find_attrib_soft(xml, attrib));
}
/**
* Get attribute character value of node
* @param xml the XML node to search
* @param attrib the Attribute name
* @return the attribute value
*/
char iks_find_char_attrib(iks *xml, const char *attrib)
{
return iks_find_attrib_soft(xml, attrib)[0];
}
/**
* Convert iksemel XML node type to string
* @param type the XML node type
......@@ -392,6 +403,54 @@ int iks_attrib_is_decimal_between_zero_and_one(const char *value)
return SWITCH_FALSE;
}
/**
* Validate dtmf digit
* @param value
* @return SWITCH_TRUE if 0-9,a,b,c,d,A,B,C,D,*,#
*/
int iks_attrib_is_dtmf_digit(const char *value)
{
if (value && *value && strlen(value) == 1) {
switch (*value) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'A':
case 'a':
case 'B':
case 'b':
case 'C':
case 'c':
case 'D':
case 'd':
case '*':
case '#':
return SWITCH_TRUE;
}
}
return SWITCH_FALSE;
}
/**
* @param fn to evaluate attribute
* @param attrib to evaluate
* @return true if not set or is valid
*/
int validate_optional_attrib(iks_attrib_validation_function fn, const char *attrib)
{
if (!attrib || !*attrib) {
return SWITCH_TRUE;
}
return fn(attrib);
}
#define IKS_SHA256_HEX_DIGEST_LENGTH ((SHA256_DIGEST_LENGTH * 2) + 1)
/**
......
......@@ -63,6 +63,7 @@ extern const char *iks_find_attrib_soft(iks *xml, const char *attrib);
extern const char *iks_find_attrib_default(iks *xml, const char *attrib, const char *def);
extern int iks_find_bool_attrib(iks *xml, const char *attrib);
extern int iks_find_int_attrib(iks *xml, const char *attrib);
extern char iks_find_char_attrib(iks *xml, const char *attrib);
extern double iks_find_decimal_attrib(iks *xml, const char *attrib);
extern const char *iks_node_type_to_string(int type);
extern const char *iks_net_error_to_string(int err);
......@@ -73,9 +74,12 @@ extern char *iks_server_dialback_key(const char *secret, const char *receiving_s
/** A function to validate attribute value */
typedef int (*iks_attrib_validation_function)(const char *);
extern int validate_optional_attrib(iks_attrib_validation_function fn, const char *attrib);
#define ELEMENT_DECL(name) extern int VALIDATE_##name(iks *node);
#define ELEMENT(name) int VALIDATE_##name(iks *node) { int result = 1; if (!node) return 0;
#define ATTRIB(name, def, rule) result &= iks_attrib_is_##rule(iks_find_attrib_default(node, #name, #def));
#define OPTIONAL_ATTRIB(name, def, rule) result &= validate_optional_attrib(iks_attrib_is_##rule, iks_find_attrib_default(node, #name, #def));
#define STRING_ATTRIB(name, def, rule) result &= value_matches(iks_find_attrib_default(node, #name, #def), rule);
#define ELEMENT_END return result; }
......@@ -87,6 +91,7 @@ extern int iks_attrib_is_positive(const char *value);
extern int iks_attrib_is_positive_or_neg_one(const char *value);
extern int iks_attrib_is_any(const char *value);
extern int iks_attrib_is_decimal_between_zero_and_one(const char *value);
extern int iks_attrib_is_dtmf_digit(const char *value);
#endif
......
......@@ -3737,6 +3737,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)
"</grammar></input>"
"</prompt>");
rayo_add_cmd_alias("prompt_barge_mrcp", "<prompt xmlns=\""RAYO_PROMPT_NS"\" barge-in=\"true\">"
"<output xmlns=\""RAYO_OUTPUT_NS"\" repeat-times=\"5\"><document content-type=\"application/ssml+xml\"><![CDATA[<speak><p>Please press a digit.</p></speak>]]></document></output>"
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"any\" initial-timeout=\"5000\" inter-digit-timeout=\"3000\">"
"<grammar content-type=\"application/srgs+xml\">"
"<![CDATA[<grammar mode=\"dtmf\"><rule id=\"digit\" scope=\"public\"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></rule></grammar>]]>"
"</grammar></input>"
"</prompt>");
rayo_add_cmd_alias("prompt_no_barge", "<prompt xmlns=\""RAYO_PROMPT_NS"\" barge-in=\"false\">"
"<output xmlns=\""RAYO_OUTPUT_NS"\" repeat-times=\"2\"><document content-type=\"application/ssml+xml\"><![CDATA[<speak><p>Please press a digit.</p></speak>]]></document></output>"
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"dtmf\" initial-timeout=\"5000\" inter-digit-timeout=\"3000\">"
......@@ -3800,6 +3808,34 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)
"<unjoin xmlns=\""RAYO_NS"\" mixer-name=\"test\"/>");
rayo_add_cmd_alias("unjoin",
"<unjoin xmlns=\""RAYO_NS"\"/>");
rayo_add_cmd_alias("input_voice_yesno_unimrcp",
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"voice\" recognizer=\"unimrcp\"><grammar content-type=\"application/srgs+xml\">"
"<![CDATA[<grammar xmlns=\"http://www.w3.org/2001/06/grammar\" "
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"xsi:schemaLocation=\"http://www.w3.org/2001/06/grammar http://www.w3.org/TR/speech-grammar/grammar.xsd\" "
"xml:lang=\"en-US\" version=\"1.0\">"
"<rule id=\"yesno\"><one-of><item>yes</item><item>no</item></one-of></rule></grammar>]]></grammar></input>");
rayo_add_cmd_alias("input_voice_yesno_unimrcp_timeout",
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"voice\" recognizer=\"unimrcp\" max-silence=\"5\" initial-timeout=\"5000\"><grammar content-type=\"application/srgs+xml\">"
"<![CDATA[<grammar xmlns=\"http://www.w3.org/2001/06/grammar\" "
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"xsi:schemaLocation=\"http://www.w3.org/2001/06/grammar http://www.w3.org/TR/speech-grammar/grammar.xsd\" "
"xml:lang=\"en-US\" version=\"1.0\">"
"<rule id=\"yesno\"><one-of><item>yes</item><item>no</item></one-of></rule></grammar>]]></grammar></input>");
rayo_add_cmd_alias("input_voice_yesno_pocketsphinx",
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"voice\" recognizer=\"pocketsphinx\" max-silence=\"5000\" initial-timeout=\"5000\"><grammar content-type=\"application/srgs+xml\">"
"<![CDATA[<grammar xmlns=\"http://www.w3.org/2001/06/grammar\" "
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"xsi:schemaLocation=\"http://www.w3.org/2001/06/grammar http://www.w3.org/TR/speech-grammar/grammar.xsd\" "
"xml:lang=\"en-US\" version=\"1.0\">"
"<rule id=\"yesno\"><one-of><item>yes</item><item>no</item></one-of></rule></grammar>]]></grammar></input>");
rayo_add_cmd_alias("input_voice_yesno_default",
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"voice\"><grammar content-type=\"application/srgs+xml\">"
"<![CDATA[<grammar xmlns=\"http://www.w3.org/2001/06/grammar\" "
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"xsi:schemaLocation=\"http://www.w3.org/2001/06/grammar http://www.w3.org/TR/speech-grammar/grammar.xsd\" "
"xml:lang=\"en-US\" version=\"1.0\">"
"<rule id=\"yesno\"><one-of><item>yes</item><item>no</item></one-of></rule></grammar>]]></grammar></input>");
return SWITCH_STATUS_SUCCESS;
}
......
......@@ -227,15 +227,10 @@ void rayo_component_api_execute_async(struct rayo_component *component, const ch
*/
switch_status_t rayo_components_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file)
{
rayo_input_component_load();
rayo_output_component_load(module_interface, pool);
rayo_prompt_component_load();
rayo_record_component_load(pool, config_file);
if (rayo_input_component_load() != SWITCH_STATUS_SUCCESS ||
rayo_output_component_load(module_interface, pool) != SWITCH_STATUS_SUCCESS ||
rayo_prompt_component_load() != SWITCH_STATUS_SUCCESS ||
rayo_record_component_load(pool, config_file) != SWITCH_STATUS_SUCCESS) {
if (rayo_input_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS ||
rayo_output_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS ||
rayo_prompt_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS ||
rayo_record_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_TERM;
}
return SWITCH_STATUS_SUCCESS;
......
......@@ -54,10 +54,10 @@
#define COMPONENT_COMPLETE_HANGUP "hangup", RAYO_EXT_COMPLETE_NS
extern switch_status_t rayo_components_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
extern switch_status_t rayo_input_component_load(void);
extern switch_status_t rayo_output_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool);
extern switch_status_t rayo_prompt_component_load(void);
extern switch_status_t rayo_record_component_load(switch_memory_pool_t *pool, const char *config_file);
extern switch_status_t rayo_input_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
extern switch_status_t rayo_output_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
extern switch_status_t rayo_prompt_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
extern switch_status_t rayo_record_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
extern switch_status_t rayo_components_shutdown(void);
extern switch_status_t rayo_input_component_shutdown(void);
......
......@@ -33,7 +33,7 @@
*/
ELEMENT(RAYO_INPUT)
STRING_ATTRIB(mode, any, "any,dtmf,voice")
ATTRIB(terminator,, any)
OPTIONAL_ATTRIB(terminator,, dtmf_digit)
ATTRIB(recognizer,, any)
ATTRIB(language, en-US, any)
ATTRIB(initial-timeout, -1, positive_or_neg_one)
......
......@@ -1092,9 +1092,12 @@ static char *fileman_supported_formats[] = { "fileman", NULL };
/**
* Initialize output component
* @param module_interface
* @param pool memory pool to allocate from
* @param config_file to use
* @return SWITCH_STATUS_SUCCESS if successful
*/
switch_status_t rayo_output_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool)
switch_status_t rayo_output_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file)
{
switch_api_interface_t *api_interface;
switch_file_interface_t *file_interface;
......
......@@ -620,9 +620,12 @@ static iks *forward_output_component_request(struct rayo_actor *prompt, struct r
/**
* Initialize prompt component
* @param module_interface
* @param pool memory pool to allocate from
* @param config_file to use
* @return SWITCH_STATUS_SUCCESS if successful
*/
switch_status_t rayo_prompt_component_load(void)
switch_status_t rayo_prompt_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file)
{
/* Prompt is a convenience component that wraps <input> and <output> */
rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_PROMPT_NS":prompt", start_call_prompt_component);
......
......@@ -479,11 +479,12 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_
/**
* Initialize record component
* @param module_interface
* @param pool memory pool to allocate from
* @param config_file to use
* @return SWITCH_STATUS_SUCCESS if successful
*/
switch_status_t rayo_record_component_load(switch_memory_pool_t *pool, const char *config_file)
switch_status_t rayo_record_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file)
{
if (do_config(pool, config_file) != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_TERM;
......
......@@ -145,6 +145,27 @@ static void test_dialback_key(void)
ASSERT_NULL(iks_server_dialback_key("s3cr3tf0rd14lb4ck", "xmpp.example.com", "example.org", NULL));
}
static void test_validate_dtmf(void)
{
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("1"));
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("A"));
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("a"));
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("D"));
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("d"));
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("*"));
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("#"));
ASSERT_EQUALS(SWITCH_FALSE, iks_attrib_is_dtmf_digit("E"));
ASSERT_EQUALS(SWITCH_FALSE, iks_attrib_is_dtmf_digit(NULL));
ASSERT_EQUALS(SWITCH_FALSE, iks_attrib_is_dtmf_digit(""));
ASSERT_EQUALS(SWITCH_FALSE, iks_attrib_is_dtmf_digit("11"));
ASSERT_EQUALS(SWITCH_TRUE, validate_optional_attrib(iks_attrib_is_dtmf_digit, "A"));
ASSERT_EQUALS(SWITCH_TRUE, validate_optional_attrib(iks_attrib_is_dtmf_digit, "1"));
ASSERT_EQUALS(SWITCH_FALSE, validate_optional_attrib(iks_attrib_is_dtmf_digit, "Z"));
ASSERT_EQUALS(SWITCH_FALSE, validate_optional_attrib(iks_attrib_is_dtmf_digit, "11"));
ASSERT_EQUALS(SWITCH_TRUE, validate_optional_attrib(iks_attrib_is_dtmf_digit, NULL));
ASSERT_EQUALS(SWITCH_TRUE, validate_optional_attrib(iks_attrib_is_dtmf_digit, ""));
}
/**
* main program
*/
......@@ -159,5 +180,6 @@ int main(int argc, char **argv)
TEST(test_rayo_test_srgs);
TEST(test_iks_helper_value_matches);
TEST(test_dialback_key);
TEST(test_validate_dtmf);
return 0;
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论