Thu Apr 28 2011 17:15:29

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 *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 struct ast_module_info
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Sound File Playback Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static char * app = "Playback"
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_cli_entry cli_playback []
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"

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 554 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 380 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(), say_old, and ast_cli_entry::usage.

{
   const char *old_mode = say_api_buf[0] ? say_new : say_old;
   char *mode;
   switch (cmd) {
   case CLI_INIT:
      e->command = "say load [new|old]";
      e->usage = 
         "Usage: say load [new|old]\n"
         "       say load\n"
         "           Report status of current say mode\n"
         "       say load new\n"
         "           Set say method, configured in say.conf\n"
         "       say load old\n"
         "           Set old say method, coded in asterisk core\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }
   if (a->argc == 2) {
      ast_cli(a->fd, "say mode is [%s]\n", old_mode);
      return CLI_SUCCESS;
   } else if (a->argc != e->args)
      return CLI_SHOWUSAGE;
   mode = a->argv[2];
   if (!strcmp(mode, old_mode))
      ast_cli(a->fd, "say mode is %s already\n", mode);
   else
      if (say_init_mode(mode) == 0)
         ast_cli(a->fd, "setting say mode from %s to %s\n", old_mode, mode);

   return CLI_SUCCESS;
}
static void __unreg_module ( void  ) [static]

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

{
   struct ast_variable *v;
   char *lang, *x, *rule = NULL;
   int ret = 0;   
   struct varshead head = { .first = NULL, .last = NULL };
   struct ast_var_t *n;

   ast_debug(2, "string <%s> depth <%d>\n", s, depth);
   if (depth++ > 10) {
      ast_log(LOG_WARNING, "recursion too deep, exiting\n");
      return -1;
   } else if (!say_cfg) {
      ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s);
      return -1;
   }

   /* scan languages same as in file.c */
   if (a->language == NULL)
      a->language = "en";     /* default */
   ast_debug(2, "try <%s> in <%s>\n", s, a->language);
   lang = ast_strdupa(a->language);
   for (;;) {
      for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) {
         if (ast_extension_match(v->name, s)) {
            rule = ast_strdupa(v->value);
            break;
         }
      }
      if (rule)
         break;
      if ( (x = strchr(lang, '_')) )
         *x = '\0';      /* try without suffix */
      else if (strcmp(lang, "en"))
         lang = "en";    /* last resort, try 'en' if not done yet */
      else
         break;
   }
   if (!rule)
      return 0;

   /* skip up to two prefixes to get the value */
   if ( (x = strchr(s, ':')) )
      s = x + 1;
   if ( (x = strchr(s, ':')) )
      s = x + 1;
   ast_debug(2, "value is <%s>\n", s);
   n = ast_var_assign("SAY", s);
   AST_LIST_INSERT_HEAD(&head, n, entries);

   /* scan the body, one piece at a time */
   while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */
      char fn[128];
      const char *p, *fmt, *data; /* format and data pointers */

      /* prepare a decent file name */
      x = ast_skip_blanks(x);
      ast_trim_blanks(x);

      /* replace variables */
      pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn));
      ast_debug(2, "doing [%s]\n", fn);

      /* locate prefix and data, if any */
      fmt = strchr(fn, ':');
      if (!fmt || fmt == fn)  {  /* regular filename */
         ret = s_streamwait3(a, fn);
         continue;
      }
      fmt++;
      data = strchr(fmt, ':');   /* colon before data */
      if (!data || data == fmt) {   /* simple prefix-fmt */
         ret = do_say(a, fn, options, depth);
         continue;
      }
      /* prefix:fmt:data */
      for (p = fmt; p < data && ret <= 0; p++) {
         char fn2[sizeof(fn)];
         if (*p == ' ' || *p == '\t')  /* skip blanks */
            continue;
         if (*p == '\'') {/* file name - we trim them */
            char *y;
            strcpy(fn2, ast_skip_blanks(p+1));  /* make a full copy */
            y = strchr(fn2, '\'');
            if (!y) {
               p = data;   /* invalid. prepare to end */
               break;
            }
            *y = '\0';
            ast_trim_blanks(fn2);
            p = strchr(p+1, '\'');
            ret = s_streamwait3(a, fn2);
         } else {
            int l = fmt-fn;
            strcpy(fn2, fn); /* copy everything */
            /* after prefix, append the format */
            fn2[l++] = *p;
            strcpy(fn2 + l, data);
            ret = do_say(a, fn2, options, depth);
         }
         
         if (ret) {
            break;
         }
      }
   }
   ast_var_delete(n);
   return ret;
}
static int playback_exec ( struct ast_channel chan,
void *  data 
) [static]

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

{
   int res = 0;
   int mres = 0;
   char *tmp;
   int option_skip=0;
   int option_say=0;
   int option_noanswer = 0;

   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(filenames);
      AST_APP_ARG(options);
   );
   
   if (ast_strlen_zero(data)) {
      ast_log(LOG_WARNING, "Playback requires an argument (filename)\n");
      return -1;
   }

   tmp = ast_strdupa(data);
   AST_STANDARD_APP_ARGS(args, tmp);

   if (args.options) {
      if (strcasestr(args.options, "skip"))
         option_skip = 1;
      if (strcasestr(args.options, "say"))
         option_say = 1;
      if (strcasestr(args.options, "noanswer"))
         option_noanswer = 1;
   } 
   if (chan->_state != AST_STATE_UP) {
      if (option_skip) {
         /* At the user's option, skip if the line is not up */
         goto done;
      } else if (!option_noanswer) {
         /* Otherwise answer unless we're supposed to send this while on-hook */
         res = ast_answer(chan);
      }
   }
   if (!res) {
      char *back = args.filenames;
      char *front;

      ast_stopstream(chan);
      while (!res && (front = strsep(&back, "&"))) {
         if (option_say)
            res = say_full(chan, front, "", chan->language, NULL, -1, -1);
         else
            res = ast_streamfile(chan, front, chan->language);
         if (!res) { 
            res = ast_waitstream(chan, "");  
            ast_stopstream(chan);
         } else {
            ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
            res = 0;
            mres = 1;
         }
      }
   }
done:
   pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", mres ? "FAILED" : "SUCCESS");
   return res;
}
static int reload ( void  ) [static]

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

{
   struct ast_variable *v;
   struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
   struct ast_config *newcfg;

   if ((newcfg = ast_config_load("say.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
      return 0;
   } else if (newcfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_ERROR, "Config file say.conf is in an invalid format.  Aborting.\n");
      return 0;
   }

   if (say_cfg) {
      ast_config_destroy(say_cfg);
      ast_log(LOG_NOTICE, "Reloading say.conf\n");
      say_cfg = newcfg;
   }

   if (say_cfg) {
      for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {
            if (ast_extension_match(v->name, "mode")) {
            say_init_mode(v->value);
            break;
         }
      }
   }
   
   /*
    * XXX here we should sort rules according to the same order
    * we have in pbx.c so we have the same matching behaviour.
    */
   return 0;
}
static int s_streamwait3 ( const say_args_t a,
const char *  fn 
) [static]

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

{
   int res = ast_streamfile(a->chan, fn, a->language);
   if (res) {
      ast_log(LOG_WARNING, "Unable to play message %s\n", fn);
      return res;
   }
   res = (a->audiofd  > -1 && a->ctrlfd > -1) ?
   ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) :
   ast_waitstream(a->chan, a->ints);
   ast_stopstream(a->chan);
   return res;  
}
static int say_date ( struct ast_channel chan,
time_t  t,
const char *  ints,
const char *  lang 
) [static]

Definition at line 331 of file app_playback.c.

References say_date_generic().

Referenced by say_init_mode().

{
   return say_date_generic(chan, t, ints, lang, "", NULL, "date");
}
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 300 of file app_playback.c.

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

{
   char buf[128];
   struct ast_tm tm;
   struct timeval when = { t, 0 };
   say_args_t a = { chan, ints, lang, -1, -1 };
   if (format == NULL)
      format = "";

   ast_localtime(&when, &tm, NULL);
   snprintf(buf, sizeof(buf), "%s:%s:%04d%02d%02d%02d%02d.%02d-%d-%3d",
      prefix,
      format,
      tm.tm_year+1900,
      tm.tm_mon+1,
      tm.tm_mday,
      tm.tm_hour,
      tm.tm_min,
      tm.tm_sec,
      tm.tm_wday,
      tm.tm_yday);
   return do_say(&a, buf, NULL, 0);
}
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 325 of file app_playback.c.

References say_date_generic().

Referenced by say_init_mode().

{
   return say_date_generic(chan, t, ints, lang, format, timezonename, "datetime");
}
static int say_datetime ( struct ast_channel chan,
time_t  t,
const char *  ints,
const char *  lang 
) [static]

Definition at line 341 of file app_playback.c.

References say_date_generic().

Referenced by say_init_mode().

{
   return say_date_generic(chan, t, ints, lang, "", NULL, "datetime");
}
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 290 of file app_playback.c.

References buf, chan, and do_say().

Referenced by say_init_mode().

{
   char buf[64];
   say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
   snprintf(buf, sizeof(buf), "enum:%d", num);
   return do_say(&a, buf, options, 0);
}
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 272 of file app_playback.c.

References chan, and do_say().

Referenced by playback_exec().

{
   say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
   return do_say(&a, string, options, 0);
}
static int say_init_mode ( const char *  mode) [static]
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 280 of file app_playback.c.

References buf, chan, and do_say().

Referenced by say_init_mode().

{
   char buf[64];
   say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
   snprintf(buf, sizeof(buf), "num:%d", num);
   return do_say(&a, buf, options, 0);
}
static int say_time ( struct ast_channel chan,
time_t  t,
const char *  ints,
const char *  lang 
) [static]

Definition at line 336 of file app_playback.c.

References say_date_generic().

Referenced by say_init_mode().

{
   return say_date_generic(chan, t, ints, lang, "", NULL, "time");
}
static int unload_module ( void  ) [static]

Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Sound File Playback Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 554 of file app_playback.c.

char* app = "Playback" [static]

Definition at line 84 of file app_playback.c.

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

const void* say_api_buf[40] [static]

Definition at line 92 of file app_playback.c.

struct ast_config* say_cfg = NULL [static]

Definition at line 86 of file app_playback.c.

const char* say_new = "new" [static]

Definition at line 94 of file app_playback.c.

const char* say_old = "old" [static]

Definition at line 93 of file app_playback.c.

Referenced by __say_cli_init().