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