Wed Oct 28 11:45:46 2009

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"

Include dependency graph for app_playback.c:

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 *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_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 __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Sound File Playback Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static char * app = "Playback"
static const struct
ast_module_info
ast_module_info = &__mod_info
static struct ast_cli_entry cli_playback []
static char * descrip
static const void * say_api_buf [40]
static struct ast_configsay_cfg = NULL
static const char * say_new = "new"
static const char * say_old = "old"
static char * synopsis = "Play a file"


Detailed Description

Trivial application to playback a sound file.

Author:
Mark Spencer <markster@digium.com>

Definition in file app_playback.c.


Function Documentation

static void __reg_module ( void   )  [static]

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

00358 {
00359    const char *old_mode = say_api_buf[0] ? say_new : say_old;
00360    char *mode;
00361    switch (cmd) {
00362    case CLI_INIT:
00363       e->command = "say load [new|old]";
00364       e->usage = 
00365          "Usage: say load [new|old]\n"
00366          "       say load\n"
00367          "           Report status of current say mode\n"
00368          "       say load new\n"
00369          "           Set say method, configured in say.conf\n"
00370          "       say load old\n"
00371          "           Set old say method, coded in asterisk core\n";
00372       return NULL;
00373    case CLI_GENERATE:
00374       return NULL;
00375    }
00376    if (a->argc == 2) {
00377       ast_cli(a->fd, "say mode is [%s]\n", old_mode);
00378       return CLI_SUCCESS;
00379    } else if (a->argc != e->args)
00380       return CLI_SHOWUSAGE;
00381    mode = a->argv[2];
00382    if (!strcmp(mode, old_mode))
00383       ast_cli(a->fd, "say mode is %s already\n", mode);
00384    else
00385       if (say_init_mode(mode) == 0)
00386          ast_cli(a->fd, "setting say mode from %s to %s\n", old_mode, mode);
00387 
00388    return CLI_SUCCESS;
00389 }

static void __unreg_module ( void   )  [static]

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

00140 {
00141    struct ast_variable *v;
00142    char *lang, *x, *rule = NULL;
00143    int ret = 0;   
00144    struct varshead head = { .first = NULL, .last = NULL };
00145    struct ast_var_t *n;
00146 
00147    ast_debug(2, "string <%s> depth <%d>\n", s, depth);
00148    if (depth++ > 10) {
00149       ast_log(LOG_WARNING, "recursion too deep, exiting\n");
00150       return -1;
00151    } else if (!say_cfg) {
00152       ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s);
00153       return -1;
00154    }
00155 
00156    /* scan languages same as in file.c */
00157    if (a->language == NULL)
00158       a->language = "en";     /* default */
00159    ast_debug(2, "try <%s> in <%s>\n", s, a->language);
00160    lang = ast_strdupa(a->language);
00161    for (;;) {
00162       for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) {
00163          if (ast_extension_match(v->name, s)) {
00164             rule = ast_strdupa(v->value);
00165             break;
00166          }
00167       }
00168       if (rule)
00169          break;
00170       if ( (x = strchr(lang, '_')) )
00171          *x = '\0';      /* try without suffix */
00172       else if (strcmp(lang, "en"))
00173          lang = "en";    /* last resort, try 'en' if not done yet */
00174       else
00175          break;
00176    }
00177    if (!rule)
00178       return 0;
00179 
00180    /* skip up to two prefixes to get the value */
00181    if ( (x = strchr(s, ':')) )
00182       s = x + 1;
00183    if ( (x = strchr(s, ':')) )
00184       s = x + 1;
00185    ast_debug(2, "value is <%s>\n", s);
00186    n = ast_var_assign("SAY", s);
00187    AST_LIST_INSERT_HEAD(&head, n, entries);
00188 
00189    /* scan the body, one piece at a time */
00190    while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */
00191       char fn[128];
00192       const char *p, *fmt, *data; /* format and data pointers */
00193 
00194       /* prepare a decent file name */
00195       x = ast_skip_blanks(x);
00196       ast_trim_blanks(x);
00197 
00198       /* replace variables */
00199       pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn));
00200       ast_debug(2, "doing [%s]\n", fn);
00201 
00202       /* locate prefix and data, if any */
00203       fmt = strchr(fn, ':');
00204       if (!fmt || fmt == fn)  {  /* regular filename */
00205          ret = s_streamwait3(a, fn);
00206          continue;
00207       }
00208       fmt++;
00209       data = strchr(fmt, ':');   /* colon before data */
00210       if (!data || data == fmt) {   /* simple prefix-fmt */
00211          ret = do_say(a, fn, options, depth);
00212          continue;
00213       }
00214       /* prefix:fmt:data */
00215       for (p = fmt; p < data && ret <= 0; p++) {
00216          char fn2[sizeof(fn)];
00217          if (*p == ' ' || *p == '\t')  /* skip blanks */
00218             continue;
00219          if (*p == '\'') {/* file name - we trim them */
00220             char *y;
00221             strcpy(fn2, ast_skip_blanks(p+1));  /* make a full copy */
00222             y = strchr(fn2, '\'');
00223             if (!y) {
00224                p = data;   /* invalid. prepare to end */
00225                break;
00226             }
00227             *y = '\0';
00228             ast_trim_blanks(fn2);
00229             p = strchr(p+1, '\'');
00230             ret = s_streamwait3(a, fn2);
00231          } else {
00232             int l = fmt-fn;
00233             strcpy(fn2, fn); /* copy everything */
00234             /* after prefix, append the format */
00235             fn2[l++] = *p;
00236             strcpy(fn2 + l, data);
00237             ret = do_say(a, fn2, options, depth);
00238          }
00239          
00240          if (ret) {
00241             break;
00242          }
00243       }
00244    }
00245    ast_var_delete(n);
00246    return ret;
00247 }

static int load_module ( void   )  [static]

Definition at line 504 of file app_playback.c.

References ast_cli_register_multiple(), ast_config_load, ast_extension_match(), ast_register_application, ast_variable_browse(), ast_variable::name, ast_variable::next, playback_exec(), say_init_mode(), and ast_variable::value.

00505 {
00506    struct ast_variable *v;
00507    struct ast_flags config_flags = { 0 };
00508 
00509    say_cfg = ast_config_load("say.conf", config_flags);
00510    if (say_cfg) {
00511       for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {
00512             if (ast_extension_match(v->name, "mode")) {
00513             say_init_mode(v->value);
00514             break;
00515          }
00516       }
00517    }
00518 
00519         ast_cli_register_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry));
00520    return ast_register_application(app, playback_exec, synopsis, descrip);
00521 }

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

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

00396 {
00397    int res = 0;
00398    int mres = 0;
00399    char *tmp;
00400    int option_skip=0;
00401    int option_say=0;
00402    int option_noanswer = 0;
00403 
00404    AST_DECLARE_APP_ARGS(args,
00405       AST_APP_ARG(filenames);
00406       AST_APP_ARG(options);
00407    );
00408    
00409    if (ast_strlen_zero(data)) {
00410       ast_log(LOG_WARNING, "Playback requires an argument (filename)\n");
00411       return -1;
00412    }
00413 
00414    tmp = ast_strdupa(data);
00415    AST_STANDARD_APP_ARGS(args, tmp);
00416 
00417    if (args.options) {
00418       if (strcasestr(args.options, "skip"))
00419          option_skip = 1;
00420       if (strcasestr(args.options, "say"))
00421          option_say = 1;
00422       if (strcasestr(args.options, "noanswer"))
00423          option_noanswer = 1;
00424    } 
00425    if (chan->_state != AST_STATE_UP) {
00426       if (option_skip) {
00427          /* At the user's option, skip if the line is not up */
00428          goto done;
00429       } else if (!option_noanswer) {
00430          /* Otherwise answer unless we're supposed to send this while on-hook */
00431          res = ast_answer(chan);
00432       }
00433    }
00434    if (!res) {
00435       char *back = args.filenames;
00436       char *front;
00437 
00438       ast_stopstream(chan);
00439       while (!res && (front = strsep(&back, "&"))) {
00440          if (option_say)
00441             res = say_full(chan, front, "", chan->language, NULL, -1, -1);
00442          else
00443             res = ast_streamfile(chan, front, chan->language);
00444          if (!res) { 
00445             res = ast_waitstream(chan, "");  
00446             ast_stopstream(chan);
00447          } else {
00448             ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
00449             res = 0;
00450             mres = 1;
00451          }
00452       }
00453    }
00454 done:
00455    pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", mres ? "FAILED" : "SUCCESS");
00456    return res;
00457 }

static int reload ( void   )  [static]

Definition at line 459 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_FILEUNCHANGED, LOG_NOTICE, ast_variable::name, ast_variable::next, say_init_mode(), and ast_variable::value.

00460 {
00461    struct ast_variable *v;
00462    struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
00463    struct ast_config *newcfg;
00464 
00465    if ((newcfg = ast_config_load("say.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
00466       return 0;
00467 
00468    if (say_cfg) {
00469       ast_config_destroy(say_cfg);
00470       ast_log(LOG_NOTICE, "Reloading say.conf\n");
00471       say_cfg = newcfg;
00472    }
00473 
00474    if (say_cfg) {
00475       for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {
00476             if (ast_extension_match(v->name, "mode")) {
00477             say_init_mode(v->value);
00478             break;
00479          }
00480       }
00481    }
00482    
00483    /*
00484     * XXX here we should sort rules according to the same order
00485     * we have in pbx.c so we have the same matching behaviour.
00486     */
00487    return 0;
00488 }

static void restore_say_mode ( void *  arg  )  [static]

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

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

00122 {
00123         int res = ast_streamfile(a->chan, fn, a->language);
00124         if (res) {
00125                 ast_log(LOG_WARNING, "Unable to play message %s\n", fn);
00126                 return res;
00127         }
00128         res = (a->audiofd  > -1 && a->ctrlfd > -1) ?
00129                 ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) :
00130                 ast_waitstream(a->chan, a->ints);
00131         ast_stopstream(a->chan);
00132         return res;  
00133 }

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

References say_date_generic().

00309 {
00310    return say_date_generic(chan, t, ints, lang, "", NULL, "date");
00311 }

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

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

00279 {
00280    char buf[128];
00281    struct ast_tm tm;
00282    struct timeval tv = { t, 0 };
00283         say_args_t a = { chan, ints, lang, -1, -1 };
00284    if (format == NULL)
00285       format = "";
00286 
00287    ast_localtime(&tv, &tm, NULL);
00288    snprintf(buf, sizeof(buf), "%s:%s:%04d%02d%02d%02d%02d.%02d-%d-%3d",
00289       prefix,
00290       format,
00291       tm.tm_year+1900,
00292       tm.tm_mon+1,
00293       tm.tm_mday,
00294       tm.tm_hour,
00295       tm.tm_min,
00296       tm.tm_sec,
00297       tm.tm_wday,
00298       tm.tm_yday);
00299         return do_say(&a, buf, NULL, 0);
00300 }

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

References say_date_generic().

00304 {
00305    return say_date_generic(chan, t, ints, lang, format, timezone, "datetime");
00306 }

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

Definition at line 318 of file app_playback.c.

References say_date_generic().

00319 {
00320    return say_date_generic(chan, t, ints, lang, "", NULL, "datetime");
00321 }

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

References buf, and do_say().

00270 {
00271    char buf[64];
00272         say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
00273    snprintf(buf, sizeof(buf), "enum:%d", num);
00274         return do_say(&a, buf, options, 0);
00275 }

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

References do_say().

Referenced by playback_exec().

00252 {
00253         say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
00254         return do_say(&a, string, options, 0);
00255 }

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

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

00326                                            {
00327    if (!strcmp(mode, say_new)) {
00328       if (say_cfg == NULL) {
00329          ast_log(LOG_ERROR, "There is no say.conf file to use new mode\n");
00330          return -1;
00331       }
00332       save_say_mode(say_new);
00333       ast_say_number_full = say_number_full;
00334 
00335       ast_say_enumeration_full = say_enumeration_full;
00336 #if 0
00337       ast_say_digits_full = say_digits_full;
00338       ast_say_digit_str_full = say_digit_str_full;
00339       ast_say_character_str_full = say_character_str_full;
00340       ast_say_phonetic_str_full = say_phonetic_str_full;
00341       ast_say_datetime_from_now = say_datetime_from_now;
00342 #endif
00343       ast_say_datetime = say_datetime;
00344       ast_say_time = say_time;
00345       ast_say_date = say_date;
00346       ast_say_date_with_format = say_date_with_format;
00347    } else if (!strcmp(mode, say_old) && say_api_buf[0] == say_new) {
00348       restore_say_mode(NULL);
00349    } else if (strcmp(mode, say_old)) {
00350       ast_log(LOG_WARNING, "unrecognized mode %s\n", mode);
00351       return -1;
00352    }
00353    
00354    return 0;
00355 }

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

References buf, and do_say().

00260 {
00261    char buf[64];
00262         say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
00263    snprintf(buf, sizeof(buf), "num:%d", num);
00264         return do_say(&a, buf, options, 0);
00265 }

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

Definition at line 313 of file app_playback.c.

References say_date_generic().

00314 {
00315    return say_date_generic(chan, t, ints, lang, "", NULL, "time");
00316 }

static int unload_module ( void   )  [static]

Definition at line 490 of file app_playback.c.

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

00491 {
00492    int res;
00493 
00494    res = ast_unregister_application(app);
00495 
00496    ast_cli_unregister_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry));
00497 
00498    if (say_cfg)
00499       ast_config_destroy(say_cfg);
00500 
00501    return res; 
00502 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Sound File Playback Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 527 of file app_playback.c.

char* app = "Playback" [static]

Definition at line 42 of file app_playback.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 527 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 391 of file app_playback.c.

char* descrip [static]

Definition at line 46 of file app_playback.c.

const void* say_api_buf[40] [static]

Definition at line 69 of file app_playback.c.

struct ast_config* say_cfg = NULL [static]

Definition at line 63 of file app_playback.c.

const char* say_new = "new" [static]

Definition at line 71 of file app_playback.c.

const char* say_old = "old" [static]

Definition at line 70 of file app_playback.c.

char* synopsis = "Play a file" [static]

Definition at line 44 of file app_playback.c.


Generated on Wed Oct 28 11:45:46 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6