issue #5752
[asterisk/asterisk.git] / apps / app_playback.c
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
19 /*! \file
20  *
21  * \brief Trivial application to playback a sound file
22  * 
23  * \ingroup applications
24  */
25  
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include "asterisk/lock.h"
35 #include "asterisk/file.h"
36 #include "asterisk/logger.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/module.h"
40 #include "asterisk/translate.h"
41 #include "asterisk/utils.h"
42 #include "asterisk/options.h"
43 #include "asterisk/app.h"
44
45 static char *tdesc = "Sound File Playback Application";
46
47 static char *app = "Playback";
48
49 static char *synopsis = "Play a file";
50
51 static char *descrip = 
52 "  Playback(filename[&filename2...][|option]):  Plays back given filenames (do not put\n"
53 "extension). Options may also be included following a pipe symbol. The 'skip'\n"
54 "option causes the playback of the message to be skipped if the channel\n"
55 "is not in the 'up' state (i.e. it hasn't been  answered  yet). If 'skip' is \n"
56 "specified, the application will return immediately should the channel not be\n"
57 "off hook.  Otherwise, unless 'noanswer' is specified, the channel will\n"
58 "be answered before the sound is played. Not all channels support playing\n"
59 "messages while still on hook. If 'j' is specified, the application\n"
60 "will jump to priority n+101 if present when a file specified to be played\n"
61 "does not exist.\n"
62 "This application sets the following channel variable upon completion:\n"
63 " PLAYBACKSTATUS    The status of the playback attempt as a text string, one of\n"
64 "               SUCCESS | FAILED\n"
65 ;
66
67 STANDARD_LOCAL_USER;
68
69 LOCAL_USER_DECL;
70
71 static int playback_exec(struct ast_channel *chan, void *data)
72 {
73         int res = 0, mres = 0;
74         struct localuser *u;
75         char *tmp = NULL;
76         int option_skip=0;
77         int option_noanswer = 0;
78         char *front = NULL, *back = NULL;
79         int priority_jump = 0;
80         AST_DECLARE_APP_ARGS(args,
81                 AST_APP_ARG(filenames);
82                 AST_APP_ARG(options);
83         );
84         
85         if (ast_strlen_zero(data)) {
86                 ast_log(LOG_WARNING, "Playback requires an argument (filename)\n");
87                 return -1;
88         }
89
90         LOCAL_USER_ADD(u);
91
92         tmp = ast_strdupa(data);
93         if (!tmp) {
94                 ast_log(LOG_ERROR, "Out of memory!\n");
95                 LOCAL_USER_REMOVE(u);
96                 return -1;      
97         }
98
99         AST_STANDARD_APP_ARGS(args, tmp);
100
101         if (args.options) {
102                 if (strcasestr(args.options, "skip"))
103                         option_skip = 1;
104                 if (strcasestr(args.options, "noanswer"))
105                         option_noanswer = 1;
106                 if (strchr(args.options, 'j'))
107                         priority_jump = 1;
108         }
109         
110         if (chan->_state != AST_STATE_UP) {
111                 if (option_skip) {
112                         /* At the user's option, skip if the line is not up */
113                         LOCAL_USER_REMOVE(u);
114                         return 0;
115                 } else if (!option_noanswer)
116                         /* Otherwise answer unless we're supposed to send this while on-hook */
117                         res = ast_answer(chan);
118         }
119         if (!res) {
120                 ast_stopstream(chan);
121                 front = tmp;
122                 while (!res && front) {
123                         if ((back = strchr(front, '&'))) {
124                                 *back = '\0';
125                                 back++;
126                         }
127                         res = ast_streamfile(chan, front, chan->language);
128                         if (!res) { 
129                                 res = ast_waitstream(chan, ""); 
130                                 ast_stopstream(chan);
131                         } else {
132                                 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
133                                 if (priority_jump || option_priority_jumping)
134                                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
135                                 res = 0;
136                                 mres = 1;
137                         }
138                         front = back;
139                 }
140                 if (mres)
141                         pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", "FAILED");
142                 else
143                         pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", "SUCCESS");
144         }
145         LOCAL_USER_REMOVE(u);
146         return res;
147 }
148
149 int unload_module(void)
150 {
151         int res;
152
153         res = ast_unregister_application(app);
154
155         STANDARD_HANGUP_LOCALUSERS;
156
157         return res;     
158 }
159
160 int load_module(void)
161 {
162         return ast_register_application(app, playback_exec, synopsis, descrip);
163 }
164
165 char *description(void)
166 {
167         return tdesc;
168 }
169
170 int usecount(void)
171 {
172         int res;
173         STANDARD_USECOUNT(res);
174         return res;
175 }
176
177 char *key()
178 {
179         return ASTERISK_GPL_KEY;
180 }