introduce new say_string method of doing say and use it in mod_say_en as an example. try: eval ${say_string en.gsm en current_date_time pronounced ${strepoch()}} from the cli with this patch. We can do more to centralize the say things and go back and apply it to other langs, using this method you can set the desired file ext as well which I think is a bounty....

This commit is contained in:
Anthony Minessale 2011-03-29 19:55:28 -05:00
parent 1552ecf54a
commit d5ef86d778
11 changed files with 548 additions and 111 deletions

View File

@ -145,6 +145,8 @@ SWITCH_DECLARE(int) switch_snprintf(_Out_z_cap_(len)
SWITCH_DECLARE(int) switch_vasprintf(_Out_opt_ char **buf, _In_z_ _Printf_format_string_ const char *format, _In_ va_list ap);
SWITCH_DECLARE(int) switch_vsnprintf(char *buf, switch_size_t len, const char *format, va_list ap);
SWITCH_DECLARE(char *) switch_copy_string(_Out_z_cap_(dst_size)
char *dst, _In_z_ const char *src, _In_ switch_size_t dst_size);

View File

@ -2240,6 +2240,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_del_registration(const char *user, c
*/
SWITCH_DECLARE(switch_status_t) switch_core_expire_registration(int force);
SWITCH_DECLARE(char *) switch_say_file_handle_get_variable(switch_say_file_handle_t *sh, const char *var);
SWITCH_DECLARE(char *) switch_say_file_handle_get_path(switch_say_file_handle_t *sh);
SWITCH_DECLARE(char *) switch_say_file_handle_detach_path(switch_say_file_handle_t *sh);
SWITCH_DECLARE(void) switch_say_file_handle_destroy(switch_say_file_handle_t **sh);
SWITCH_DECLARE(switch_status_t) switch_say_file_handle_create(switch_say_file_handle_t **sh, const char *ext, switch_event_t **var_event);
SWITCH_DECLARE(void) switch_say_file(switch_say_file_handle_t *sh, const char *fmt, ...);
SWITCH_END_EXTERN_C
#endif
/* For Emacs:

View File

@ -859,6 +859,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say(switch_core_session_t *session,
const char *say_gender,
switch_input_args_t *args);
SWITCH_DECLARE(switch_status_t) switch_ivr_say_string(switch_core_session_t *session,
const char *lang,
const char *ext,
const char *tosay,
const char *module_name,
const char *say_type,
const char *say_method,
const char *say_gender,
char **rstr);
SWITCH_DECLARE(switch_say_method_t) switch_ivr_get_say_method_by_name(const char *name);
SWITCH_DECLARE(switch_say_gender_t) switch_ivr_get_say_gender_by_name(const char *name);
SWITCH_DECLARE(switch_say_type_t) switch_ivr_get_say_type_by_name(const char *name);

View File

@ -103,29 +103,9 @@ struct switch_stream_handle {
};
struct switch_io_event_hooks;
struct switch_say_file_handle;
typedef switch_call_cause_t (*switch_io_outgoing_channel_t)
typedef switch_call_cause_t (*switch_io_outgoing_channel_t)
(switch_core_session_t *, switch_event_t *, switch_caller_profile_t *, switch_core_session_t **, switch_memory_pool_t **, switch_originate_flag_t,
switch_call_cause_t *);
typedef switch_status_t (*switch_io_read_frame_t) (switch_core_session_t *, switch_frame_t **, switch_io_flag_t, int);
@ -490,6 +470,7 @@ struct switch_say_interface {
const char *interface_name;
/*! function to pass down to the module */
switch_say_callback_t say_function;
switch_say_string_callback_t say_string_function;
switch_thread_rwlock_t *rwlock;
int refs;
switch_mutex_t *reflock;

View File

@ -36,6 +36,7 @@
#define SWITCH_TYPES_H
#include <switch.h>
SWITCH_BEGIN_EXTERN_C
#define SWITCH_ENT_ORIGINATE_DELIM ":_:"
#define SWITCH_BLANK_STRING ""
@ -1735,6 +1736,7 @@ typedef switch_status_t (*switch_stream_handle_raw_write_function_t) (switch_str
typedef switch_status_t (*switch_api_function_t) (_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session,
_In_ switch_stream_handle_t *stream);
#define SWITCH_STANDARD_API(name) static switch_status_t name (_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream)
typedef switch_status_t (*switch_input_callback_function_t) (switch_core_session_t *session, void *input,
@ -1772,17 +1774,32 @@ typedef struct {
switch_ivr_dmachine_t *dmachine;
} switch_input_args_t;
typedef struct {
switch_say_type_t type;
switch_say_method_t method;
switch_say_gender_t gender;
const char *ext;
} switch_say_args_t;
typedef switch_status_t (*switch_say_callback_t) (switch_core_session_t *session,
char *tosay,
switch_say_args_t *say_args,
switch_input_args_t *args);
typedef switch_status_t (*switch_say_string_callback_t) (switch_core_session_t *session,
char *tosay,
switch_say_args_t *say_args, char **rstr);
struct switch_say_file_handle;
typedef struct switch_say_file_handle switch_say_file_handle_t;
typedef switch_status_t (*switch_new_say_callback_t) (switch_say_file_handle_t *sh,
char *tosay,
switch_say_args_t *say_args);
typedef struct switch_xml *switch_xml_t;
typedef struct switch_core_time_duration switch_core_time_duration_t;
typedef switch_xml_t(*switch_xml_search_function_t) (const char *section,

View File

@ -116,6 +116,59 @@ static switch_status_t select_url(const char *user,
return SWITCH_STATUS_SUCCESS;
}
#define SAY_STRING_SYNTAX "<module_name>[.<ext>] <lang>[.<ext>] <say_type> <say_method> [<say_gender>] <text>"
SWITCH_STANDARD_API(say_string_function)
{
char *argv[6] = { 0 };
int argc;
char *lbuf = NULL, *string = NULL;
int err = 1, par = 0;
char *p, *ext = "wav";
if (cmd) {
lbuf = strdup(cmd);
}
if (lbuf && (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) && (argc == 5 || argc == 6)) {
if ((p = strchr(argv[0], '.'))) {
*p++ = '\0';
ext = p;
par++;
}
if (!par && (p = strchr(argv[1], '.'))) {
*p++ = '\0';
ext = p;
}
switch_ivr_say_string(session,
argv[1],
ext,
(argc == 5) ? argv[4] : argv[5],
argv[0],
argv[2],
argv[3],
(argc == 6) ? argv[4] : NULL ,
&string);
if (string) {
stream->write_function(stream, "%s", string);
free(string);
err = 0;
}
}
if (err) {
stream->write_function(stream, "-ERR Usage: %s\n", SAY_STRING_SYNTAX);
}
free(lbuf);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(reg_url_function)
{
char *data;
@ -5105,6 +5158,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
SWITCH_ADD_API(commands_api_interface, "reload", "Reload Module", reload_function, UNLOAD_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "reloadxml", "Reload XML", reload_xml_function, "");
SWITCH_ADD_API(commands_api_interface, "replace", "replace a string", replace_function, "<data>|<string1>|<string2>");
SWITCH_ADD_API(commands_api_interface, "say_string", "", say_string_function, SAY_STRING_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "sched_api", "Schedule an api command", sched_api_function, SCHED_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "sched_broadcast", "Schedule a broadcast event to a running call", sched_broadcast_function,
SCHED_BROADCAST_SYNTAX);

View File

@ -51,7 +51,8 @@
SWITCH_MODULE_LOAD_FUNCTION(mod_say_en_load);
SWITCH_MODULE_DEFINITION(mod_say_en, mod_say_en_load, NULL, NULL);
#define say_num(num, meth) { \
#define say_num(_sh, num, meth) { \
char tmp[80]; \
switch_status_t tstatus; \
switch_say_method_t smeth = say_args->method; \
@ -59,7 +60,7 @@ SWITCH_MODULE_DEFINITION(mod_say_en, mod_say_en_load, NULL, NULL);
say_args->type = SST_ITEMS; say_args->method = meth; \
switch_snprintf(tmp, sizeof(tmp), "%u", (unsigned)num); \
if ((tstatus = \
en_say_general_count(session, tmp, say_args, args)) \
en_say_general_count(_sh, tmp, say_args)) \
!= SWITCH_STATUS_SUCCESS) { \
return tstatus; \
} \
@ -67,57 +68,44 @@ SWITCH_MODULE_DEFINITION(mod_say_en, mod_say_en_load, NULL, NULL);
} \
#define say_file(...) { \
char tmp[80]; \
switch_status_t tstatus; \
switch_snprintf(tmp, sizeof(tmp), __VA_ARGS__); \
if ((tstatus = \
switch_ivr_play_file(session, NULL, tmp, args)) \
!= SWITCH_STATUS_SUCCESS){ \
return tstatus; \
} \
if (!switch_channel_ready(switch_core_session_get_channel(session))) { \
return SWITCH_STATUS_FALSE; \
}} \
static switch_status_t play_group(switch_say_method_t method, int a, int b, int c, char *what, switch_core_session_t *session, switch_input_args_t *args)
static switch_status_t play_group(switch_say_method_t method, int a, int b, int c, char *what, switch_say_file_handle_t *sh)
{
if (a) {
say_file("digits/%d.wav", a);
say_file("digits/hundred.wav");
switch_say_file(sh, "digits/%d", a);
switch_say_file(sh, "digits/hundred");
}
if (b) {
if (b > 1) {
if ((c == 0) && (method == SSM_COUNTED)) {
say_file("digits/h-%d0.wav", b);
switch_say_file(sh, "digits/h-%d0", b);
} else {
say_file("digits/%d0.wav", b);
switch_say_file(sh, "digits/%d0", b);
}
} else {
say_file("digits/%d%d.wav", b, c);
switch_say_file(sh, "digits/%d%d", b, c);
c = 0;
}
}
if (c) {
if (method == SSM_COUNTED) {
say_file("digits/h-%d.wav", c);
switch_say_file(sh, "digits/h-%d", c);
} else {
say_file("digits/%d.wav", c);
switch_say_file(sh, "digits/%d", c);
}
}
if (what && (a || b || c)) {
say_file(what);
switch_say_file(sh, what);
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t en_say_general_count(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
static switch_status_t en_say_general_count(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args)
{
int in;
int x = 0;
@ -129,7 +117,7 @@ static switch_status_t en_say_general_count(switch_core_session_t *session, char
if ((tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1))) {
char *p;
for (p = tosay; p && *p; p++) {
say_file("digits/%c.wav", *p);
switch_say_file(sh, "digits/%c", *p);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");
@ -156,13 +144,13 @@ static switch_status_t en_say_general_count(switch_core_session_t *session, char
switch (say_args->method) {
case SSM_COUNTED:
case SSM_PRONOUNCED:
if ((status = play_group(SSM_PRONOUNCED, places[8], places[7], places[6], "digits/million.wav", session, args)) != SWITCH_STATUS_SUCCESS) {
if ((status = play_group(SSM_PRONOUNCED, places[8], places[7], places[6], "digits/million", sh)) != SWITCH_STATUS_SUCCESS) {
return status;
}
if ((status = play_group(SSM_PRONOUNCED, places[5], places[4], places[3], "digits/thousand.wav", session, args)) != SWITCH_STATUS_SUCCESS) {
if ((status = play_group(SSM_PRONOUNCED, places[5], places[4], places[3], "digits/thousand", sh)) != SWITCH_STATUS_SUCCESS) {
return status;
}
if ((status = play_group(say_args->method, places[2], places[1], places[0], NULL, session, args)) != SWITCH_STATUS_SUCCESS) {
if ((status = play_group(say_args->method, places[2], places[1], places[0], NULL, sh)) != SWITCH_STATUS_SUCCESS) {
return status;
}
break;
@ -170,20 +158,21 @@ static switch_status_t en_say_general_count(switch_core_session_t *session, char
break;
}
} else {
say_file("digits/0.wav");
switch_say_file(sh, "digits/0");
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t en_say_time(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
static switch_status_t en_say_time(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args)
{
int32_t t;
switch_time_t target = 0, target_now = 0;
switch_time_exp_t tm, tm_now;
uint8_t say_date = 0, say_time = 0, say_year = 0, say_month = 0, say_dow = 0, say_day = 0, say_yesterday = 0, say_today = 0;
switch_channel_t *channel = switch_core_session_get_channel(session);
const char *tz = switch_channel_get_variable(channel, "timezone");
const char *tz = NULL;
tz = switch_say_file_handle_get_variable(sh, "timezone");
if (say_args->type == SST_TIME_MEASUREMENT) {
int64_t hours = 0;
@ -192,7 +181,7 @@ static switch_status_t en_say_time(switch_core_session_t *session, char *tosay,
int64_t r = 0;
if (strchr(tosay, ':')) {
char *tme = switch_core_session_strdup(session, tosay);
char *tme = strdup(tosay);
char *p;
if ((p = strrchr(tme, ':'))) {
@ -208,6 +197,7 @@ static switch_status_t en_say_time(switch_core_session_t *session, char *tosay,
minutes = atoi(tme);
}
}
free(tme);
} else {
if ((seconds = atol(tosay)) <= 0) {
seconds = (int64_t) switch_epoch_time_now(NULL);
@ -227,39 +217,39 @@ static switch_status_t en_say_time(switch_core_session_t *session, char *tosay,
}
if (hours) {
say_num(hours, SSM_PRONOUNCED);
say_num(sh, hours, SSM_PRONOUNCED);
if (hours == 1) {
say_file("time/hour.wav");
switch_say_file(sh, "time/hour");
} else {
say_file("time/hours.wav");
switch_say_file(sh, "time/hours");
}
} else {
say_file("digits/0.wav");
say_file("time/hours.wav");
switch_say_file(sh, "digits/0");
switch_say_file(sh, "time/hours");
}
if (minutes) {
say_num(minutes, SSM_PRONOUNCED);
say_num(sh, minutes, SSM_PRONOUNCED);
if (minutes == 1) {
say_file("time/minute.wav");
switch_say_file(sh, "time/minute");
} else {
say_file("time/minutes.wav");
switch_say_file(sh, "time/minutes");
}
} else {
say_file("digits/0.wav");
say_file("time/minutes.wav");
switch_say_file(sh, "digits/0");
switch_say_file(sh, "time/minutes");
}
if (seconds) {
say_num(seconds, SSM_PRONOUNCED);
say_num(sh, seconds, SSM_PRONOUNCED);
if (seconds == 1) {
say_file("time/second.wav");
switch_say_file(sh, "time/second");
} else {
say_file("time/seconds.wav");
switch_say_file(sh, "time/seconds");
}
} else {
say_file("digits/0.wav");
say_file("time/seconds.wav");
switch_say_file(sh, "digits/0");
switch_say_file(sh, "time/seconds");
}
return SWITCH_STATUS_SUCCESS;
@ -275,7 +265,7 @@ static switch_status_t en_say_time(switch_core_session_t *session, char *tosay,
if (tz) {
int check = atoi(tz);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Timezone is [%s]\n", tz);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Timezone is [%s]\n", tz);
if (check) {
switch_time_exp_tz(&tm, target, check);
switch_time_exp_tz(&tm_now, target_now, check);
@ -329,13 +319,13 @@ static switch_status_t en_say_time(switch_core_session_t *session, char *tosay,
}
if (say_today) {
say_file("time/today.wav");
switch_say_file(sh, "time/today");
}
if (say_yesterday) {
say_file("time/yesterday.wav");
switch_say_file(sh, "time/yesterday");
}
if (say_dow) {
say_file("time/day-%d.wav", tm.tm_wday);
switch_say_file(sh, "time/day-%d", tm.tm_wday);
}
if (say_date) {
@ -344,20 +334,20 @@ static switch_status_t en_say_time(switch_core_session_t *session, char *tosay,
}
if (say_month) {
say_file("time/mon-%d.wav", tm.tm_mon);
switch_say_file(sh, "time/mon-%d", tm.tm_mon);
}
if (say_day) {
say_num(tm.tm_mday, SSM_COUNTED);
say_num(sh, tm.tm_mday, SSM_COUNTED);
}
if (say_year) {
say_num(tm.tm_year + 1900, SSM_PRONOUNCED);
say_num(sh, tm.tm_year + 1900, SSM_PRONOUNCED);
}
if (say_time) {
int32_t hour = tm.tm_hour, pm = 0;
if (say_date || say_today || say_yesterday || say_dow) {
say_file("time/at.wav");
switch_say_file(sh, "time/at");
}
if (hour > 12) {
@ -370,25 +360,25 @@ static switch_status_t en_say_time(switch_core_session_t *session, char *tosay,
pm = 0;
}
say_num(hour, SSM_PRONOUNCED);
say_num(sh, hour, SSM_PRONOUNCED);
if (tm.tm_min > 9) {
say_num(tm.tm_min, SSM_PRONOUNCED);
say_num(sh, tm.tm_min, SSM_PRONOUNCED);
} else if (tm.tm_min) {
say_file("time/oh.wav");
say_num(tm.tm_min, SSM_PRONOUNCED);
switch_say_file(sh, "time/oh");
say_num(sh, tm.tm_min, SSM_PRONOUNCED);
} else {
say_file("time/oclock.wav");
switch_say_file(sh, "time/oclock");
}
say_file("time/%s.wav", pm ? "p-m" : "a-m");
switch_say_file(sh, "time/%s", pm ? "p-m" : "a-m");
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t en_say_money(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
static switch_status_t en_say_money(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args)
{
char sbuf[16] = ""; /* enough for 999,999,999,999.99 (w/o the commas or leading $) */
char *dollars = NULL;
@ -415,43 +405,108 @@ static switch_status_t en_say_money(switch_core_session_t *session, char *tosay,
/* If negative say "negative" */
if (sbuf[0] == '-') {
say_file("currency/negative.wav");
switch_say_file(sh, "currency/negative");
dollars++;
}
/* Say dollar amount */
en_say_general_count(session, dollars, say_args, args);
en_say_general_count(sh, dollars, say_args);
if (atoi(dollars) == 1) {
say_file("currency/dollar.wav");
switch_say_file(sh, "currency/dollar");
} else {
say_file("currency/dollars.wav");
switch_say_file(sh, "currency/dollars");
}
/* Say "and" */
say_file("currency/and.wav");
switch_say_file(sh, "currency/and");
/* Say cents */
if (cents) {
en_say_general_count(session, cents, say_args, args);
en_say_general_count(sh, cents, say_args);
if (atoi(cents) == 1) {
say_file("currency/cent.wav");
switch_say_file(sh, "currency/cent");
} else {
say_file("currency/cents.wav");
switch_say_file(sh, "currency/cents");
}
} else {
say_file("digits/0.wav");
say_file("currency/cents.wav");
switch_say_file(sh, "digits/0");
switch_say_file(sh, "currency/cents");
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t en_say(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
static switch_status_t say_ip(switch_say_file_handle_t *sh,
char *tosay,
switch_say_args_t *say_args)
{
char *a, *b, *c, *d;
switch_status_t status = SWITCH_STATUS_FALSE;
if (!(a = strdup(tosay))) {
abort();
}
switch_say_callback_t say_cb = NULL;
if (!(b = strchr(a, '.'))) {
goto end;
}
*b++ = '\0';
if (!(c = strchr(b, '.'))) {
goto end;
}
*c++ = '\0';
if (!(d = strchr(c, '.'))) {
goto end;
}
*d++ = '\0';
say_num(sh, atoi(a), say_args->method);
switch_say_file(sh, "digits/dot");
say_num(sh, atoi(b), say_args->method);
switch_say_file(sh, "digits/dot");
say_num(sh, atoi(c), say_args->method);
switch_say_file(sh, "digits/dot");
say_num(sh, atoi(d), say_args->method);
end:
free(a);
return status;
}
static switch_status_t say_spell(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args)
{
char *p;
for (p = tosay; p && *p; p++) {
int a = tolower((int) *p);
if (a >= '0' && a <= '9') {
switch_say_file(sh, "digits/%d", a - '0');
} else {
if (say_args->type == SST_NAME_SPELLED) {
switch_say_file(sh, "ascii/%d", a);
} else if (say_args->type == SST_NAME_PHONETIC) {
switch_say_file(sh, "phonetic-ascii/%d", a);
}
}
}
return SWITCH_STATUS_SUCCESS;
}
static switch_new_say_callback_t choose_callback(switch_say_args_t *say_args)
{
switch_new_say_callback_t say_cb = NULL;
switch (say_args->type) {
case SST_NUMBER:
@ -468,11 +523,11 @@ static switch_status_t en_say(switch_core_session_t *session, char *tosay, switc
say_cb = en_say_time;
break;
case SST_IP_ADDRESS:
return switch_ivr_say_ip(session, tosay, en_say_general_count, say_args, args);
say_cb = say_ip;
break;
case SST_NAME_SPELLED:
case SST_NAME_PHONETIC:
return switch_ivr_say_spell(session, tosay, say_args, args);
say_cb = say_spell;
break;
case SST_CURRENCY:
say_cb = en_say_money;
@ -482,11 +537,77 @@ static switch_status_t en_say(switch_core_session_t *session, char *tosay, switc
break;
}
if (say_cb) {
return say_cb(session, tosay, say_args, args);
return say_cb;
}
static switch_status_t run_callback(switch_new_say_callback_t say_cb, char *tosay, switch_say_args_t *say_args, switch_core_session_t *session, char **rstr)
{
switch_say_file_handle_t *sh;
switch_status_t status = SWITCH_STATUS_FALSE;
switch_event_t *var_event = NULL;
if (session) {
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_channel_get_variables(channel, &var_event);
}
return SWITCH_STATUS_FALSE;
switch_say_file_handle_create(&sh, say_args->ext, &var_event);
status = say_cb(sh, tosay, say_args);
if ((*rstr = switch_say_file_handle_detach_path(sh))) {
status = SWITCH_STATUS_SUCCESS;
}
switch_say_file_handle_destroy(&sh);
return status;
}
static switch_status_t en_say(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
{
switch_new_say_callback_t say_cb = NULL;
char *string = NULL;
switch_status_t status = SWITCH_STATUS_FALSE;
say_cb = choose_callback(say_args);
if (say_cb) {
status = run_callback(say_cb, tosay, say_args, session, &string);
if (session && string) {
status = switch_ivr_play_file(session, NULL, string, args);
}
switch_safe_free(string);
}
return status;
}
static switch_status_t en_say_string(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, char **rstr)
{
switch_new_say_callback_t say_cb = NULL;
char *string = NULL;
switch_status_t status = SWITCH_STATUS_FALSE;
say_cb = choose_callback(say_args);
if (say_cb) {
status = run_callback(say_cb, tosay, say_args, session, &string);
if (string) {
status = SWITCH_STATUS_SUCCESS;
*rstr = string;
}
}
return status;
}
SWITCH_MODULE_LOAD_FUNCTION(mod_say_en_load)
@ -497,7 +618,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_say_en_load)
say_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_SAY_INTERFACE);
say_interface->interface_name = "en";
say_interface->say_function = en_say;
say_interface->say_string_function = en_say_string;
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
}

View File

@ -2943,7 +2943,7 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel
char *data, *indup, *endof_indup;
size_t sp = 0, len = 0, olen = 0, vtype = 0, br = 0, cpos, block = 128;
char *cloned_sub_val = NULL, *sub_val = NULL;
char *func_val = NULL;
char *func_val = NULL, *sb = NULL;
int nv = 0;
if (zstr(in)) {
@ -3033,8 +3033,19 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel
}
p = e > endof_indup ? endof_indup : e;
if ((vval = strchr(vname, '(')) || (vval = strchr(vname, ' '))) {
if (*vval == '(') br = 1;
vval = NULL;
for(sb = vname; sb && *sb; sb++) {
if (*sb == ' ') {
vval = sb;
break;
} else if (*sb == '(') {
vval = sb;
br = 1;
break;
}
}
if (vval) {
e = vval - 1;
*vval++ = '\0';
while (*e == ' ') {

View File

@ -1563,7 +1563,7 @@ SWITCH_DECLARE(char *) switch_event_expand_headers(switch_event_t *event, const
char *cloned_sub_val = NULL;
char *func_val = NULL;
int nv = 0;
char *gvar = NULL;
char *gvar = NULL, *sb = NULL;
if (zstr(in)) {
return (char *) in;
@ -1651,10 +1651,22 @@ SWITCH_DECLARE(char *) switch_event_expand_headers(switch_event_t *event, const
}
p = e > endof_indup ? endof_indup : e;
if ((vval = strchr(vname, '(')) || (vval = strchr(vname, ' '))) {
if (*vval == '(') br = 1;
vval = NULL;
for(sb = vname; sb && *sb; sb++) {
if (*sb == ' ') {
vval = sb;
break;
} else if (*sb == '(') {
vval = sb;
br = 1;
break;
}
}
if (vval) {
e = vval - 1;
*vval++ = '\0';
while (*e == ' ') {
*e-- = '\0';
}

View File

@ -2432,6 +2432,134 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say(switch_core_session_t *session,
return status;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_say_string(switch_core_session_t *session,
const char *lang,
const char *ext,
const char *tosay,
const char *module_name,
const char *say_type,
const char *say_method,
const char *say_gender,
char **rstr)
{
switch_say_interface_t *si;
switch_channel_t *channel = NULL;
switch_status_t status = SWITCH_STATUS_FALSE;
const char *save_path = NULL, *chan_lang = NULL, *lname = NULL, *sound_path = NULL;
switch_event_t *hint_data;
switch_xml_t cfg, xml = NULL, language, macros;
if (session) {
channel = switch_core_session_get_channel(session);
if (!lang) {
lang = switch_channel_get_variable(channel, "language");
if (!lang) {
chan_lang = switch_channel_get_variable(channel, "default_language");
if (!chan_lang) {
chan_lang = "en";
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No language specified - Using [%s]\n", chan_lang);
} else {
chan_lang = lang;
}
}
}
if (!lang) lang = "en";
if (!chan_lang) chan_lang = lang;
switch_event_create(&hint_data, SWITCH_EVENT_REQUEST_PARAMS);
switch_assert(hint_data);
switch_event_add_header_string(hint_data, SWITCH_STACK_BOTTOM, "macro_name", "say_app");
switch_event_add_header_string(hint_data, SWITCH_STACK_BOTTOM, "lang", chan_lang);
if (channel) {
switch_channel_event_set_data(channel, hint_data);
}
if (switch_xml_locate("phrases", NULL, NULL, NULL, &xml, &cfg, hint_data, SWITCH_TRUE) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Open of phrases failed.\n");
goto done;
}
if (!(macros = switch_xml_child(cfg, "macros"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find macros tag.\n");
goto done;
}
if (!(language = switch_xml_child(macros, "language"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find language tag.\n");
goto done;
}
while (language) {
if ((lname = (char *) switch_xml_attr(language, "name")) && !strcasecmp(lname, chan_lang)) {
const char *tmp;
if ((tmp = switch_xml_attr(language, "module"))) {
module_name = tmp;
}
break;
}
language = language->next;
}
if (!language) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find language %s.\n", chan_lang);
goto done;
}
if (!module_name) {
module_name = chan_lang;
}
if (!(sound_path = (char *) switch_xml_attr(language, "sound-path"))) {
sound_path = (char *) switch_xml_attr(language, "sound_path");
}
if (channel) {
save_path = switch_channel_get_variable(channel, "sound_prefix");
}
if (sound_path && channel) {
switch_channel_set_variable(channel, "sound_prefix", sound_path);
}
if ((si = switch_loadable_module_get_say_interface(module_name))) {
/* should go back and proto all the say mods to const.... */
switch_say_args_t say_args = {0};
say_args.type = switch_ivr_get_say_type_by_name(say_type);
say_args.method = switch_ivr_get_say_method_by_name(say_method);
say_args.gender = switch_ivr_get_say_gender_by_name(say_gender);
say_args.ext = ext;
status = si->say_string_function(session, (char *) tosay, &say_args, rstr);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid SAY Interface [%s]!\n", module_name);
status = SWITCH_STATUS_FALSE;
}
done:
if (hint_data) {
switch_event_destroy(&hint_data);
}
if (save_path && channel) {
switch_channel_set_variable(channel, "sound_prefix", save_path);
}
if (xml) {
switch_xml_free(xml);
}
return status;
}
static const char *get_prefixed_str(char *buffer, size_t buffer_size, const char *prefix, size_t prefix_size, const char *str)
{
size_t str_len;

View File

@ -1918,6 +1918,97 @@ SWITCH_DECLARE(void *) switch_loadable_module_create_interface(switch_loadable_m
}
}
struct switch_say_file_handle {
char *ext;
int cnt;
struct switch_stream_handle stream;
switch_event_t *param_event;
};
SWITCH_DECLARE(char *) switch_say_file_handle_get_variable(switch_say_file_handle_t *sh, const char *var)
{
char *ret = NULL;
if (sh->param_event) {
ret = switch_event_get_header(sh->param_event, var);
}
return ret;
}
SWITCH_DECLARE(char *) switch_say_file_handle_get_path(switch_say_file_handle_t *sh)
{
return (char *) sh->stream.data;
}
SWITCH_DECLARE(char *) switch_say_file_handle_detach_path(switch_say_file_handle_t *sh)
{
char *path;
switch_assert(sh);
path = (char *) sh->stream.data;
sh->stream.data = NULL;
return path;
}
SWITCH_DECLARE(void) switch_say_file_handle_destroy(switch_say_file_handle_t **sh)
{
switch_assert(sh);
switch_safe_free((*sh)->stream.data);
switch_safe_free((*sh)->ext);
if ((*sh)->param_event) {
switch_event_destroy(&(*sh)->param_event);
}
free(*sh);
*sh = NULL;
}
SWITCH_DECLARE(switch_status_t) switch_say_file_handle_create(switch_say_file_handle_t **sh, const char *ext, switch_event_t **var_event)
{
switch_assert(sh);
*sh = malloc(sizeof(**sh));
memset(*sh, 0, sizeof(**sh));
SWITCH_STANDARD_STREAM((*sh)->stream);
if (var_event) {
(*sh)->param_event = *var_event;
*var_event = NULL;
}
(*sh)->ext = strdup(ext);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(void) switch_say_file(switch_say_file_handle_t *sh, const char *fmt, ...)
{
char buf[256] = "";
int ret;
va_list ap;
va_start(ap, fmt);
if ((ret = switch_vsnprintf(buf, sizeof(buf), fmt, ap)) > 0) {
if (!sh->cnt++) {
sh->stream.write_function(&sh->stream, "file_string://%s.%s", buf, sh->ext);
} else {
sh->stream.write_function(&sh->stream, "!%s.%s", buf, sh->ext);
}
}
va_end(ap);
}
/* For Emacs:
* Local Variables:
* mode:c