]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add pelim say stuff, module framework, xml parser, dialplan app, and add new channel...
authorAnthony Minessale <anthony.minessale@gmail.com>
Wed, 20 Dec 2006 21:25:14 +0000 (21:25 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Wed, 20 Dec 2006 21:25:14 +0000 (21:25 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3766 d0543943-73ff-0310-b7d9-9358b9ac24b2

conf/freeswitch.xml
src/include/switch_ivr.h
src/include/switch_loadable_module.h
src/include/switch_module_interfaces.h
src/include/switch_types.h
src/mod/applications/mod_dptools/mod_dptools.c
src/mod/say/mod_say_en/mod_say_en.c [new file with mode: 0644]
src/switch_ivr.c
src/switch_loadable_module.c
src/switch_xml.c

index 693486959ffb45d14cfd8bfba1d6907272401c96..828a94e79e93e8f20c0d67ca637746fea76639de 100644 (file)
       </user>
     </domain>
   </section>
+
+  <!-- phrases section (under development still) -->
+  <section name="phrases" description="Speech Phrase Management">
+    <macros>
+      <language name="en" sound_path="/snds" tts_engine="cepstral" tts_voice="david">
+       <macro name="msgcount">
+         <input pattern="(.*)">
+           <action function="execute" data="sleep(1000)"/>
+           <action function="play-file" data="vm-youhave.wav"/>
+           <action function="say" data="$1" method="pronounced" type="items"/>
+           <action function="play-file" data="vm-messages.wav"/>
+           <!-- or -->
+           <!--<action function="speak-text" data="you have $1 messages"/>-->
+         </input>
+       </macro>
+       <macro name="timeleft">
+         <input pattern="(\d+):(\d+)">
+           <action function="speak-text" data="You have $1 minutes, $2 seconds remaining"/>
+         </input>
+       </macro>
+      </language>
+      <language name="fr" sound_path="/var/sounds/lang/fr/jean" tts_engine="cepstral" tts_voice="jean-pierre">
+       <macro name="msgcount">
+         <input pattern="(.*)">
+           <action function="play-file" data="tuas.wav"/>
+           <action function="say" data="$1" method="pronounced" type="items"/>
+           <action function="play-file" data="messages.wav"/>
+         </input>
+       </macro>
+       <macro name="timeleft">
+         <input pattern="(\d+):(\d+)">
+           <action function="speak-text" data="il y a $1 minutes et de $2 secondes de restant"/>
+         </input>
+       </macro>
+      </language>
+    </macros>
+  </section>
 </document>
 
 
index 198c19be344a6702674f534efd5990c6a21a72e8..fa74b8522798bfa27acf83f55b9930430a5c7d4a 100644 (file)
@@ -626,6 +626,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_add_custom(switch_ivr_
  */
 SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_init(switch_ivr_menu_xml_ctx_t **xml_menu_ctx, switch_memory_pool_t *pool);
 
+SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro(switch_core_session_t *session,
+                                                        char *macro_name,
+                                                        char *data,
+                                                        char *lang,
+                                                        switch_input_callback_function_t input_callback,
+                                                        void *buf,
+                                                        uint32_t buflen);
 /** @} */
 
 SWITCH_END_EXTERN_C
index 82689c836e0bae26f692ab5a91f91d9872a71264..436fab4e2f3fe39e8c56bb994a99128f2ccc18a9 100644 (file)
@@ -75,6 +75,8 @@ struct switch_loadable_module_interface {
        const switch_directory_interface_t *directory_interface;
        /*! the table of chat interfaces the module has implmented */
        const switch_chat_interface_t *chat_interface;
+       /*! the table of say interfaces the module has implmented */
+       const switch_say_interface_t *say_interface;
        /*! the table of asr interfaces the module has implmented */
        const switch_asr_interface_t *asr_interface;
 };
@@ -181,6 +183,13 @@ SWITCH_DECLARE(switch_directory_interface_t *) switch_loadable_module_get_direct
  */
 SWITCH_DECLARE(switch_chat_interface_t *) switch_loadable_module_get_chat_interface(char *name);
 
+/*!
+  \brief Retrieve the say interface by it's registered name
+  \param name the name of the say interface
+  \return the desired say interface
+ */
+SWITCH_DECLARE(switch_say_interface_t *) switch_loadable_module_get_say_interface(char *name);
+
 
 /*!
   \brief Retrieve the list of loaded codecs into an array
index 4e9d2902ea0fa22da683fac3f7e64e7470189559..b48bcff80036228d2d73d0226c140df7f02177ea 100644 (file)
@@ -412,6 +412,20 @@ struct switch_speech_handle {
        void *private_info;
 };
 
+/*! \brief Abstract interface to a say module */
+struct switch_say_interface {
+       /*! the name of the interface */
+       const char *interface_name;
+       /*! function to pass down to the module */
+    switch_status_t (*say_function)(switch_core_session_t *session,
+                                    char *tosay,
+                                    switch_say_type_t type,
+                                    switch_say_method_t method,
+                                    switch_input_callback_function_t dtmf_callback,
+                                    void *buf,
+                                    uint32_t buflen);
+       const struct switch_say_interface *next;
+};
 
 /*! \brief Abstract interface to a chat module */
 struct switch_chat_interface {
index f04026f8325486948827f7f2864fe8ddf8f963ab..ed09ebd7316d1f11f50768b57c1f1d216081c57c 100644 (file)
@@ -93,6 +93,33 @@ SWITCH_BEGIN_EXTERN_C
 #define SWITCH_BITS_PER_BYTE 8
 typedef uint8_t switch_byte_t;
 
+typedef enum {
+       SSM_NA,
+       SSM_PRONOUNCED,
+       SSM_ITERATED
+} switch_say_method_t;
+
+typedef enum {
+       SST_NUMBER,
+       SST_ITEMS,
+       SST_PERSONS,
+       SST_MESSAGES,
+       SST_CURRENCY,
+       SST_TIME_MEASUREMENT,
+       SST_CURRENT_DATE,
+       SST_CURRENT_TIME,
+       SST_CURRENT_DATE_TIME,
+       SST_TELEPHONE_NUMBER,
+       SST_TELEPHONE_EXTENSION,
+       SST_URL,
+       SST_EMAIL_ADDRESS,
+       SST_POSTAL_ADDRESS,
+       SST_ACCOUNT_NUMBER,
+       SST_NAME_SPELLED,
+       SST_NAME_PHONETIC,
+} switch_say_type_t;
+
+
 typedef enum {
        SMF_NONE = 0,
        SMF_REBRIDGE = (1 << 0),
@@ -172,7 +199,8 @@ typedef enum {
        SWITCH_XML_SECTION_RESULT = 0,
        SWITCH_XML_SECTION_CONFIG = (1 << 0),
        SWITCH_XML_SECTION_DIRECTORY = (1 << 1),
-       SWITCH_XML_SECTION_DIALPLAN = (1 << 2)
+       SWITCH_XML_SECTION_DIALPLAN = (1 << 2),
+       SWITCH_XML_SECTION_PHRASES = (1 << 3)
 } switch_xml_section_t;
 
 /*!
@@ -863,6 +891,7 @@ typedef struct switch_speech_interface switch_speech_interface_t;
 typedef struct switch_asr_interface switch_asr_interface_t;
 typedef struct switch_directory_interface switch_directory_interface_t;
 typedef struct switch_chat_interface switch_chat_interface_t;
+typedef struct switch_say_interface switch_say_interface_t;
 typedef struct switch_core_port_allocator switch_core_port_allocator_t;
 typedef struct switch_media_bug switch_media_bug_t;
 typedef void (*switch_media_bug_callback_t)(switch_media_bug_t *, void *, switch_abc_type_t);
index c6607cbf76dd5adb1a1febc0cd2fbc0b64198f21..acd7e6e202b15335c83308a1259726476d9c4b6e 100644 (file)
@@ -102,6 +102,32 @@ static void eval_function(switch_core_session_t *session, char *data)
        return;
 }
 
+static void phrase_function(switch_core_session_t *session, char *data)
+{
+    switch_channel_t *channel;
+    char *mydata = NULL;
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel != NULL);
+    
+    if ((mydata = switch_core_session_strdup(session, data))) {
+        char *lang;
+        char *macro = mydata;
+        char *mdata = NULL;
+
+        if ((mdata = strchr(macro, ','))) {
+            *mdata++ = '\0';
+        }
+        if (!(lang = switch_channel_get_variable(channel, "language"))) {
+            lang = "en";
+        }
+        
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Execute %s(%s) lang %s\n", macro, mdata, lang);
+        switch_ivr_phrase_macro(session, macro, mdata, lang, NULL, NULL, 0);
+    }
+
+}
+
 static void answer_function(switch_core_session_t *session, char *data)
 {
        switch_channel_t *channel;
@@ -462,13 +488,23 @@ static const switch_application_interface_t eval_application_interface = {
 
 };
 
+static const switch_application_interface_t phrase_application_interface = {
+       /*.interface_name */ "phrase",
+       /*.application_function */ phrase_function,
+       /* long_desc */ "Say a Phrase",
+       /* short_desc */ "Say a Phrase",
+       /* syntax */ "<macro_name>,<data>",
+       /*.next */ &eval_application_interface
+
+};
+
 static const switch_application_interface_t strftime_application_interface = {
        /*.interface_name */ "strftime",
        /*.application_function */ strftime_function,
        /* long_desc */ NULL,
        /* short_desc */ NULL,
        /* syntax */ NULL,
-       /*.next */ &eval_application_interface
+       /*.next */ &phrase_application_interface
 
 };
 
diff --git a/src/mod/say/mod_say_en/mod_say_en.c b/src/mod/say/mod_say_en/mod_say_en.c
new file mode 100644 (file)
index 0000000..27d2f3a
--- /dev/null
@@ -0,0 +1,178 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * mod_say_en.c -- Say for English
+ *
+ */
+#include <switch.h>
+#include <math.h>
+
+static const char modname[] = "mod_say_en";
+
+static switch_status_t en_say(switch_core_session_t *session,
+                                                         char *tosay,
+                                                         switch_say_type_t type,
+                                                         switch_say_method_t method,
+                                                         switch_input_callback_function_t input_callback,
+                                                         void *buf,
+                                                         uint32_t buflen)
+{
+       switch_channel_t *channel;
+
+       assert(session != NULL);
+       channel = switch_core_session_get_channel(session);
+       assert(channel != NULL);
+       
+       switch(type) {
+       case SST_NUMBER:
+       case SST_ITEMS:
+       case SST_PERSONS:
+       case SST_MESSAGES:
+               {
+                       int in;
+                       int x, places[7] = {0};
+                       char tmp[25];
+
+                       in = atoi(tosay);
+
+                       for(x = 6; x >= 0; x--) {
+                               int num = pow(10, x);
+                               if ((places[x] = in / num)) {
+                                       in -= places[x] * num;
+                               }
+                       }
+
+                       switch (method) {
+                       case SSM_PRONOUNCED:
+                               if (places[6]) {
+                                       snprintf(tmp, sizeof(tmp), "digits/%d.wav", places[6]);
+                                       switch_ivr_play_file(session, NULL, tmp, NULL, input_callback, buf, buflen);
+                                       switch_ivr_play_file(session, NULL, "digits/million.wav", NULL, input_callback, buf, buflen);
+                               }
+
+                               if (places[5]) {
+                                       snprintf(tmp, sizeof(tmp), "digits/%d.wav", places[5]);
+                                       switch_ivr_play_file(session, NULL, tmp, NULL, input_callback, buf, buflen);
+                                       switch_ivr_play_file(session, NULL, "digits/hundred.wav", NULL, input_callback, buf, buflen);
+                               }
+                       
+                               if (places[4]) {
+                                       if (places[4] > 1) {
+                                               snprintf(tmp, sizeof(tmp), "digits/%d0.wav", places[4]);
+                                               switch_ivr_play_file(session, NULL, tmp, NULL, input_callback, buf, buflen);
+                                       } else {
+                                               snprintf(tmp, sizeof(tmp), "digits/%d%d.wav", places[4], places[3]);
+                                               switch_ivr_play_file(session, NULL, tmp, NULL, input_callback, buf, buflen);
+                                               places[3] = 0;
+                                       }
+                               }
+                       
+                               if (places[3]) {
+                                       snprintf(tmp, sizeof(tmp), "digits/%d.wav", places[3]);
+                                       switch_ivr_play_file(session, NULL, tmp, NULL, input_callback, buf, buflen);
+                               }
+
+                               if (places[4] || places[3]) {
+                                       switch_ivr_play_file(session, NULL, "digits/thousand.wav", NULL, input_callback, buf, buflen);
+                               }
+
+                               if (places[2]) {
+                                       snprintf(tmp, sizeof(tmp), "digits/%d.wav", places[2]);
+                                       switch_ivr_play_file(session, NULL, tmp, NULL, input_callback, buf, buflen);
+                                       switch_ivr_play_file(session, NULL, "digits/hundred.wav", NULL, input_callback, buf, buflen);
+                               }
+
+                               if (places[1]) {
+                                       if (places[1] > 1) {
+                                               snprintf(tmp, sizeof(tmp), "digits/%d0.wav", places[1]);
+                                               switch_ivr_play_file(session, NULL, tmp, NULL, input_callback, buf, buflen);
+                                       } else {
+                                               snprintf(tmp, sizeof(tmp), "digits/%d%d.wav", places[1], places[0]);
+                                               switch_ivr_play_file(session, NULL, tmp, NULL, input_callback, buf, buflen);
+                                               places[0] = 0;
+                                       }
+                               }
+
+                               if (places[0]) {
+                                       snprintf(tmp, sizeof(tmp), "digits/%d.wav", places[0]);
+                                       switch_ivr_play_file(session, NULL, tmp, NULL, input_callback, buf, buflen);
+                               }
+
+                               break;
+                       case SSM_ITERATED:
+                               for(x = 7; x >= 0; x--) {
+                                       if (places[x]) {
+                                               snprintf(tmp, sizeof(tmp), "digits/%d.wav", places[x]);
+                                               switch_ivr_play_file(session, NULL, tmp, NULL, input_callback, buf, buflen);
+                                       }
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+               break;
+       default:
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Finish ME!\n");
+               break;
+       }
+
+
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static const switch_chat_interface_t en_say_interface= {
+       /*.name */ "en",
+       /*.say_function */ en_say,
+};
+
+static switch_loadable_module_interface_t say_en_module_interface = {
+       /*.module_name */ modname,
+       /*.endpoint_interface */ NULL,
+       /*.timer_interface */ NULL,
+       /*.dialplan_interface */ NULL,
+       /*.codec_interface */ NULL,
+       /*.application_interface */ NULL,
+       /*.api_interface */ NULL,
+       /*.file_interface */ NULL,
+       /*.speech_interface */ NULL,
+       /*.directory_interface */ NULL,
+       /*.chat_interface */ NULL,
+       /*.say_inteface*/ &en_say_interface,
+       /*.asr_interface*/ NULL
+};
+
+SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename)
+{
+       /* connect my internal structure to the blank pointer passed to me */
+       *module_interface = &say_en_module_interface;
+
+       /* indicate that the module should continue to be loaded */
+       return SWITCH_STATUS_SUCCESS;
+}
+
index a0ed7741e7f56639e111bfbeffa7d049c056d364..879f31a096b78491dadcdf6a6ff363b30e374dba 100644 (file)
@@ -977,8 +977,23 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
        char *title = "", *copyright = "", *software = "", *artist = "", *comment = "", *date = "";
        uint8_t asis = 0;
        char *ext;
+    char *prefix;
+
+       channel = switch_core_session_get_channel(session);
+       assert(channel != NULL);
+
+    prefix = switch_channel_get_variable(channel, "sound_prefix");
        
        if (file) {
+        if (prefix && *file != '/' && *file != '\\' && *(file+1) != ':') {
+            char *new_file;
+            uint32_t len;
+            len = (uint32_t)strlen(file) + (uint32_t)strlen(prefix) + 10;
+            new_file = switch_core_session_alloc(session, len);
+            snprintf(new_file, len, "%s/%s", prefix, file);
+            file = new_file;
+        }
+
                if ((ext = strrchr(file, '.'))) {
                        ext++;
                } else {
@@ -1004,10 +1019,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
                fh->samples = 0;
        }
 
-
-       channel = switch_core_session_get_channel(session);
-       assert(channel != NULL);
-
        if (switch_core_file_open(fh,
                                                          file,
                                                          SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT,
@@ -1054,7 +1065,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
                date = (char *) switch_core_session_strdup(session, (char *)p);
                switch_channel_set_variable(channel, "RECORD_DATE", (char *)p);
        }
-       
+#if 0
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 
                                          "OPEN FILE %s %uhz %u channels\n"
                                          "TITLE=%s\n"
@@ -1069,6 +1080,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
                                          artist,
                                          comment,
                                          date);
+#endif
 
        assert(read_codec != NULL);
        interval = read_codec->implementation->microseconds_per_frame / 1000;
@@ -4336,6 +4348,230 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_build(switch_ivr_menu_
        return status;
 }
 
+
+static char *SAY_METHOD_NAMES[] = {
+    "N/A",
+    "PRONOUNCED",
+    "ITERATED",
+    NULL
+};
+
+static char *SAY_TYPE_NAMES[] = {
+       "NUMBER",
+       "ITEMS",
+       "PERSONS",
+       "MESSAGES",
+       "CURRENCY",
+       "TIME_MEASUREMENT",
+       "CURRENT_DATE",
+       "CURRENT_TIME",
+       "CURRENT_DATE_TIME",
+       "TELEPHONE_NUMBER",
+       "TELEPHONE_EXTENSION",
+       "URL",
+       "EMAIL_ADDRESS",
+       "POSTAL_ADDRESS",
+       "ACCOUNT_NUMBER",
+       "NAME_SPELLED",
+       "NAME_PHONETIC",
+    NULL
+};
+
+
+static switch_say_method_t get_say_method_by_name(char *name)
+{
+    int x = 0;
+    for (x = 0; SAY_METHOD_NAMES[x]; x++) {
+        if (!strcasecmp(SAY_METHOD_NAMES[x], name)) {
+            break;
+        }
+    }
+
+    return (switch_say_method_t) x;
+}
+
+static switch_say_method_t get_say_type_by_name(char *name)
+{
+    int x = 0;
+    for (x = 0; SAY_TYPE_NAMES[x]; x++) {
+        if (!strcasecmp(SAY_TYPE_NAMES[x], name)) {
+            break;
+        }
+    }
+    
+    return (switch_say_method_t) x;
+}
+
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro(switch_core_session_t *session,
+                                                        char *macro_name,
+                                                        char *data,
+                                                        char *lang,
+                                                        switch_input_callback_function_t input_callback,
+                                                        void *buf,
+                                                        uint32_t buflen)
+{
+       switch_xml_t cfg, xml = NULL, language, macros, macro, input, action;
+    char *lname = NULL, *mname = NULL, hint_data[1024] = "", enc_hint[1024] = "";
+    switch_status_t status = SWITCH_STATUS_GENERR;
+    char *old_sound_prefix, *sound_path = NULL, *tts_engine = NULL, *tts_voice = NULL;
+    switch_channel_t *channel;
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel != NULL);
+
+    switch_url_encode(data, enc_hint, sizeof(enc_hint));
+    snprintf(hint_data, sizeof(hint_data), "macro_name=%s&lang=%s&data=%s", macro_name, lang, enc_hint);
+    
+       if (switch_xml_locate("phrases", NULL, NULL, NULL, &xml, &cfg, hint_data) != SWITCH_STATUS_SUCCESS) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of phrases failed.\n");
+        goto done;
+       }
+
+    if (!(macros = switch_xml_child(cfg, "macros"))) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "can't find macros tag.\n");
+        goto done;
+    }
+
+    if (!(language = switch_xml_child(macros, "language"))) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "can't find language tag.\n");
+        goto done;
+    }
+
+    while(language) {
+        if ((lname = switch_xml_attr(language, "name")) && !strcasecmp(lname, lang)) {
+            break;
+        }
+        language = language->next;
+    }
+
+    if (!language) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "can't find language %s.\n", lang);
+        goto done;
+    }
+
+    sound_path = switch_xml_attr_soft(language, "sound_path");
+    tts_engine = switch_xml_attr_soft(language, "tts_engine");
+    tts_voice = switch_xml_attr_soft(language, "tts_voice");
+
+    old_sound_prefix = switch_channel_get_variable(channel, "sound_prefix");    
+    switch_channel_set_variable(channel, "sound_prefix", sound_path);
+
+    if (!(macro = switch_xml_child(language, "macro"))) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "can't find any macro tags.\n");
+        goto done;
+    }
+    
+    while(macro) {
+        if ((mname = switch_xml_attr(macro, "name")) && !strcasecmp(mname, macro_name)) {
+            break;
+        }
+        macro = macro->next;
+    }
+    
+    if (!macro) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "can't find macro %s.\n", macro_name);
+        goto done;
+    }
+
+    if (!(input = switch_xml_child(macro, "input"))) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "can't find any input tags.\n");
+        goto done;
+    }
+
+    switch_channel_pre_answer(channel);
+
+    while(input) {
+        char *pattern = switch_xml_attr(input, "pattern");
+
+        if (pattern) {
+            pcre *re = NULL;
+            int proceed = 0, ovector[30];
+            char substituted[1024] = "";
+            char *odata = NULL;
+
+            if ((proceed = switch_perform_regex(data, pattern, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
+                for (action = switch_xml_child(input, "action"); action; action = action->next) {
+                    char *adata = switch_xml_attr_soft(action, "data");
+                    char *func = switch_xml_attr_soft(action, "function");
+
+                    if (strchr(pattern, '(') && strchr(adata, '$')) {
+                        switch_perform_substitution(re, proceed, adata, data, substituted, sizeof(substituted), ovector);
+                        odata = substituted;
+                    } else {
+                        odata = adata;
+                    }
+
+                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Handle %s:[%s] (%s)\n", func, odata, lang);
+
+                    if (!strcasecmp(func, "play-file")) {
+                        switch_ivr_play_file(session, NULL, odata, NULL, input_callback, buf, buflen);
+                    } else if (!strcasecmp(func, "execute")) {
+                        const switch_application_interface_t *application_interface;
+                        char *app_name = NULL;
+                        char *app_arg = NULL;
+
+                        if ((app_name = strdup(odata))) {
+                            char *e = NULL;
+                            if ((app_arg = strchr(app_name, '('))) {
+                                *app_arg++ = '\0';
+                                if ((e = strchr(app_arg, ')'))) {
+                                    *e = '\0';
+                                }
+                                if (app_name && app_arg && e && (application_interface = switch_loadable_module_get_application_interface(app_name))) {
+                                    if (application_interface->application_function) {
+                                        application_interface->application_function(session, app_arg);
+                                    }
+                                } else {
+                                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Application!\n");
+                                }
+                            }
+                            switch_safe_free(app_name);
+                        } 
+                    } else if (!strcasecmp(func, "say")) {
+                        switch_say_interface_t *si;
+                        if ((si = switch_loadable_module_get_say_interface(lang))) {
+                            char *say_type = switch_xml_attr_soft(action, "type");
+                            char *say_method = switch_xml_attr_soft(action, "method");
+                            
+                            si->say_function(session, odata, get_say_type_by_name(say_type), get_say_method_by_name(say_method), input_callback, buf, buflen);
+                        } else {
+                            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invaid SAY Interface [%s]!\n", lang);
+                        }
+                    } else if (!strcasecmp(func, "speak-text")) {
+                        switch_codec_t *read_codec;
+                        if ((read_codec = switch_core_session_get_read_codec(session))) {
+                            switch_ivr_speak_text(session,
+                                                  tts_engine,
+                                                  tts_voice,
+                                                  NULL,
+                                                  read_codec->implementation->samples_per_second,
+                                                  input_callback,
+                                                  odata,
+                                                  buf,
+                                                  buflen);
+                        }
+                    }
+                }
+            }
+
+            switch_clean_re(re);
+        }
+
+        input = input->next;
+    }
+
+ done:
+
+       switch_channel_set_variable(channel, "sound_prefix", old_sound_prefix);
+
+    if (xml) {
+        switch_xml_free(xml);
+    }
+    return status;
+}
+
+
 /* For Emacs:
  * Local Variables:
  * mode:c
index a84d706d4a1666c837a8f309c77f90beb1e1e786..368b918e29cc7c6a2854164b867691243e7b5d55 100644 (file)
@@ -54,6 +54,7 @@ struct switch_loadable_module_container {
        switch_hash_t *asr_hash;
        switch_hash_t *directory_hash;
        switch_hash_t *chat_hash;
+       switch_hash_t *say_hash;
        switch_memory_pool_t *pool;
 };
 
@@ -260,6 +261,20 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                        switch_core_hash_insert(loadable_modules.chat_hash, (char *) ptr->interface_name, (void *) ptr);
                }
        }
+
+       if (new_module->module_interface->say_interface) {
+               const switch_say_interface_t *ptr;
+
+               for (ptr = new_module->module_interface->say_interface; ptr; ptr = ptr->next) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding Say interface '%s'\n", ptr->interface_name);
+                       if (switch_event_create(&event, SWITCH_EVENT_MODULE_LOAD) == SWITCH_STATUS_SUCCESS) {
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "type", "say");
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "name", "%s", ptr->interface_name);
+                               switch_event_fire(&event);
+                       }
+                       switch_core_hash_insert(loadable_modules.say_hash, (char *) ptr->interface_name, (void *) ptr);
+               }
+       }
        
 
        return SWITCH_STATUS_SUCCESS;
@@ -506,6 +521,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init()
        switch_core_hash_init(&loadable_modules.asr_hash, loadable_modules.pool);
        switch_core_hash_init(&loadable_modules.directory_hash, loadable_modules.pool);
        switch_core_hash_init(&loadable_modules.chat_hash, loadable_modules.pool);
+       switch_core_hash_init(&loadable_modules.say_hash, loadable_modules.pool);
        switch_core_hash_init(&loadable_modules.dialplan_hash, loadable_modules.pool);
 
        if ((xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
@@ -683,6 +699,11 @@ SWITCH_DECLARE(switch_chat_interface_t *) switch_loadable_module_get_chat_interf
        return switch_core_hash_find(loadable_modules.chat_hash, name);
 }
 
+SWITCH_DECLARE(switch_say_interface_t *) switch_loadable_module_get_say_interface(char *name)
+{
+       return switch_core_hash_find(loadable_modules.say_hash, name);
+}
+
 SWITCH_DECLARE(int) switch_loadable_module_get_codecs(switch_memory_pool_t *pool, const switch_codec_implementation_t **array,
                                                                                                          int arraylen)
 {
index abcca867fff34b75425024565214d02131024fce..f2da227986a2a0b3d0cad968c88b5b8acf01fb1e 100644 (file)
@@ -107,6 +107,7 @@ static struct xml_section_t SECTIONS[] = {
        { "config", SWITCH_XML_SECTION_CONFIG},
        { "directory", SWITCH_XML_SECTION_DIRECTORY},
        { "dialplan", SWITCH_XML_SECTION_DIALPLAN},
+       { "phrases", SWITCH_XML_SECTION_PHRASES},
        { NULL, 0}
 };