107 static char *
app =
"Playback";
117 static const char *
const say_old =
"old";
118 static const char *
const say_new =
"new";
120 static void save_say_mode(
const void *arg)
137 static void restore_say_mode(
void *arg)
168 static int s_streamwait3(
const say_args_t *a,
const char *fn)
172 ast_log(LOG_WARNING,
"Unable to play message %s\n", fn);
175 res = (a->audiofd > -1 && a->ctrlfd > -1) ?
192 char *rule_head = NULL;
194 struct varshead head = { .first = NULL, .last = NULL };
197 ast_debug(2,
"string <%s> depth <%d>\n", s, depth);
199 ast_log(LOG_WARNING,
"recursion too deep, exiting\n");
201 }
else if (!say_cfg) {
202 ast_log(LOG_WARNING,
"no say.conf, cannot spell '%s'\n", s);
207 if (a->language == NULL)
209 ast_debug(2,
"try <%s> in <%s>\n", s, a->language);
212 for (v = ast_variable_browse(say_cfg, lang); v ; v = v->
next) {
220 if ( (x = strchr(lang,
'_')) )
222 else if (strcmp(lang,
"en"))
231 if ( (x = strchr(s,
':')) )
233 if ( (x = strchr(s,
':')) )
236 n = ast_var_assign(
"SAY", s);
238 ast_log(LOG_ERROR,
"Memory allocation error in do_say\n");
245 while ( !ret && (x = strsep(&rule,
",")) ) {
247 const char *p, *fmt, *data;
254 pbx_substitute_variables_varshead(&head, x, fn,
sizeof(fn));
258 fmt = strchr(fn,
':');
259 if (!fmt || fmt == fn) {
260 ret = s_streamwait3(a, fn);
264 data = strchr(fmt,
':');
265 if (!data || data == fmt) {
266 ret =
do_say(a, fn, options, depth);
270 for (p = fmt; p < data && ret <= 0; p++) {
271 char fn2[
sizeof(fn)];
272 if (*p ==
' ' || *p ==
'\t')
277 y = strchr(fn2,
'\'');
284 p = strchr(p+1,
'\'');
285 ret = s_streamwait3(a, fn2);
291 strcpy(fn2 + l, data);
292 ret =
do_say(a, fn2, options, depth);
305 static int say_full(
struct ast_channel *chan,
const char *
string,
306 const char *ints,
const char *lang,
const char *options,
307 int audiofd,
int ctrlfd)
309 say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
310 return do_say(&a,
string, options, 0);
314 const char *ints,
const char *lang,
const char *options,
315 int audiofd,
int ctrlfd)
318 say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
319 snprintf(buf,
sizeof(buf),
"num:%d", num);
320 return do_say(&a, buf, options, 0);
324 const char *ints,
const char *lang,
const char *options,
325 int audiofd,
int ctrlfd)
328 say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
329 snprintf(buf,
sizeof(buf),
"enum:%d", num);
330 return do_say(&a, buf, options, 0);
333 static int say_date_generic(
struct ast_channel *chan, time_t t,
334 const char *ints,
const char *lang,
const char *format,
const char *timezonename,
const char *prefix)
338 struct timeval when = { t, 0 };
344 snprintf(buf,
sizeof(buf),
"%s:%s:%04d%02d%02d%02d%02d.%02d-%d-%3d",
355 return do_say(&a, buf, NULL, 0);
358 static int say_date_with_format(
struct ast_channel *chan, time_t t,
359 const char *ints,
const char *lang,
const char *format,
const char *timezonename)
361 return say_date_generic(chan, t, ints, lang, format, timezonename,
"datetime");
364 static int say_date(
struct ast_channel *chan, time_t t,
const char *ints,
const char *lang)
366 return say_date_generic(chan, t, ints, lang,
"", NULL,
"date");
369 static int say_time(
struct ast_channel *chan, time_t t,
const char *ints,
const char *lang)
371 return say_date_generic(chan, t, ints, lang,
"", NULL,
"time");
374 static int say_datetime(
struct ast_channel *chan, time_t t,
const char *ints,
const char *lang)
376 return say_date_generic(chan, t, ints, lang,
"", NULL,
"datetime");
383 if (!strcmp(mode, say_new)) {
384 if (say_cfg == NULL) {
385 ast_log(LOG_ERROR,
"There is no say.conf file to use new mode\n");
388 save_say_mode(say_new);
399 ast_say_character_str_full = say_character_str_full;
400 ast_say_phonetic_str_full = say_phonetic_str_full;
401 ast_say_datetime_from_now = say_datetime_from_now;
403 ast_say_datetime = say_datetime;
404 ast_say_time = say_time;
405 ast_say_date = say_date;
406 ast_say_date_with_format = say_date_with_format;
407 }
else if (!strcmp(mode, say_old) &&
say_api_buf[0] == say_new) {
408 restore_say_mode(NULL);
409 }
else if (strcmp(mode, say_old)) {
410 ast_log(LOG_WARNING,
"unrecognized mode %s\n", mode);
419 const char *old_mode =
say_api_buf[0] ? say_new : say_old;
423 e->
command =
"say load [new|old]";
425 "Usage: say load [new|old]\n"
427 " Report status of current say mode\n"
429 " Set say method, configured in say.conf\n"
431 " Set old say method, coded in asterisk core\n";
437 ast_cli(a->fd,
"say mode is [%s]\n", old_mode);
439 }
else if (a->argc != e->
args)
440 return CLI_SHOWUSAGE;
442 if (!strcmp(mode, old_mode))
443 ast_cli(a->fd,
"say mode is %s already\n", mode);
446 ast_cli(a->fd,
"setting say mode from %s to %s\n", old_mode, mode);
452 AST_CLI_DEFINE(__say_cli_init,
"Set or show the say mode"),
455 static int playback_exec(
struct ast_channel *chan,
const char *data)
463 int option_noanswer = 0;
470 if (ast_strlen_zero(data)) {
471 ast_log(LOG_WARNING,
"Playback requires an argument (filename)\n");
479 if (strcasestr(
args.options,
"skip"))
481 if (strcasestr(
args.options,
"say"))
483 if (strcasestr(
args.options,
"mix"))
485 if (strcasestr(
args.options,
"noanswer"))
492 }
else if (!option_noanswer) {
498 char *back =
args.filenames;
504 res = say_full(chan, front,
"", ast_channel_language(chan), NULL, -1, -1);
505 else if (option_mix){
507 if (strcasestr(front,
":") && !strcasestr(front,
"://"))
508 res = say_full(chan, front,
"", ast_channel_language(chan), NULL, -1, -1);
519 ast_log(LOG_WARNING,
"Playback failed on %s for %s\n", ast_channel_name(chan), (
char *)data);
537 if ((newcfg =
ast_config_load(
"say.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
539 }
else if (newcfg == CONFIG_STATUS_FILEINVALID) {
540 ast_log(LOG_ERROR,
"Config file say.conf is in an invalid format. Aborting.\n");
546 ast_log(LOG_NOTICE,
"Reloading say.conf\n");
551 for (v = ast_variable_browse(say_cfg,
"general"); v ; v = v->
next) {
566 static int unload_module(
void)
580 static int load_module(
void)
586 if (say_cfg && say_cfg != CONFIG_STATUS_FILEINVALID) {
587 for (v = ast_variable_browse(say_cfg,
"general"); v ; v = v->
next) {
599 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,
"Sound File Playback Application",
600 .support_level = AST_MODULE_SUPPORT_CORE,
602 .unload = unload_module,
struct ast_variable * next
Main Channel structure associated with a channel.
SAY_EXTERN int(* ast_say_number_full)(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) SAY_INIT(ast_say_number_full)
Same as ast_say_number() with audiofd for received audio and returns 1 on ctrlfd being readable...
static int say_number_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
ast_say_number_full: call language-specific functions
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Asterisk main include file. File version handling, generic pbx functions.
SAY_EXTERN int(* ast_say_enumeration_full)(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) SAY_INIT(ast_say_enumeration_full)
Same as ast_say_enumeration() with audiofd for received audio and returns 1 on ctrlfd being readable...
static int do_say(say_args_t *a, const char *s, const char *options, int depth)
the string is 'prefix:data' or prefix:fmt:data' with ':' being invalid in strings.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
descriptor for a cli entry.
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
int ast_say_digits_full(struct ast_channel *chan, int num, const char *ints, const char *lang, int audiofd, int ctrlfd)
Same as ast_say_digits() with audiofd for received audio and returns 1 on ctrlfd being readable...
Structure for variables, used for configurations and for channel variables.
ast_channel_state
ast_channel states
#define ast_cli_register_multiple(e, len)
Register multiple commands.
#define ast_strdup(str)
A wrapper for strdup()
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
int ast_unregister_application(const char *app)
Unregister an application.
int args
This gets set in ast_cli_register()
#define ast_config_load(filename, flags)
Load a config file.
SAY_EXTERN int(* ast_say_digit_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, int audiofd, int ctrlfd) SAY_INIT(ast_say_digit_str_full)
Same as ast_say_digit_str() with audiofd for received audio and returns 1 on ctrlfd being readable...
#define ast_strdupa(s)
duplicate a string in memory from the stack
static int say_enumeration_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
ast_say_enumeration_full: call language-specific functions
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
#define ast_debug(level,...)
Log a DEBUG message.
Core PBX routines and definitions.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
char * ast_trim_blanks(char *str)
Trims trailing whitespace characters from a string.
Typical 'say' arguments in addition to the date or number or string to say. We do not include 'option...
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
static const void * say_api_buf[40]
save the say' api calls. The first entry is NULL if we have the standard source, otherwise we are sou...
int ast_extension_match(const char *pattern, const char *extension)
Determine if a given extension matches a given pattern (in NXX format)
Structure used to handle boolean flags.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int monfd)
Standard Command Line Interface.
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
int ast_answer(struct ast_channel *chan)
Answer a channel.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Say numbers and dates (maybe words one day too)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
static int say_init_mode(const char *mode)
remap the 'say' functions to use those in this file
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
const ast_string_field language
int ast_stopstream(struct ast_channel *c)
Stops a stream.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define AST_APP_ARG(name)
Define an application argument.