#include "asterisk.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/utils.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/cli.h"
#include "asterisk/localtime.h"
#include "asterisk/say.h"
Include dependency graph for app_playback.c:
Go to the source code of this file.
Data Structures | |
struct | say_args_t |
Functions | |
static int | __say_init (int fd, int argc, char *argv[]) |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Sound File Playback Application",.load=load_module,.unload=unload_module,.reload=reload,) | |
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 *timezone, 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 *timezone) |
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_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 char * | app = "Playback" |
static struct ast_cli_entry | cli_playback [] |
static char * | descrip |
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" |
static char * | synopsis = "Play a file" |
Definition in file app_playback.c.
static int __say_init | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 330 of file app_playback.c.
References ast_cli(), ast_config_load(), 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_WARNING, restore_say_mode(), RESULT_SHOWUSAGE, RESULT_SUCCESS, save_say_mode(), say_cfg, 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().
00331 { 00332 const char *old_mode = say_api_buf[0] ? say_new : say_old; 00333 char *mode; 00334 00335 if (argc == 2) { 00336 ast_cli(fd, "say mode is [%s]\n", old_mode); 00337 return RESULT_SUCCESS; 00338 } else if (argc != 3) 00339 return RESULT_SHOWUSAGE; 00340 mode = argv[2]; 00341 00342 ast_log(LOG_WARNING, "init say.c from %s to %s\n", old_mode, mode); 00343 00344 if (!strcmp(mode, old_mode)) { 00345 ast_log(LOG_WARNING, "say mode is %s already\n", mode); 00346 } else if (!strcmp(mode, say_new)) { 00347 if (say_cfg == NULL) 00348 say_cfg = ast_config_load("say.conf"); 00349 save_say_mode(say_new); 00350 ast_say_number_full = say_number_full; 00351 00352 ast_say_enumeration_full = say_enumeration_full; 00353 #if 0 00354 ast_say_digits_full = say_digits_full; 00355 ast_say_digit_str_full = say_digit_str_full; 00356 ast_say_character_str_full = say_character_str_full; 00357 ast_say_phonetic_str_full = say_phonetic_str_full; 00358 ast_say_datetime_from_now = say_datetime_from_now; 00359 #endif 00360 ast_say_datetime = say_datetime; 00361 ast_say_time = say_time; 00362 ast_say_date = say_date; 00363 ast_say_date_with_format = say_date_with_format; 00364 } else if (!strcmp(mode, say_old) && say_api_buf[0] == say_new) { 00365 restore_say_mode(NULL); 00366 } else { 00367 ast_log(LOG_WARNING, "unrecognized mode %s\n", mode); 00368 } 00369 return RESULT_SUCCESS; 00370 }
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_DEFAULT | , | |||
"Sound File Playback Application" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
static int do_say | ( | say_args_t * | a, | |
const char * | s, | |||
const char * | options, | |||
int | depth | |||
) | [static] |
Definition at line 147 of file app_playback.c.
References ast_extension_match(), ast_log(), ast_strdupa, ast_variable_browse(), say_args_t::language, LOG_WARNING, ast_variable::name, ast_variable::next, say_cfg, and ast_variable::value.
Referenced by say_date_generic(), say_enumeration_full(), say_full(), and say_number_full().
00148 { 00149 struct ast_variable *v; 00150 char *lang, *x, *rule = NULL; 00151 int ret = 0; 00152 struct varshead head = { .first = NULL, .last = NULL }; 00153 struct ast_var_t *n; 00154 00155 ast_log(LOG_WARNING, "string <%s> depth <%d>\n", s, depth); 00156 if (depth++ > 10) { 00157 ast_log(LOG_WARNING, "recursion too deep, exiting\n"); 00158 return -1; 00159 } else if (!say_cfg) { 00160 ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s); 00161 return -1; 00162 } 00163 00164 /* scan languages same as in file.c */ 00165 if (a->language == NULL) 00166 a->language = "en"; /* default */ 00167 ast_log(LOG_WARNING, "try <%s> in <%s>\n", s, a->language); 00168 lang = ast_strdupa(a->language); 00169 for (;;) { 00170 for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) { 00171 if (ast_extension_match(v->name, s)) { 00172 rule = ast_strdupa(v->value); 00173 break; 00174 } 00175 } 00176 if (rule) 00177 break; 00178 if ( (x = strchr(lang, '_')) ) 00179 *x = '\0'; /* try without suffix */ 00180 else if (strcmp(lang, "en")) 00181 lang = "en"; /* last resort, try 'en' if not done yet */ 00182 else 00183 break; 00184 } 00185 if (!rule) 00186 return 0; 00187 00188 /* skip up to two prefixes to get the value */ 00189 if ( (x = strchr(s, ':')) ) 00190 s = x + 1; 00191 if ( (x = strchr(s, ':')) ) 00192 s = x + 1; 00193 ast_log(LOG_WARNING, "value is <%s>\n", s); 00194 n = ast_var_assign("SAY", s); 00195 AST_LIST_INSERT_HEAD(&head, n, entries); 00196 00197 /* scan the body, one piece at a time */ 00198 while ( ret <= 0 && (x = strsep(&rule, ",")) ) { /* exit on key */ 00199 char fn[128]; 00200 const char *p, *fmt, *data; /* format and data pointers */ 00201 00202 /* prepare a decent file name */ 00203 x = ast_skip_blanks(x); 00204 ast_trim_blanks(x); 00205 00206 /* replace variables */ 00207 memset(fn, 0, sizeof(fn)); /* XXX why isn't done in pbx_substitute_variables_helper! */ 00208 pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn)); 00209 ast_log(LOG_WARNING, "doing [%s]\n", fn); 00210 00211 /* locate prefix and data, if any */ 00212 fmt = index(fn, ':'); 00213 if (!fmt || fmt == fn) { /* regular filename */ 00214 ret = s_streamwait3(a, fn); 00215 continue; 00216 } 00217 fmt++; 00218 data = index(fmt, ':'); /* colon before data */ 00219 if (!data || data == fmt) { /* simple prefix-fmt */ 00220 ret = do_say(a, fn, options, depth); 00221 continue; 00222 } 00223 /* prefix:fmt:data */ 00224 for (p = fmt; p < data && ret <= 0; p++) { 00225 char fn2[sizeof(fn)]; 00226 if (*p == ' ' || *p == '\t') /* skip blanks */ 00227 continue; 00228 if (*p == '\'') {/* file name - we trim them */ 00229 char *y; 00230 strcpy(fn2, ast_skip_blanks(p+1)); /* make a full copy */ 00231 y = index(fn2, '\''); 00232 if (!y) { 00233 p = data; /* invalid. prepare to end */ 00234 break; 00235 } 00236 *y = '\0'; 00237 ast_trim_blanks(fn2); 00238 p = index(p+1, '\''); 00239 ret = s_streamwait3(a, fn2); 00240 } else { 00241 int l = fmt-fn; 00242 strcpy(fn2, fn); /* copy everything */ 00243 /* after prefix, append the format */ 00244 fn2[l++] = *p; 00245 strcpy(fn2 + l, data); 00246 ret = do_say(a, fn2, options, depth); 00247 } 00248 } 00249 } 00250 ast_var_delete(n); 00251 return ret; 00252 }
static int load_module | ( | void | ) | [static] |
Definition at line 481 of file app_playback.c.
References ast_cli_register_multiple(), ast_config_load(), ast_register_application(), cli_playback, playback_exec(), and say_cfg.
00482 { 00483 say_cfg = ast_config_load("say.conf"); 00484 ast_cli_register_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry)); 00485 return ast_register_application(app, playback_exec, synopsis, descrip); 00486 }
static int playback_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 378 of file app_playback.c.
References ast_channel::_state, ast_answer(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_waitstream(), ast_module_user::chan, ast_channel::context, LOG_WARNING, pbx_builtin_setvar_helper(), say_full(), strcasestr(), and strsep().
Referenced by load_module().
00379 { 00380 int res = 0; 00381 int mres = 0; 00382 struct ast_module_user *u; 00383 char *tmp; 00384 int option_skip=0; 00385 int option_say=0; 00386 int option_noanswer = 0; 00387 int priority_jump = 0; 00388 00389 AST_DECLARE_APP_ARGS(args, 00390 AST_APP_ARG(filenames); 00391 AST_APP_ARG(options); 00392 ); 00393 00394 if (ast_strlen_zero(data)) { 00395 ast_log(LOG_WARNING, "Playback requires an argument (filename)\n"); 00396 return -1; 00397 } 00398 00399 tmp = ast_strdupa(data); 00400 00401 u = ast_module_user_add(chan); 00402 AST_STANDARD_APP_ARGS(args, tmp); 00403 00404 if (args.options) { 00405 if (strcasestr(args.options, "skip")) 00406 option_skip = 1; 00407 if (strcasestr(args.options, "say")) 00408 option_say = 1; 00409 if (strcasestr(args.options, "noanswer")) 00410 option_noanswer = 1; 00411 if (strchr(args.options, 'j')) 00412 priority_jump = 1; 00413 } 00414 00415 if (chan->_state != AST_STATE_UP) { 00416 if (option_skip) { 00417 /* At the user's option, skip if the line is not up */ 00418 goto done; 00419 } else if (!option_noanswer) 00420 /* Otherwise answer unless we're supposed to send this while on-hook */ 00421 res = ast_answer(chan); 00422 } 00423 if (!res) { 00424 char *back = args.filenames; 00425 char *front; 00426 00427 ast_stopstream(chan); 00428 while (!res && (front = strsep(&back, "&"))) { 00429 if (option_say) 00430 res = say_full(chan, front, "", chan->language, NULL, -1, -1); 00431 else 00432 res = ast_streamfile(chan, front, chan->language); 00433 if (!res) { 00434 res = ast_waitstream(chan, ""); 00435 ast_stopstream(chan); 00436 } else { 00437 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data); 00438 if (priority_jump || ast_opt_priority_jumping) 00439 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 00440 res = 0; 00441 mres = 1; 00442 } 00443 } 00444 } 00445 done: 00446 pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", mres ? "FAILED" : "SUCCESS"); 00447 ast_module_user_remove(u); 00448 return res; 00449 }
static int reload | ( | void | ) | [static] |
Definition at line 451 of file app_playback.c.
References ast_config_destroy(), ast_config_load(), ast_log(), LOG_NOTICE, and say_cfg.
00452 { 00453 if (say_cfg) { 00454 ast_config_destroy(say_cfg); 00455 ast_log(LOG_NOTICE, "Reloading say.conf\n"); 00456 } 00457 say_cfg = ast_config_load("say.conf"); 00458 /* 00459 * XXX here we should sort rules according to the same order 00460 * we have in pbx.c so we have the same matching behaviour. 00461 */ 00462 return 0; 00463 }
static void restore_say_mode | ( | void * | arg | ) | [static] |
Definition at line 98 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().
00099 { 00100 int i = 0; 00101 say_api_buf[i++] = arg; 00102 00103 ast_say_number_full = say_api_buf[i++]; 00104 ast_say_enumeration_full = say_api_buf[i++]; 00105 ast_say_digit_str_full = say_api_buf[i++]; 00106 ast_say_character_str_full = say_api_buf[i++]; 00107 ast_say_phonetic_str_full = say_api_buf[i++]; 00108 ast_say_datetime = say_api_buf[i++]; 00109 ast_say_time = say_api_buf[i++]; 00110 ast_say_date = say_api_buf[i++]; 00111 ast_say_datetime_from_now = say_api_buf[i++]; 00112 ast_say_date_with_format = say_api_buf[i++]; 00113 }
static int s_streamwait3 | ( | const say_args_t * | a, | |
const char * | fn | |||
) | [static] |
Definition at line 129 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.
00130 { 00131 int res = ast_streamfile(a->chan, fn, a->language); 00132 if (res) { 00133 ast_log(LOG_WARNING, "Unable to play message %s\n", fn); 00134 return res; 00135 } 00136 res = (a->audiofd > -1 && a->ctrlfd > -1) ? 00137 ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) : 00138 ast_waitstream(a->chan, a->ints); 00139 ast_stopstream(a->chan); 00140 return res; 00141 }
static void save_say_mode | ( | const void * | arg | ) | [static] |
Definition at line 81 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().
00082 { 00083 int i = 0; 00084 say_api_buf[i++] = arg; 00085 00086 say_api_buf[i++] = ast_say_number_full; 00087 say_api_buf[i++] = ast_say_enumeration_full; 00088 say_api_buf[i++] = ast_say_digit_str_full; 00089 say_api_buf[i++] = ast_say_character_str_full; 00090 say_api_buf[i++] = ast_say_phonetic_str_full; 00091 say_api_buf[i++] = ast_say_datetime; 00092 say_api_buf[i++] = ast_say_time; 00093 say_api_buf[i++] = ast_say_date; 00094 say_api_buf[i++] = ast_say_datetime_from_now; 00095 say_api_buf[i++] = ast_say_date_with_format; 00096 }
static int say_date | ( | struct ast_channel * | chan, | |
time_t | t, | |||
const char * | ints, | |||
const char * | lang | |||
) | [static] |
Definition at line 312 of file app_playback.c.
References say_date_generic().
00313 { 00314 return say_date_generic(chan, t, ints, lang, "", NULL, "date"); 00315 }
static int say_date_generic | ( | struct ast_channel * | chan, | |
time_t | t, | |||
const char * | ints, | |||
const char * | lang, | |||
const char * | format, | |||
const char * | timezone, | |||
const char * | prefix | |||
) | [static] |
Definition at line 282 of file app_playback.c.
References ast_localtime(), and do_say().
Referenced by say_date(), say_date_with_format(), say_datetime(), and say_time().
00284 { 00285 char buf[128]; 00286 struct tm tm; 00287 say_args_t a = { chan, ints, lang, -1, -1 }; 00288 if (format == NULL) 00289 format = ""; 00290 00291 ast_localtime(&t, &tm, NULL); 00292 snprintf(buf, sizeof(buf), "%s:%s:%04d%02d%02d%02d%02d.%02d-%d-%3d", 00293 prefix, 00294 format, 00295 tm.tm_year+1900, 00296 tm.tm_mon+1, 00297 tm.tm_mday, 00298 tm.tm_hour, 00299 tm.tm_min, 00300 tm.tm_sec, 00301 tm.tm_wday, 00302 tm.tm_yday); 00303 return do_say(&a, buf, NULL, 0); 00304 }
static int say_date_with_format | ( | struct ast_channel * | chan, | |
time_t | t, | |||
const char * | ints, | |||
const char * | lang, | |||
const char * | format, | |||
const char * | timezone | |||
) | [static] |
Definition at line 306 of file app_playback.c.
References say_date_generic().
00308 { 00309 return say_date_generic(chan, t, ints, lang, format, timezone, "datetime"); 00310 }
static int say_datetime | ( | struct ast_channel * | chan, | |
time_t | t, | |||
const char * | ints, | |||
const char * | lang | |||
) | [static] |
Definition at line 322 of file app_playback.c.
References say_date_generic().
00323 { 00324 return say_date_generic(chan, t, ints, lang, "", NULL, "datetime"); 00325 }
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 272 of file app_playback.c.
References do_say().
00275 { 00276 char buf[64]; 00277 say_args_t a = { chan, ints, lang, audiofd, ctrlfd }; 00278 snprintf(buf, sizeof(buf), "enum:%d", num); 00279 return do_say(&a, buf, options, 0); 00280 }
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 254 of file app_playback.c.
References do_say().
Referenced by playback_exec().
00257 { 00258 say_args_t a = { chan, ints, lang, audiofd, ctrlfd }; 00259 return do_say(&a, string, options, 0); 00260 }
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 262 of file app_playback.c.
References do_say().
00265 { 00266 char buf[64]; 00267 say_args_t a = { chan, ints, lang, audiofd, ctrlfd }; 00268 snprintf(buf, sizeof(buf), "num:%d", num); 00269 return do_say(&a, buf, options, 0); 00270 }
static int say_time | ( | struct ast_channel * | chan, | |
time_t | t, | |||
const char * | ints, | |||
const char * | lang | |||
) | [static] |
Definition at line 317 of file app_playback.c.
References say_date_generic().
00318 { 00319 return say_date_generic(chan, t, ints, lang, "", NULL, "time"); 00320 }
static int unload_module | ( | void | ) | [static] |
Definition at line 465 of file app_playback.c.
References ast_cli_unregister_multiple(), ast_config_destroy(), ast_module_user_hangup_all, ast_unregister_application(), cli_playback, and say_cfg.
00466 { 00467 int res; 00468 00469 res = ast_unregister_application(app); 00470 00471 ast_cli_unregister_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry)); 00472 00473 ast_module_user_hangup_all(); 00474 00475 if (say_cfg) 00476 ast_config_destroy(say_cfg); 00477 00478 return res; 00479 }
char* app = "Playback" [static] |
Definition at line 50 of file app_playback.c.
struct ast_cli_entry cli_playback[] [static] |
Initial value:
{ { { "say", "load", NULL }, __say_init, "set/show the say mode", "say load new|old" }, }
Definition at line 372 of file app_playback.c.
Referenced by load_module(), and unload_module().
char* descrip [static] |
Definition at line 54 of file app_playback.c.
const void* say_api_buf[40] [static] |
Definition at line 77 of file app_playback.c.
struct ast_config* say_cfg = NULL [static] |
Definition at line 71 of file app_playback.c.
Referenced by __say_init(), do_say(), load_module(), reload(), and unload_module().
const char* say_new = "new" [static] |
Definition at line 79 of file app_playback.c.
const char* say_old = "old" [static] |
Definition at line 78 of file app_playback.c.
Definition at line 52 of file app_playback.c.