app_playback.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2005, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief Trivial application to playback a sound file
  21. *
  22. * \author Mark Spencer <markster@digium.com>
  23. *
  24. * \ingroup applications
  25. */
  26. /*** MODULEINFO
  27. <support_level>core</support_level>
  28. ***/
  29. #include "asterisk.h"
  30. #include "asterisk/file.h"
  31. #include "asterisk/pbx.h"
  32. #include "asterisk/module.h"
  33. #include "asterisk/app.h"
  34. /* This file provides config-file based 'say' functions, and implements
  35. * some CLI commands.
  36. */
  37. #include "asterisk/say.h" /*!< provides config-file based 'say' functions */
  38. #include "asterisk/cli.h"
  39. /*** DOCUMENTATION
  40. <application name="Playback" language="en_US">
  41. <synopsis>
  42. Play a file.
  43. </synopsis>
  44. <syntax>
  45. <parameter name="filenames" required="true" argsep="&amp;">
  46. <para>Ampersand separated list of filenames. If the filename
  47. is a relative filename (it does not begin with a slash), it
  48. will be searched for in the Asterisk sounds directory. If the
  49. filename is able to be parsed as a URL, Asterisk will
  50. download the file and then begin playback on it. To include a
  51. literal <literal>&amp;</literal> in the URL you can enclose
  52. the URL in single quotes.</para>
  53. <argument name="filename" required="true" />
  54. <argument name="filename2" multiple="true" />
  55. </parameter>
  56. <parameter name="options">
  57. <para>Comma separated list of options</para>
  58. <optionlist>
  59. <option name="skip">
  60. <para>Do not play if not answered</para>
  61. </option>
  62. <option name="noanswer">
  63. <para>Playback without answering, otherwise the channel will
  64. be answered before the sound is played.</para>
  65. <note><para>Not all channel types support playing messages while still on hook.</para></note>
  66. </option>
  67. <option name="say">
  68. <para>Play using the say.conf file.</para>
  69. </option>
  70. <option name="mix">
  71. <para>Play using a mix of filename and the say.conf file.</para>
  72. </option>
  73. </optionlist>
  74. </parameter>
  75. </syntax>
  76. <description>
  77. <para>Plays back given filenames (do not put extension of wav/alaw etc).
  78. The Playback application answers the channel if no options are specified.
  79. If the file is non-existent it will fail.</para>
  80. <para>This application sets the following channel variable upon completion:</para>
  81. <variablelist>
  82. <variable name="PLAYBACKSTATUS">
  83. <para>The status of the playback attempt as a text string.</para>
  84. <value name="SUCCESS"/>
  85. <value name="FAILED"/>
  86. </variable>
  87. </variablelist>
  88. <para>See Also: Background (application) -- for playing sound files that are interruptible</para>
  89. <para>WaitExten (application) -- wait for digits from caller, optionally play music on hold</para>
  90. </description>
  91. <see-also>
  92. <ref type="application">BackGround</ref>
  93. <ref type="application">WaitExten</ref>
  94. <ref type="application">ControlPlayback</ref>
  95. <ref type="agi">stream file</ref>
  96. <ref type="agi">control stream file</ref>
  97. <ref type="manager">ControlPlayback</ref>
  98. </see-also>
  99. </application>
  100. ***/
  101. static char *app = "Playback";
  102. static struct ast_config *say_cfg = NULL;
  103. /*! \brief save the say' api calls.
  104. * The first entry is NULL if we have the standard source,
  105. * otherwise we are sourcing from here.
  106. * 'say load [new|old]' will enable the new or old method, or report status
  107. */
  108. static const void *say_api_buf[40];
  109. static const char * const say_old = "old";
  110. static const char * const say_new = "new";
  111. static void save_say_mode(const void *arg)
  112. {
  113. int i = 0;
  114. say_api_buf[i++] = arg;
  115. say_api_buf[i++] = ast_say_number_full;
  116. say_api_buf[i++] = ast_say_enumeration_full;
  117. say_api_buf[i++] = ast_say_digit_str_full;
  118. say_api_buf[i++] = ast_say_character_str_full;
  119. say_api_buf[i++] = ast_say_phonetic_str_full;
  120. say_api_buf[i++] = ast_say_datetime;
  121. say_api_buf[i++] = ast_say_time;
  122. say_api_buf[i++] = ast_say_date;
  123. say_api_buf[i++] = ast_say_datetime_from_now;
  124. say_api_buf[i++] = ast_say_date_with_format;
  125. }
  126. static void restore_say_mode(void *arg)
  127. {
  128. int i = 0;
  129. say_api_buf[i++] = arg;
  130. ast_say_number_full = say_api_buf[i++];
  131. ast_say_enumeration_full = say_api_buf[i++];
  132. ast_say_digit_str_full = say_api_buf[i++];
  133. ast_say_character_str_full = say_api_buf[i++];
  134. ast_say_phonetic_str_full = say_api_buf[i++];
  135. ast_say_datetime = say_api_buf[i++];
  136. ast_say_time = say_api_buf[i++];
  137. ast_say_date = say_api_buf[i++];
  138. ast_say_datetime_from_now = say_api_buf[i++];
  139. ast_say_date_with_format = say_api_buf[i++];
  140. }
  141. /*! \brief
  142. * Typical 'say' arguments in addition to the date or number or string
  143. * to say. We do not include 'options' because they may be different
  144. * in recursive calls, and so they are better left as an external
  145. * parameter.
  146. */
  147. typedef struct {
  148. struct ast_channel *chan;
  149. const char *ints;
  150. const char *language;
  151. int audiofd;
  152. int ctrlfd;
  153. } say_args_t;
  154. static int s_streamwait3(const say_args_t *a, const char *fn)
  155. {
  156. int res = ast_streamfile(a->chan, fn, a->language);
  157. if (res) {
  158. ast_log(LOG_WARNING, "Unable to play message %s\n", fn);
  159. return res;
  160. }
  161. res = (a->audiofd > -1 && a->ctrlfd > -1) ?
  162. ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) :
  163. ast_waitstream(a->chan, a->ints);
  164. ast_stopstream(a->chan);
  165. return res;
  166. }
  167. /*! \brief
  168. * the string is 'prefix:data' or prefix:fmt:data'
  169. * with ':' being invalid in strings.
  170. */
  171. static int do_say(say_args_t *a, const char *s, const char *options, int depth)
  172. {
  173. struct ast_variable *v;
  174. char *lang;
  175. char *x;
  176. char *rule = NULL;
  177. char *rule_head = NULL;
  178. int ret = 0;
  179. struct varshead head = { .first = NULL, .last = NULL };
  180. struct ast_var_t *n;
  181. ast_debug(2, "string <%s> depth <%d>\n", s, depth);
  182. if (depth++ > 10) {
  183. ast_log(LOG_WARNING, "recursion too deep, exiting\n");
  184. return -1;
  185. } else if (!say_cfg) {
  186. ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s);
  187. return -1;
  188. }
  189. /* scan languages same as in file.c */
  190. if (a->language == NULL)
  191. a->language = "en"; /* default */
  192. ast_debug(2, "try <%s> in <%s>\n", s, a->language);
  193. lang = ast_strdupa(a->language);
  194. for (;;) {
  195. for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) {
  196. if (ast_extension_match(v->name, s)) {
  197. rule_head = rule = ast_strdup(v->value);
  198. break;
  199. }
  200. }
  201. if (rule)
  202. break;
  203. if ( (x = strchr(lang, '_')) )
  204. *x = '\0'; /* try without suffix */
  205. else if (strcmp(lang, "en"))
  206. lang = "en"; /* last resort, try 'en' if not done yet */
  207. else
  208. break;
  209. }
  210. if (!rule)
  211. return 0;
  212. /* skip up to two prefixes to get the value */
  213. if ( (x = strchr(s, ':')) )
  214. s = x + 1;
  215. if ( (x = strchr(s, ':')) )
  216. s = x + 1;
  217. ast_debug(2, "value is <%s>\n", s);
  218. n = ast_var_assign("SAY", s);
  219. if (!n) {
  220. ast_log(LOG_ERROR, "Memory allocation error in do_say\n");
  221. ast_free(rule_head);
  222. return -1;
  223. }
  224. AST_LIST_INSERT_HEAD(&head, n, entries);
  225. /* scan the body, one piece at a time */
  226. while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */
  227. char fn[128];
  228. const char *p, *fmt, *data; /* format and data pointers */
  229. /* prepare a decent file name */
  230. x = ast_skip_blanks(x);
  231. ast_trim_blanks(x);
  232. /* replace variables */
  233. pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn));
  234. ast_debug(2, "doing [%s]\n", fn);
  235. /* locate prefix and data, if any */
  236. fmt = strchr(fn, ':');
  237. if (!fmt || fmt == fn) { /* regular filename */
  238. ret = s_streamwait3(a, fn);
  239. continue;
  240. }
  241. fmt++;
  242. data = strchr(fmt, ':'); /* colon before data */
  243. if (!data || data == fmt) { /* simple prefix-fmt */
  244. ret = do_say(a, fn, options, depth);
  245. continue;
  246. }
  247. /* prefix:fmt:data */
  248. for (p = fmt; p < data && ret <= 0; p++) {
  249. char fn2[sizeof(fn)];
  250. if (*p == ' ' || *p == '\t') /* skip blanks */
  251. continue;
  252. if (*p == '\'') {/* file name - we trim them */
  253. char *y;
  254. strcpy(fn2, ast_skip_blanks(p+1)); /* make a full copy */
  255. y = strchr(fn2, '\'');
  256. if (!y) {
  257. p = data; /* invalid. prepare to end */
  258. break;
  259. }
  260. *y = '\0';
  261. ast_trim_blanks(fn2);
  262. p = strchr(p+1, '\'');
  263. ret = s_streamwait3(a, fn2);
  264. } else {
  265. int l = fmt-fn;
  266. strcpy(fn2, fn); /* copy everything */
  267. /* after prefix, append the format */
  268. fn2[l++] = *p;
  269. strcpy(fn2 + l, data);
  270. ret = do_say(a, fn2, options, depth);
  271. }
  272. if (ret) {
  273. break;
  274. }
  275. }
  276. }
  277. ast_var_delete(n);
  278. ast_free(rule_head);
  279. return ret;
  280. }
  281. static int say_full(struct ast_channel *chan, const char *string,
  282. const char *ints, const char *lang, const char *options,
  283. int audiofd, int ctrlfd)
  284. {
  285. say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
  286. return do_say(&a, string, options, 0);
  287. }
  288. static int say_number_full(struct ast_channel *chan, int num,
  289. const char *ints, const char *lang, const char *options,
  290. int audiofd, int ctrlfd)
  291. {
  292. char buf[64];
  293. say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
  294. snprintf(buf, sizeof(buf), "num:%d", num);
  295. return do_say(&a, buf, options, 0);
  296. }
  297. static int say_enumeration_full(struct ast_channel *chan, int num,
  298. const char *ints, const char *lang, const char *options,
  299. int audiofd, int ctrlfd)
  300. {
  301. char buf[64];
  302. say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
  303. snprintf(buf, sizeof(buf), "enum:%d", num);
  304. return do_say(&a, buf, options, 0);
  305. }
  306. static int say_date_generic(struct ast_channel *chan, time_t t,
  307. const char *ints, const char *lang, const char *format, const char *timezonename, const char *prefix)
  308. {
  309. char buf[128];
  310. struct ast_tm tm;
  311. struct timeval when = { t, 0 };
  312. say_args_t a = { chan, ints, lang, -1, -1 };
  313. if (format == NULL)
  314. format = "";
  315. ast_localtime(&when, &tm, timezonename);
  316. snprintf(buf, sizeof(buf), "%s:%s:%04d%02d%02d%02d%02d.%02d-%d-%3d",
  317. prefix,
  318. format,
  319. tm.tm_year+1900,
  320. tm.tm_mon+1,
  321. tm.tm_mday,
  322. tm.tm_hour,
  323. tm.tm_min,
  324. tm.tm_sec,
  325. tm.tm_wday,
  326. tm.tm_yday);
  327. return do_say(&a, buf, NULL, 0);
  328. }
  329. static int say_date_with_format(struct ast_channel *chan, time_t t,
  330. const char *ints, const char *lang, const char *format, const char *timezonename)
  331. {
  332. return say_date_generic(chan, t, ints, lang, format, timezonename, "datetime");
  333. }
  334. static int say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
  335. {
  336. return say_date_generic(chan, t, ints, lang, "", NULL, "date");
  337. }
  338. static int say_time(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
  339. {
  340. return say_date_generic(chan, t, ints, lang, "", NULL, "time");
  341. }
  342. static int say_datetime(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
  343. {
  344. return say_date_generic(chan, t, ints, lang, "", NULL, "datetime");
  345. }
  346. /*! \brief
  347. * remap the 'say' functions to use those in this file
  348. */
  349. static int say_init_mode(const char *mode) {
  350. if (!strcmp(mode, say_new)) {
  351. if (say_cfg == NULL) {
  352. ast_log(LOG_ERROR, "There is no say.conf file to use new mode\n");
  353. return -1;
  354. }
  355. save_say_mode(say_new);
  356. ast_say_number_full = say_number_full;
  357. ast_say_enumeration_full = say_enumeration_full;
  358. #if 0
  359. /*! \todo XXX
  360. These functions doesn't exist.
  361. say.conf.sample indicates this is working...
  362. */
  363. ast_say_digits_full = say_digits_full;
  364. ast_say_digit_str_full = say_digit_str_full;
  365. ast_say_character_str_full = say_character_str_full;
  366. ast_say_phonetic_str_full = say_phonetic_str_full;
  367. ast_say_datetime_from_now = say_datetime_from_now;
  368. #endif
  369. ast_say_datetime = say_datetime;
  370. ast_say_time = say_time;
  371. ast_say_date = say_date;
  372. ast_say_date_with_format = say_date_with_format;
  373. } else if (!strcmp(mode, say_old) && say_api_buf[0] == say_new) {
  374. restore_say_mode(NULL);
  375. } else if (strcmp(mode, say_old)) {
  376. ast_log(LOG_WARNING, "unrecognized mode %s\n", mode);
  377. return -1;
  378. }
  379. return 0;
  380. }
  381. static char *__say_cli_init(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  382. {
  383. const char *old_mode = say_api_buf[0] ? say_new : say_old;
  384. const char *mode;
  385. switch (cmd) {
  386. case CLI_INIT:
  387. e->command = "say load [new|old]";
  388. e->usage =
  389. "Usage: say load [new|old]\n"
  390. " say load\n"
  391. " Report status of current say mode\n"
  392. " say load new\n"
  393. " Set say method, configured in say.conf\n"
  394. " say load old\n"
  395. " Set old say method, coded in asterisk core\n";
  396. return NULL;
  397. case CLI_GENERATE:
  398. return NULL;
  399. }
  400. if (a->argc == 2) {
  401. ast_cli(a->fd, "say mode is [%s]\n", old_mode);
  402. return CLI_SUCCESS;
  403. } else if (a->argc != e->args)
  404. return CLI_SHOWUSAGE;
  405. mode = a->argv[2];
  406. if (!strcmp(mode, old_mode))
  407. ast_cli(a->fd, "say mode is %s already\n", mode);
  408. else
  409. if (say_init_mode(mode) == 0)
  410. ast_cli(a->fd, "setting say mode from %s to %s\n", old_mode, mode);
  411. return CLI_SUCCESS;
  412. }
  413. static struct ast_cli_entry cli_playback[] = {
  414. AST_CLI_DEFINE(__say_cli_init, "Set or show the say mode"),
  415. };
  416. static int playback_exec(struct ast_channel *chan, const char *data)
  417. {
  418. int res = 0;
  419. int mres = 0;
  420. char *tmp;
  421. int option_skip=0;
  422. int option_say=0;
  423. int option_mix=0;
  424. int option_noanswer = 0;
  425. AST_DECLARE_APP_ARGS(args,
  426. AST_APP_ARG(filenames);
  427. AST_APP_ARG(options);
  428. );
  429. if (ast_strlen_zero(data)) {
  430. ast_log(LOG_WARNING, "Playback requires an argument (filename)\n");
  431. return -1;
  432. }
  433. tmp = ast_strdupa(data);
  434. AST_STANDARD_APP_ARGS(args, tmp);
  435. if (args.options) {
  436. if (strcasestr(args.options, "skip"))
  437. option_skip = 1;
  438. if (strcasestr(args.options, "say"))
  439. option_say = 1;
  440. if (strcasestr(args.options, "mix"))
  441. option_mix = 1;
  442. if (strcasestr(args.options, "noanswer"))
  443. option_noanswer = 1;
  444. }
  445. if (ast_channel_state(chan) != AST_STATE_UP) {
  446. if (option_skip) {
  447. /* At the user's option, skip if the line is not up */
  448. goto done;
  449. } else if (!option_noanswer) {
  450. /* Otherwise answer unless we're supposed to send this while on-hook */
  451. res = ast_answer(chan);
  452. }
  453. }
  454. if (!res) {
  455. char *back = args.filenames;
  456. char *front;
  457. ast_stopstream(chan);
  458. while (!res && (front = ast_strsep(&back, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
  459. if (option_say)
  460. res = say_full(chan, front, "", ast_channel_language(chan), NULL, -1, -1);
  461. else if (option_mix){
  462. /* Check if it is in say format but not remote audio file */
  463. if (strcasestr(front, ":") && !strcasestr(front, "://"))
  464. res = say_full(chan, front, "", ast_channel_language(chan), NULL, -1, -1);
  465. else
  466. res = ast_streamfile(chan, front, ast_channel_language(chan));
  467. }
  468. else
  469. res = ast_streamfile(chan, front, ast_channel_language(chan));
  470. if (!res) {
  471. res = ast_waitstream(chan, "");
  472. ast_stopstream(chan);
  473. } else {
  474. if (!ast_check_hangup(chan)) {
  475. ast_log(LOG_WARNING, "Playback failed on %s for %s\n", ast_channel_name(chan), (char *)data);
  476. }
  477. res = 0;
  478. mres = 1;
  479. }
  480. }
  481. }
  482. done:
  483. pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", mres ? "FAILED" : "SUCCESS");
  484. return res;
  485. }
  486. static int reload(void)
  487. {
  488. struct ast_variable *v;
  489. struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
  490. struct ast_config *newcfg;
  491. if ((newcfg = ast_config_load("say.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
  492. return 0;
  493. } else if (newcfg == CONFIG_STATUS_FILEINVALID) {
  494. ast_log(LOG_ERROR, "Config file say.conf is in an invalid format. Aborting.\n");
  495. return 0;
  496. }
  497. if (say_cfg) {
  498. ast_config_destroy(say_cfg);
  499. ast_log(LOG_NOTICE, "Reloading say.conf\n");
  500. }
  501. say_cfg = newcfg;
  502. if (say_cfg) {
  503. for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {
  504. if (ast_extension_match(v->name, "mode")) {
  505. say_init_mode(v->value);
  506. break;
  507. }
  508. }
  509. }
  510. /*! \todo
  511. * XXX here we should sort rules according to the same order
  512. * we have in pbx.c so we have the same matching behaviour.
  513. */
  514. return 0;
  515. }
  516. static int unload_module(void)
  517. {
  518. int res;
  519. res = ast_unregister_application(app);
  520. ast_cli_unregister_multiple(cli_playback, ARRAY_LEN(cli_playback));
  521. if (say_cfg)
  522. ast_config_destroy(say_cfg);
  523. return res;
  524. }
  525. static int load_module(void)
  526. {
  527. struct ast_variable *v;
  528. struct ast_flags config_flags = { 0 };
  529. say_cfg = ast_config_load("say.conf", config_flags);
  530. if (say_cfg && say_cfg != CONFIG_STATUS_FILEINVALID) {
  531. for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {
  532. if (ast_extension_match(v->name, "mode")) {
  533. say_init_mode(v->value);
  534. break;
  535. }
  536. }
  537. }
  538. ast_cli_register_multiple(cli_playback, ARRAY_LEN(cli_playback));
  539. return ast_register_application_xml(app, playback_exec);
  540. }
  541. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Sound File Playback Application",
  542. .support_level = AST_MODULE_SUPPORT_CORE,
  543. .load = load_module,
  544. .unload = unload_module,
  545. .reload = reload,
  546. );