Thu Sep 7 01:03:08 2017

Asterisk developer's documentation


app_playback.c File Reference

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 char * __say_cli_init (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 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, const char *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 char * app = "Playback"
static struct ast_cli_entry cli_playback []
static const void * say_api_buf [40]
static struct ast_configsay_cfg = NULL
static const char *const say_new = "new"
static const char *const say_old = "old"

Detailed Description

Trivial application to playback a sound file.

Author:
Mark Spencer <markster@digium.com>

Definition in file app_playback.c.


Function Documentation

static char* __say_cli_init ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 388 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(), and ast_cli_entry::usage.

00389 {
00390    const char *old_mode = say_api_buf[0] ? say_new : say_old;
00391    const char *mode;
00392    switch (cmd) {
00393    case CLI_INIT:
00394       e->command = "say load [new|old]";
00395       e->usage = 
00396          "Usage: say load [new|old]\n"
00397          "       say load\n"
00398          "           Report status of current say mode\n"
00399          "       say load new\n"
00400          "           Set say method, configured in say.conf\n"
00401          "       say load old\n"
00402          "           Set old say method, coded in asterisk core\n";
00403       return NULL;
00404    case CLI_GENERATE:
00405       return NULL;
00406    }
00407    if (a->argc == 2) {
00408       ast_cli(a->fd, "say mode is [%s]\n", old_mode);
00409       return CLI_SUCCESS;
00410    } else if (a->argc != e->args)
00411       return CLI_SHOWUSAGE;
00412    mode = a->argv[2];
00413    if (!strcmp(mode, old_mode))
00414       ast_cli(a->fd, "say mode is %s already\n", mode);
00415    else
00416       if (say_init_mode(mode) == 0)
00417          ast_cli(a->fd, "setting say mode from %s to %s\n", old_mode, mode);
00418 
00419    return CLI_SUCCESS;
00420 }

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 166 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(), say_args_t::language, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, pbx_substitute_variables_varshead(), s_streamwait3(), and ast_variable::value.

Referenced by say_date_generic(), say_enumeration_full(), say_full(), and say_number_full().

00167 {
00168    struct ast_variable *v;
00169    char *lang, *x, *rule = NULL;
00170    int ret = 0;   
00171    struct varshead head = { .first = NULL, .last = NULL };
00172    struct ast_var_t *n;
00173 
00174    ast_debug(2, "string <%s> depth <%d>\n", s, depth);
00175    if (depth++ > 10) {
00176       ast_log(LOG_WARNING, "recursion too deep, exiting\n");
00177       return -1;
00178    } else if (!say_cfg) {
00179       ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s);
00180       return -1;
00181    }
00182 
00183    /* scan languages same as in file.c */
00184    if (a->language == NULL)
00185       a->language = "en";     /* default */
00186    ast_debug(2, "try <%s> in <%s>\n", s, a->language);
00187    lang = ast_strdupa(a->language);
00188    for (;;) {
00189       for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) {
00190          if (ast_extension_match(v->name, s)) {
00191             rule = ast_strdupa(v->value);
00192             break;
00193          }
00194       }
00195       if (rule)
00196          break;
00197       if ( (x = strchr(lang, '_')) )
00198          *x = '\0';      /* try without suffix */
00199       else if (strcmp(lang, "en"))
00200          lang = "en";    /* last resort, try 'en' if not done yet */
00201       else
00202          break;
00203    }
00204    if (!rule)
00205       return 0;
00206 
00207    /* skip up to two prefixes to get the value */
00208    if ( (x = strchr(s, ':')) )
00209       s = x + 1;
00210    if ( (x = strchr(s, ':')) )
00211       s = x + 1;
00212    ast_debug(2, "value is <%s>\n", s);
00213    n = ast_var_assign("SAY", s);
00214    if (!n) {
00215       ast_log(LOG_ERROR, "Memory allocation error in do_say\n");
00216       return -1;
00217    }
00218    AST_LIST_INSERT_HEAD(&head, n, entries);
00219 
00220    /* scan the body, one piece at a time */
00221    while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */
00222       char fn[128];
00223       const char *p, *fmt, *data; /* format and data pointers */
00224 
00225       /* prepare a decent file name */
00226       x = ast_skip_blanks(x);
00227       ast_trim_blanks(x);
00228 
00229       /* replace variables */
00230       pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn));
00231       ast_debug(2, "doing [%s]\n", fn);
00232 
00233       /* locate prefix and data, if any */
00234       fmt = strchr(fn, ':');
00235       if (!fmt || fmt == fn)  {  /* regular filename */
00236          ret = s_streamwait3(a, fn);
00237          continue;
00238       }
00239       fmt++;
00240       data = strchr(fmt, ':');   /* colon before data */
00241       if (!data || data == fmt) {   /* simple prefix-fmt */
00242          ret = do_say(a, fn, options, depth);
00243          continue;
00244       }
00245       /* prefix:fmt:data */
00246       for (p = fmt; p < data && ret <= 0; p++) {
00247          char fn2[sizeof(fn)];
00248          if (*p == ' ' || *p == '\t')  /* skip blanks */
00249             continue;
00250          if (*p == '\'') {/* file name - we trim them */
00251             char *y;
00252             strcpy(fn2, ast_skip_blanks(p+1));  /* make a full copy */
00253             y = strchr(fn2, '\'');
00254             if (!y) {
00255                p = data;   /* invalid. prepare to end */
00256                break;
00257             }
00258             *y = '\0';
00259             ast_trim_blanks(fn2);
00260             p = strchr(p+1, '\'');
00261             ret = s_streamwait3(a, fn2);
00262          } else {
00263             int l = fmt-fn;
00264             strcpy(fn2, fn); /* copy everything */
00265             /* after prefix, append the format */
00266             fn2[l++] = *p;
00267             strcpy(fn2 + l, data);
00268             ret = do_say(a, fn2, options, depth);
00269          }
00270          
00271          if (ret) {
00272             break;
00273          }
00274       }
00275    }
00276    ast_var_delete(n);
00277    return ret;
00278 }

static int load_module ( void   )  [static]

Definition at line 539 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.

00540 {
00541    struct ast_variable *v;
00542    struct ast_flags config_flags = { 0 };
00543 
00544    say_cfg = ast_config_load("say.conf", config_flags);
00545    if (say_cfg && say_cfg != CONFIG_STATUS_FILEINVALID) {
00546       for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {
00547             if (ast_extension_match(v->name, "mode")) {
00548             say_init_mode(v->value);
00549             break;
00550          }
00551       }
00552    }
00553 
00554    ast_cli_register_multiple(cli_playback, ARRAY_LEN(cli_playback));
00555    return ast_register_application_xml(app, playback_exec);
00556 }

static int playback_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 426 of file app_playback.c.

References ast_channel::_state, 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(), LOG_WARNING, pbx_builtin_setvar_helper(), and say_full().

Referenced by load_module().

00427 {
00428    int res = 0;
00429    int mres = 0;
00430    char *tmp;
00431    int option_skip=0;
00432    int option_say=0;
00433    int option_noanswer = 0;
00434 
00435    AST_DECLARE_APP_ARGS(args,
00436       AST_APP_ARG(filenames);
00437       AST_APP_ARG(options);
00438    );
00439    
00440    if (ast_strlen_zero(data)) {
00441       ast_log(LOG_WARNING, "Playback requires an argument (filename)\n");
00442       return -1;
00443    }
00444 
00445    tmp = ast_strdupa(data);
00446    AST_STANDARD_APP_ARGS(args, tmp);
00447 
00448    if (args.options) {
00449       if (strcasestr(args.options, "skip"))
00450          option_skip = 1;
00451       if (strcasestr(args.options, "say"))
00452          option_say = 1;
00453       if (strcasestr(args.options, "noanswer"))
00454          option_noanswer = 1;
00455    } 
00456    if (chan->_state != AST_STATE_UP) {
00457       if (option_skip) {
00458          /* At the user's option, skip if the line is not up */
00459          goto done;
00460       } else if (!option_noanswer) {
00461          /* Otherwise answer unless we're supposed to send this while on-hook */
00462          res = ast_answer(chan);
00463       }
00464    }
00465    if (!res) {
00466       char *back = args.filenames;
00467       char *front;
00468 
00469       ast_stopstream(chan);
00470       while (!res && (front = strsep(&back, "&"))) {
00471          if (option_say)
00472             res = say_full(chan, front, "", chan->language, NULL, -1, -1);
00473          else
00474             res = ast_streamfile(chan, front, chan->language);
00475          if (!res) { 
00476             res = ast_waitstream(chan, "");  
00477             ast_stopstream(chan);
00478          } else {
00479             ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
00480             res = 0;
00481             mres = 1;
00482          }
00483       }
00484    }
00485 done:
00486    pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", mres ? "FAILED" : "SUCCESS");
00487    return res;
00488 }

static int reload ( void   )  [static]

Definition at line 490 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.

00491 {
00492    struct ast_variable *v;
00493    struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
00494    struct ast_config *newcfg;
00495 
00496    if ((newcfg = ast_config_load("say.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
00497       return 0;
00498    } else if (newcfg == CONFIG_STATUS_FILEINVALID) {
00499       ast_log(LOG_ERROR, "Config file say.conf is in an invalid format.  Aborting.\n");
00500       return 0;
00501    }
00502 
00503    if (say_cfg) {
00504       ast_config_destroy(say_cfg);
00505       ast_log(LOG_NOTICE, "Reloading say.conf\n");
00506    }
00507    say_cfg = newcfg;
00508 
00509    if (say_cfg) {
00510       for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {
00511             if (ast_extension_match(v->name, "mode")) {
00512             say_init_mode(v->value);
00513             break;
00514          }
00515       }
00516    }
00517    
00518    /*
00519     * XXX here we should sort rules according to the same order
00520     * we have in pbx.c so we have the same matching behaviour.
00521     */
00522    return 0;
00523 }

static void restore_say_mode ( void *  arg  )  [static]
static int s_streamwait3 ( const say_args_t a,
const char *  fn 
) [static]

Definition at line 148 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().

00149 {
00150    int res = ast_streamfile(a->chan, fn, a->language);
00151    if (res) {
00152       ast_log(LOG_WARNING, "Unable to play message %s\n", fn);
00153       return res;
00154    }
00155    res = (a->audiofd  > -1 && a->ctrlfd > -1) ?
00156    ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) :
00157    ast_waitstream(a->chan, a->ints);
00158    ast_stopstream(a->chan);
00159    return res;  
00160 }

static void save_say_mode ( const void *  arg  )  [static]
static int say_date ( struct ast_channel chan,
time_t  t,
const char *  ints,
const char *  lang 
) [static]

Definition at line 339 of file app_playback.c.

References say_date_generic().

Referenced by say_init_mode().

00340 {
00341    return say_date_generic(chan, t, ints, lang, "", NULL, "date");
00342 }

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 308 of file app_playback.c.

References ast_localtime(), 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().

00310 {
00311    char buf[128];
00312    struct ast_tm tm;
00313    struct timeval when = { t, 0 };
00314    say_args_t a = { chan, ints, lang, -1, -1 };
00315    if (format == NULL)
00316       format = "";
00317 
00318    ast_localtime(&when, &tm, NULL);
00319    snprintf(buf, sizeof(buf), "%s:%s:%04d%02d%02d%02d%02d.%02d-%d-%3d",
00320       prefix,
00321       format,
00322       tm.tm_year+1900,
00323       tm.tm_mon+1,
00324       tm.tm_mday,
00325       tm.tm_hour,
00326       tm.tm_min,
00327       tm.tm_sec,
00328       tm.tm_wday,
00329       tm.tm_yday);
00330    return do_say(&a, buf, NULL, 0);
00331 }

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 333 of file app_playback.c.

References say_date_generic().

Referenced by say_init_mode().

00335 {
00336    return say_date_generic(chan, t, ints, lang, format, timezonename, "datetime");
00337 }

static int say_datetime ( struct ast_channel chan,
time_t  t,
const char *  ints,
const char *  lang 
) [static]

Definition at line 349 of file app_playback.c.

References say_date_generic().

Referenced by say_init_mode().

00350 {
00351    return say_date_generic(chan, t, ints, lang, "", NULL, "datetime");
00352 }

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 298 of file app_playback.c.

References do_say().

Referenced by say_init_mode().

00301 {
00302    char buf[64];
00303    say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
00304    snprintf(buf, sizeof(buf), "enum:%d", num);
00305    return do_say(&a, buf, options, 0);
00306 }

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 280 of file app_playback.c.

References do_say().

Referenced by playback_exec().

00283 {
00284    say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
00285    return do_say(&a, string, options, 0);
00286 }

static int say_init_mode ( const char *  mode  )  [static]

Definition at line 357 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().

00357                                            {
00358    if (!strcmp(mode, say_new)) {
00359       if (say_cfg == NULL) {
00360          ast_log(LOG_ERROR, "There is no say.conf file to use new mode\n");
00361          return -1;
00362       }
00363       save_say_mode(say_new);
00364       ast_say_number_full = say_number_full;
00365 
00366       ast_say_enumeration_full = say_enumeration_full;
00367 #if 0
00368       ast_say_digits_full = say_digits_full;
00369       ast_say_digit_str_full = say_digit_str_full;
00370       ast_say_character_str_full = say_character_str_full;
00371       ast_say_phonetic_str_full = say_phonetic_str_full;
00372       ast_say_datetime_from_now = say_datetime_from_now;
00373 #endif
00374       ast_say_datetime = say_datetime;
00375       ast_say_time = say_time;
00376       ast_say_date = say_date;
00377       ast_say_date_with_format = say_date_with_format;
00378    } else if (!strcmp(mode, say_old) && say_api_buf[0] == say_new) {
00379       restore_say_mode(NULL);
00380    } else if (strcmp(mode, say_old)) {
00381       ast_log(LOG_WARNING, "unrecognized mode %s\n", mode);
00382       return -1;
00383    }
00384    
00385    return 0;
00386 }

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 288 of file app_playback.c.

References do_say().

Referenced by say_init_mode().

00291 {
00292    char buf[64];
00293    say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
00294    snprintf(buf, sizeof(buf), "num:%d", num);
00295    return do_say(&a, buf, options, 0);
00296 }

static int say_time ( struct ast_channel chan,
time_t  t,
const char *  ints,
const char *  lang 
) [static]

Definition at line 344 of file app_playback.c.

References say_date_generic().

Referenced by say_init_mode().

00345 {
00346    return say_date_generic(chan, t, ints, lang, "", NULL, "time");
00347 }

static int unload_module ( void   )  [static]

Definition at line 525 of file app_playback.c.

References ARRAY_LEN, ast_cli_unregister_multiple(), ast_config_destroy(), and ast_unregister_application().

00526 {
00527    int res;
00528 
00529    res = ast_unregister_application(app);
00530 
00531    ast_cli_unregister_multiple(cli_playback, ARRAY_LEN(cli_playback));
00532 
00533    if (say_cfg)
00534       ast_config_destroy(say_cfg);
00535 
00536    return res; 
00537 }


Variable Documentation

char* app = "Playback" [static]

Definition at line 88 of file app_playback.c.

struct ast_cli_entry cli_playback[] [static]
Initial value:
 {
   AST_CLI_DEFINE(__say_cli_init, "Set or show the say mode"),
}

Definition at line 422 of file app_playback.c.

const void* say_api_buf[40] [static]

Definition at line 96 of file app_playback.c.

struct ast_config* say_cfg = NULL [static]

Definition at line 90 of file app_playback.c.

const char* const say_new = "new" [static]

Definition at line 98 of file app_playback.c.

const char* const say_old = "old" [static]

Definition at line 97 of file app_playback.c.


Generated on 7 Sep 2017 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1