add pelim say stuff, module framework, xml parser, dialplan app, and add new channel var called sound_prefix for audio files

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3766 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2006-12-20 21:25:14 +00:00
parent 9db9fae8a2
commit b7dbea6407
10 changed files with 575 additions and 7 deletions

View File

@ -632,6 +632,43 @@
</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>

View 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

View 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

View 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 {

View 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);

View 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
};

View File

@ -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;
}

View 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

View 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)
{

View 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}
};