Trivial application to playback a sound file. More...
#include "asterisk.h"#include "asterisk/file.h"#include "asterisk/pbx.h"#include "asterisk/module.h"#include "asterisk/app.h"#include "asterisk/say.h"#include "asterisk/cli.h"
Go to the source code of this file.
Data Structures | |
| struct | say_args_t |
Functions | |
| static void | __reg_module (void) |
| static char * | __say_cli_init (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static void | __unreg_module (void) |
| static int | do_say (say_args_t *a, const char *s, const char *options, int depth) |
| static int | load_module (void) |
| static int | playback_exec (struct ast_channel *chan, void *data) |
| static int | reload (void) |
| static void | restore_say_mode (void *arg) |
| static int | s_streamwait3 (const say_args_t *a, const char *fn) |
| static void | save_say_mode (const void *arg) |
| static int | say_date (struct ast_channel *chan, time_t t, const char *ints, const char *lang) |
| static int | say_date_generic (struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *timezonename, const char *prefix) |
| static int | say_date_with_format (struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *timezonename) |
| static int | say_datetime (struct ast_channel *chan, time_t t, const char *ints, const char *lang) |
| static int | say_enumeration_full (struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) |
| static int | say_full (struct ast_channel *chan, const char *string, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) |
| static int | say_init_mode (const char *mode) |
| static int | say_number_full (struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) |
| static int | say_time (struct ast_channel *chan, time_t t, const char *ints, const char *lang) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info __MODULE_INFO_SECTION | __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Sound File Playback Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } |
| static char * | app = "Playback" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_cli_entry | cli_playback [] |
| static const void * | say_api_buf [40] |
| static struct ast_config * | say_cfg = NULL |
| static const char * | say_new = "new" |
| static const char * | say_old = "old" |
Trivial application to playback a sound file.
Definition in file app_playback.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 554 of file app_playback.c.
| static char* __say_cli_init | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 380 of file app_playback.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, say_init_mode(), say_old, and ast_cli_entry::usage.
{
const char *old_mode = say_api_buf[0] ? say_new : say_old;
char *mode;
switch (cmd) {
case CLI_INIT:
e->command = "say load [new|old]";
e->usage =
"Usage: say load [new|old]\n"
" say load\n"
" Report status of current say mode\n"
" say load new\n"
" Set say method, configured in say.conf\n"
" say load old\n"
" Set old say method, coded in asterisk core\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc == 2) {
ast_cli(a->fd, "say mode is [%s]\n", old_mode);
return CLI_SUCCESS;
} else if (a->argc != e->args)
return CLI_SHOWUSAGE;
mode = a->argv[2];
if (!strcmp(mode, old_mode))
ast_cli(a->fd, "say mode is %s already\n", mode);
else
if (say_init_mode(mode) == 0)
ast_cli(a->fd, "setting say mode from %s to %s\n", old_mode, mode);
return CLI_SUCCESS;
}
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 554 of file app_playback.c.
| static int do_say | ( | say_args_t * | a, |
| const char * | s, | ||
| const char * | options, | ||
| int | depth | ||
| ) | [static] |
Definition at line 162 of file app_playback.c.
References ast_debug, ast_extension_match(), AST_LIST_INSERT_HEAD, ast_log(), ast_skip_blanks(), ast_strdupa, ast_trim_blanks(), ast_var_assign(), ast_var_delete(), ast_variable_browse(), ast_var_t::entries, varshead::first, say_args_t::language, LOG_WARNING, ast_variable::name, ast_variable::next, pbx_substitute_variables_varshead(), s_streamwait3(), strsep(), and ast_variable::value.
Referenced by say_date_generic(), say_enumeration_full(), say_full(), and say_number_full().
{
struct ast_variable *v;
char *lang, *x, *rule = NULL;
int ret = 0;
struct varshead head = { .first = NULL, .last = NULL };
struct ast_var_t *n;
ast_debug(2, "string <%s> depth <%d>\n", s, depth);
if (depth++ > 10) {
ast_log(LOG_WARNING, "recursion too deep, exiting\n");
return -1;
} else if (!say_cfg) {
ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s);
return -1;
}
/* scan languages same as in file.c */
if (a->language == NULL)
a->language = "en"; /* default */
ast_debug(2, "try <%s> in <%s>\n", s, a->language);
lang = ast_strdupa(a->language);
for (;;) {
for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) {
if (ast_extension_match(v->name, s)) {
rule = ast_strdupa(v->value);
break;
}
}
if (rule)
break;
if ( (x = strchr(lang, '_')) )
*x = '\0'; /* try without suffix */
else if (strcmp(lang, "en"))
lang = "en"; /* last resort, try 'en' if not done yet */
else
break;
}
if (!rule)
return 0;
/* skip up to two prefixes to get the value */
if ( (x = strchr(s, ':')) )
s = x + 1;
if ( (x = strchr(s, ':')) )
s = x + 1;
ast_debug(2, "value is <%s>\n", s);
n = ast_var_assign("SAY", s);
AST_LIST_INSERT_HEAD(&head, n, entries);
/* scan the body, one piece at a time */
while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */
char fn[128];
const char *p, *fmt, *data; /* format and data pointers */
/* prepare a decent file name */
x = ast_skip_blanks(x);
ast_trim_blanks(x);
/* replace variables */
pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn));
ast_debug(2, "doing [%s]\n", fn);
/* locate prefix and data, if any */
fmt = strchr(fn, ':');
if (!fmt || fmt == fn) { /* regular filename */
ret = s_streamwait3(a, fn);
continue;
}
fmt++;
data = strchr(fmt, ':'); /* colon before data */
if (!data || data == fmt) { /* simple prefix-fmt */
ret = do_say(a, fn, options, depth);
continue;
}
/* prefix:fmt:data */
for (p = fmt; p < data && ret <= 0; p++) {
char fn2[sizeof(fn)];
if (*p == ' ' || *p == '\t') /* skip blanks */
continue;
if (*p == '\'') {/* file name - we trim them */
char *y;
strcpy(fn2, ast_skip_blanks(p+1)); /* make a full copy */
y = strchr(fn2, '\'');
if (!y) {
p = data; /* invalid. prepare to end */
break;
}
*y = '\0';
ast_trim_blanks(fn2);
p = strchr(p+1, '\'');
ret = s_streamwait3(a, fn2);
} else {
int l = fmt-fn;
strcpy(fn2, fn); /* copy everything */
/* after prefix, append the format */
fn2[l++] = *p;
strcpy(fn2 + l, data);
ret = do_say(a, fn2, options, depth);
}
if (ret) {
break;
}
}
}
ast_var_delete(n);
return ret;
}
| static int load_module | ( | void | ) | [static] |
Definition at line 531 of file app_playback.c.
References ARRAY_LEN, ast_cli_register_multiple(), ast_config_load, ast_extension_match(), ast_register_application_xml, ast_variable_browse(), CONFIG_STATUS_FILEINVALID, ast_variable::name, ast_variable::next, playback_exec(), say_init_mode(), and ast_variable::value.
{
struct ast_variable *v;
struct ast_flags config_flags = { 0 };
say_cfg = ast_config_load("say.conf", config_flags);
if (say_cfg && say_cfg != CONFIG_STATUS_FILEINVALID) {
for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {
if (ast_extension_match(v->name, "mode")) {
say_init_mode(v->value);
break;
}
}
}
ast_cli_register_multiple(cli_playback, ARRAY_LEN(cli_playback));
return ast_register_application_xml(app, playback_exec);
}
| static int playback_exec | ( | struct ast_channel * | chan, |
| void * | data | ||
| ) | [static] |
Definition at line 418 of file app_playback.c.
References ast_channel::_state, ast_cli_entry::args, ast_answer(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_waitstream(), ast_channel::language, LOG_WARNING, ast_channel::name, pbx_builtin_setvar_helper(), say_full(), strcasestr(), and strsep().
Referenced by load_module().
{
int res = 0;
int mres = 0;
char *tmp;
int option_skip=0;
int option_say=0;
int option_noanswer = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(filenames);
AST_APP_ARG(options);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Playback requires an argument (filename)\n");
return -1;
}
tmp = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, tmp);
if (args.options) {
if (strcasestr(args.options, "skip"))
option_skip = 1;
if (strcasestr(args.options, "say"))
option_say = 1;
if (strcasestr(args.options, "noanswer"))
option_noanswer = 1;
}
if (chan->_state != AST_STATE_UP) {
if (option_skip) {
/* At the user's option, skip if the line is not up */
goto done;
} else if (!option_noanswer) {
/* Otherwise answer unless we're supposed to send this while on-hook */
res = ast_answer(chan);
}
}
if (!res) {
char *back = args.filenames;
char *front;
ast_stopstream(chan);
while (!res && (front = strsep(&back, "&"))) {
if (option_say)
res = say_full(chan, front, "", chan->language, NULL, -1, -1);
else
res = ast_streamfile(chan, front, chan->language);
if (!res) {
res = ast_waitstream(chan, "");
ast_stopstream(chan);
} else {
ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
res = 0;
mres = 1;
}
}
}
done:
pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", mres ? "FAILED" : "SUCCESS");
return res;
}
| static int reload | ( | void | ) | [static] |
Definition at line 482 of file app_playback.c.
References ast_config_destroy(), ast_config_load, ast_extension_match(), ast_log(), ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, LOG_ERROR, LOG_NOTICE, ast_variable::name, ast_variable::next, say_init_mode(), and ast_variable::value.
{
struct ast_variable *v;
struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
struct ast_config *newcfg;
if ((newcfg = ast_config_load("say.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
return 0;
} else if (newcfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_ERROR, "Config file say.conf is in an invalid format. Aborting.\n");
return 0;
}
if (say_cfg) {
ast_config_destroy(say_cfg);
ast_log(LOG_NOTICE, "Reloading say.conf\n");
say_cfg = newcfg;
}
if (say_cfg) {
for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {
if (ast_extension_match(v->name, "mode")) {
say_init_mode(v->value);
break;
}
}
}
/*
* XXX here we should sort rules according to the same order
* we have in pbx.c so we have the same matching behaviour.
*/
return 0;
}
| static void restore_say_mode | ( | void * | arg | ) | [static] |
Definition at line 113 of file app_playback.c.
References ast_say_character_str_full, ast_say_date, ast_say_date_with_format, ast_say_datetime, ast_say_datetime_from_now, ast_say_digit_str_full, ast_say_enumeration_full, ast_say_number_full, ast_say_phonetic_str_full, and ast_say_time.
Referenced by say_init_mode().
{
int i = 0;
say_api_buf[i++] = arg;
ast_say_number_full = say_api_buf[i++];
ast_say_enumeration_full = say_api_buf[i++];
ast_say_digit_str_full = say_api_buf[i++];
ast_say_character_str_full = say_api_buf[i++];
ast_say_phonetic_str_full = say_api_buf[i++];
ast_say_datetime = say_api_buf[i++];
ast_say_time = say_api_buf[i++];
ast_say_date = say_api_buf[i++];
ast_say_datetime_from_now = say_api_buf[i++];
ast_say_date_with_format = say_api_buf[i++];
}
| static int s_streamwait3 | ( | const say_args_t * | a, |
| const char * | fn | ||
| ) | [static] |
Definition at line 144 of file app_playback.c.
References ast_log(), ast_stopstream(), ast_streamfile(), ast_waitstream(), ast_waitstream_full(), say_args_t::audiofd, say_args_t::chan, say_args_t::ctrlfd, say_args_t::ints, say_args_t::language, and LOG_WARNING.
Referenced by do_say().
{
int res = ast_streamfile(a->chan, fn, a->language);
if (res) {
ast_log(LOG_WARNING, "Unable to play message %s\n", fn);
return res;
}
res = (a->audiofd > -1 && a->ctrlfd > -1) ?
ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) :
ast_waitstream(a->chan, a->ints);
ast_stopstream(a->chan);
return res;
}
| static void save_say_mode | ( | const void * | arg | ) | [static] |
Definition at line 96 of file app_playback.c.
References ast_say_character_str_full, ast_say_date, ast_say_date_with_format, ast_say_datetime, ast_say_datetime_from_now, ast_say_digit_str_full, ast_say_enumeration_full, ast_say_number_full, ast_say_phonetic_str_full, and ast_say_time.
Referenced by say_init_mode().
{
int i = 0;
say_api_buf[i++] = arg;
say_api_buf[i++] = ast_say_number_full;
say_api_buf[i++] = ast_say_enumeration_full;
say_api_buf[i++] = ast_say_digit_str_full;
say_api_buf[i++] = ast_say_character_str_full;
say_api_buf[i++] = ast_say_phonetic_str_full;
say_api_buf[i++] = ast_say_datetime;
say_api_buf[i++] = ast_say_time;
say_api_buf[i++] = ast_say_date;
say_api_buf[i++] = ast_say_datetime_from_now;
say_api_buf[i++] = ast_say_date_with_format;
}
| static int say_date | ( | struct ast_channel * | chan, |
| time_t | t, | ||
| const char * | ints, | ||
| const char * | lang | ||
| ) | [static] |
Definition at line 331 of file app_playback.c.
References say_date_generic().
Referenced by say_init_mode().
{
return say_date_generic(chan, t, ints, lang, "", NULL, "date");
}
| static int say_date_generic | ( | struct ast_channel * | chan, |
| time_t | t, | ||
| const char * | ints, | ||
| const char * | lang, | ||
| const char * | format, | ||
| const char * | timezonename, | ||
| const char * | prefix | ||
| ) | [static] |
Definition at line 300 of file app_playback.c.
References ast_localtime(), buf, chan, do_say(), ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, ast_tm::tm_wday, ast_tm::tm_yday, and ast_tm::tm_year.
Referenced by say_date(), say_date_with_format(), say_datetime(), and say_time().
{
char buf[128];
struct ast_tm tm;
struct timeval when = { t, 0 };
say_args_t a = { chan, ints, lang, -1, -1 };
if (format == NULL)
format = "";
ast_localtime(&when, &tm, NULL);
snprintf(buf, sizeof(buf), "%s:%s:%04d%02d%02d%02d%02d.%02d-%d-%3d",
prefix,
format,
tm.tm_year+1900,
tm.tm_mon+1,
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec,
tm.tm_wday,
tm.tm_yday);
return do_say(&a, buf, NULL, 0);
}
| static int say_date_with_format | ( | struct ast_channel * | chan, |
| time_t | t, | ||
| const char * | ints, | ||
| const char * | lang, | ||
| const char * | format, | ||
| const char * | timezonename | ||
| ) | [static] |
Definition at line 325 of file app_playback.c.
References say_date_generic().
Referenced by say_init_mode().
{
return say_date_generic(chan, t, ints, lang, format, timezonename, "datetime");
}
| static int say_datetime | ( | struct ast_channel * | chan, |
| time_t | t, | ||
| const char * | ints, | ||
| const char * | lang | ||
| ) | [static] |
Definition at line 341 of file app_playback.c.
References say_date_generic().
Referenced by say_init_mode().
{
return say_date_generic(chan, t, ints, lang, "", NULL, "datetime");
}
| static int say_enumeration_full | ( | struct ast_channel * | chan, |
| int | num, | ||
| const char * | ints, | ||
| const char * | lang, | ||
| const char * | options, | ||
| int | audiofd, | ||
| int | ctrlfd | ||
| ) | [static] |
Definition at line 290 of file app_playback.c.
References buf, chan, and do_say().
Referenced by say_init_mode().
{
char buf[64];
say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
snprintf(buf, sizeof(buf), "enum:%d", num);
return do_say(&a, buf, options, 0);
}
| static int say_full | ( | struct ast_channel * | chan, |
| const char * | string, | ||
| const char * | ints, | ||
| const char * | lang, | ||
| const char * | options, | ||
| int | audiofd, | ||
| int | ctrlfd | ||
| ) | [static] |
Definition at line 272 of file app_playback.c.
References chan, and do_say().
Referenced by playback_exec().
{
say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
return do_say(&a, string, options, 0);
}
| static int say_init_mode | ( | const char * | mode | ) | [static] |
Definition at line 349 of file app_playback.c.
References ast_log(), ast_say_character_str_full, ast_say_date, ast_say_date_with_format, ast_say_datetime, ast_say_datetime_from_now, ast_say_digit_str_full, ast_say_digits_full(), ast_say_enumeration_full, ast_say_number_full, ast_say_phonetic_str_full, ast_say_time, LOG_ERROR, LOG_WARNING, restore_say_mode(), save_say_mode(), say_character_str_full(), say_date(), say_date_with_format(), say_datetime(), say_datetime_from_now(), say_digit_str_full(), say_enumeration_full(), say_number_full(), say_phonetic_str_full(), and say_time().
Referenced by __say_cli_init(), load_module(), and reload().
{
if (!strcmp(mode, say_new)) {
if (say_cfg == NULL) {
ast_log(LOG_ERROR, "There is no say.conf file to use new mode\n");
return -1;
}
save_say_mode(say_new);
ast_say_number_full = say_number_full;
ast_say_enumeration_full = say_enumeration_full;
#if 0
ast_say_digits_full = say_digits_full;
ast_say_digit_str_full = say_digit_str_full;
ast_say_character_str_full = say_character_str_full;
ast_say_phonetic_str_full = say_phonetic_str_full;
ast_say_datetime_from_now = say_datetime_from_now;
#endif
ast_say_datetime = say_datetime;
ast_say_time = say_time;
ast_say_date = say_date;
ast_say_date_with_format = say_date_with_format;
} else if (!strcmp(mode, say_old) && say_api_buf[0] == say_new) {
restore_say_mode(NULL);
} else if (strcmp(mode, say_old)) {
ast_log(LOG_WARNING, "unrecognized mode %s\n", mode);
return -1;
}
return 0;
}
| static int say_number_full | ( | struct ast_channel * | chan, |
| int | num, | ||
| const char * | ints, | ||
| const char * | lang, | ||
| const char * | options, | ||
| int | audiofd, | ||
| int | ctrlfd | ||
| ) | [static] |
Definition at line 280 of file app_playback.c.
References buf, chan, and do_say().
Referenced by say_init_mode().
{
char buf[64];
say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
snprintf(buf, sizeof(buf), "num:%d", num);
return do_say(&a, buf, options, 0);
}
| static int say_time | ( | struct ast_channel * | chan, |
| time_t | t, | ||
| const char * | ints, | ||
| const char * | lang | ||
| ) | [static] |
Definition at line 336 of file app_playback.c.
References say_date_generic().
Referenced by say_init_mode().
{
return say_date_generic(chan, t, ints, lang, "", NULL, "time");
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 517 of file app_playback.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), ast_config_destroy(), and ast_unregister_application().
{
int res;
res = ast_unregister_application(app);
ast_cli_unregister_multiple(cli_playback, ARRAY_LEN(cli_playback));
if (say_cfg)
ast_config_destroy(say_cfg);
return res;
}
struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Sound File Playback Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 554 of file app_playback.c.
char* app = "Playback" [static] |
Definition at line 84 of file app_playback.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 554 of file app_playback.c.
struct ast_cli_entry cli_playback[] [static] |
{
AST_CLI_DEFINE(__say_cli_init, "Set or show the say mode"),
}
Definition at line 414 of file app_playback.c.
const void* say_api_buf[40] [static] |
Definition at line 92 of file app_playback.c.
struct ast_config* say_cfg = NULL [static] |
Definition at line 86 of file app_playback.c.
const char* say_new = "new" [static] |
Definition at line 94 of file app_playback.c.
const char* say_old = "old" [static] |
Definition at line 93 of file app_playback.c.
Referenced by __say_cli_init().