Thu Oct 8 21:57:32 2009

Asterisk developer's documentation


app_playback.c File Reference

Trivial application to playback a sound file. More...

#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_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 int __say_init ( int  fd,
int  argc,
char *  argv[] 
) [static]

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

00333 {
00334    const char *old_mode = say_api_buf[0] ? say_new : say_old;
00335    char *mode;
00336 
00337    if (argc == 2) {
00338       ast_cli(fd, "say mode is [%s]\n", old_mode);
00339       return RESULT_SUCCESS;
00340         } else if (argc != 3)
00341                 return RESULT_SHOWUSAGE;
00342         mode = argv[2];
00343 
00344    ast_log(LOG_WARNING, "init say.c from %s to %s\n", old_mode, mode);
00345 
00346    if (!strcmp(mode, old_mode)) {
00347       ast_log(LOG_WARNING, "say mode is %s already\n", mode);
00348    } else if (!strcmp(mode, say_new)) {
00349       if (say_cfg == NULL)
00350          say_cfg = ast_config_load("say.conf");
00351       save_say_mode(say_new);
00352       ast_say_number_full = say_number_full;
00353 
00354       ast_say_enumeration_full = say_enumeration_full;
00355 #if 0
00356       ast_say_digits_full = say_digits_full;
00357       ast_say_digit_str_full = say_digit_str_full;
00358       ast_say_character_str_full = say_character_str_full;
00359       ast_say_phonetic_str_full = say_phonetic_str_full;
00360       ast_say_datetime_from_now = say_datetime_from_now;
00361 #endif
00362       ast_say_datetime = say_datetime;
00363       ast_say_time = say_time;
00364       ast_say_date = say_date;
00365       ast_say_date_with_format = say_date_with_format;
00366    } else if (!strcmp(mode, say_old) && say_api_buf[0] == say_new) {
00367       restore_say_mode(NULL);
00368    } else {
00369       ast_log(LOG_WARNING, "unrecognized mode %s\n", mode);
00370    }
00371    return RESULT_SUCCESS;
00372 }

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

References ast_extension_match(), AST_LIST_INSERT_HEAD, ast_log(), ast_strdupa, ast_var_assign(), ast_var_delete(), ast_variable_browse(), fmt, 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().

00150 {
00151    struct ast_variable *v;
00152    char *lang, *x, *rule = NULL;
00153    int ret = 0;   
00154    struct varshead head = { .first = NULL, .last = NULL };
00155    struct ast_var_t *n;
00156 
00157    if (depth++ > 10) {
00158       ast_log(LOG_WARNING, "recursion too deep, exiting\n");
00159       return -1;
00160    } else if (!say_cfg) {
00161       ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s);
00162       return -1;
00163    }
00164 
00165    /* scan languages same as in file.c */
00166    if (a->language == NULL)
00167       a->language = "en";     /* default */
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    n = ast_var_assign("SAY", s);
00194    AST_LIST_INSERT_HEAD(&head, n, entries);
00195 
00196    /* scan the body, one piece at a time */
00197    while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */
00198       char fn[128];
00199       const char *p, *fmt, *data; /* format and data pointers */
00200 
00201       /* prepare a decent file name */
00202       x = ast_skip_blanks(x);
00203       ast_trim_blanks(x);
00204 
00205       /* replace variables */
00206       memset(fn, 0, sizeof(fn)); /* XXX why isn't done in pbx_substitute_variables_helper! */
00207       pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn));
00208 
00209       /* locate prefix and data, if any */
00210       fmt = index(fn, ':');
00211       if (!fmt || fmt == fn)  {  /* regular filename */
00212          ret = s_streamwait3(a, fn);
00213          continue;
00214       }
00215       fmt++;
00216       data = index(fmt, ':'); /* colon before data */
00217       if (!data || data == fmt) {   /* simple prefix-fmt */
00218          ret = do_say(a, fn, options, depth);
00219          continue;
00220       }
00221       /* prefix:fmt:data */
00222       for (p = fmt; p < data && ret <= 0; p++) {
00223          char fn2[sizeof(fn)];
00224          if (*p == ' ' || *p == '\t')  /* skip blanks */
00225             continue;
00226          if (*p == '\'') {/* file name - we trim them */
00227             char *y;
00228             strcpy(fn2, ast_skip_blanks(p+1));  /* make a full copy */
00229             y = index(fn2, '\'');
00230             if (!y) {
00231                p = data;   /* invalid. prepare to end */
00232                break;
00233             }
00234             *y = '\0';
00235             ast_trim_blanks(fn2);
00236             p = index(p+1, '\'');
00237             ret = s_streamwait3(a, fn2);
00238          } else {
00239             int l = fmt-fn;
00240             strcpy(fn2, fn); /* copy everything */
00241             /* after prefix, append the format */
00242             fn2[l++] = *p;
00243             strcpy(fn2 + l, data);
00244             ret = do_say(a, fn2, options, depth);
00245          }
00246          
00247          if (ret) {
00248             break;
00249          }
00250       }
00251    }
00252    ast_var_delete(n);
00253    return ret;
00254 }

static int load_module ( void   )  [static]

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

Definition at line 380 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_channel::context, ast_channel::exten, LOG_WARNING, pbx_builtin_setvar_helper(), ast_channel::priority, say_full(), strcasestr(), and strsep().

Referenced by load_module().

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

static int reload ( void   )  [static]

Definition at line 453 of file app_playback.c.

References ast_config_destroy(), ast_config_load(), ast_log(), and LOG_NOTICE.

00454 {
00455    if (say_cfg) {
00456       ast_config_destroy(say_cfg);
00457       ast_log(LOG_NOTICE, "Reloading say.conf\n");
00458    }
00459    say_cfg = ast_config_load("say.conf");
00460    /*
00461     * XXX here we should sort rules according to the same order
00462     * we have in pbx.c so we have the same matching behaviour.
00463     */
00464    return 0;
00465 }

static void restore_say_mode ( void *  arg  )  [static]

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

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

00132 {
00133         int res = ast_streamfile(a->chan, fn, a->language);
00134         if (res) {
00135                 ast_log(LOG_WARNING, "Unable to play message %s\n", fn);
00136                 return res;
00137         }
00138         res = (a->audiofd  > -1 && a->ctrlfd > -1) ?
00139                 ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) :
00140                 ast_waitstream(a->chan, a->ints);
00141         ast_stopstream(a->chan);
00142         return res;  
00143 }

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

References say_date_generic().

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

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

References ast_localtime(), and do_say().

Referenced by say_date(), say_date_with_format(), say_datetime(), and say_time().

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

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

References say_date_generic().

00310 {
00311    return say_date_generic(chan, t, ints, lang, format, timezone, "datetime");
00312 }

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

Definition at line 324 of file app_playback.c.

References say_date_generic().

00325 {
00326    return say_date_generic(chan, t, ints, lang, "", NULL, "datetime");
00327 }

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

References do_say().

00277 {
00278    char buf[64];
00279         say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
00280    snprintf(buf, sizeof(buf), "enum:%d", num);
00281         return do_say(&a, buf, options, 0);
00282 }

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

References do_say().

Referenced by playback_exec().

00259 {
00260         say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
00261         return do_say(&a, string, options, 0);
00262 }

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

References do_say().

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

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

Definition at line 319 of file app_playback.c.

References say_date_generic().

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

static int unload_module ( void   )  [static]

Definition at line 467 of file app_playback.c.

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

00468 {
00469    int res;
00470 
00471    res = ast_unregister_application(app);
00472 
00473    ast_cli_unregister_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry));
00474 
00475    ast_module_user_hangup_all();
00476 
00477    if (say_cfg)
00478       ast_config_destroy(say_cfg);
00479 
00480    return res; 
00481 }


Variable Documentation

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",
   "Usage: say load [new|old]\n    Set/show the say mode\n" },
}

Definition at line 374 of file app_playback.c.

char* descrip [static]

Definition at line 54 of file app_playback.c.

const void* say_api_buf[40] [static]

Definition at line 79 of file app_playback.c.

struct ast_config* say_cfg = NULL [static]

Definition at line 73 of file app_playback.c.

const char* say_new = "new" [static]

Definition at line 81 of file app_playback.c.

const char* say_old = "old" [static]

Definition at line 80 of file app_playback.c.

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

Definition at line 52 of file app_playback.c.


Generated on Thu Oct 8 21:57:32 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.8