remove lots of useless checks of the result of ast_strdupa
[asterisk/asterisk.git] / apps / app_talkdetect.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 Playback a file with audio detect
22  *
23  * \author Mark Spencer <markster@digium.com>
24  * 
25  * \ingroup applications
26  */
27  
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.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/dsp.h"
45
46 static char *tdesc = "Playback with Talk Detection";
47
48 static char *app = "BackgroundDetect";
49
50 static char *synopsis = "Background a file with talk detect";
51
52 static char *descrip = 
53 "  BackgroundDetect(filename[|sil[|min|[max]]]):  Plays  back  a  given\n"
54 "filename, waiting for interruption from a given digit (the digit must\n"
55 "start the beginning of a valid extension, or it will be ignored).\n"
56 "During the playback of the file, audio is monitored in the receive\n"
57 "direction, and if a period of non-silence which is greater than 'min' ms\n"
58 "yet less than 'max' ms is followed by silence for at least 'sil' ms then\n"
59 "the audio playback is aborted and processing jumps to the 'talk' extension\n"
60 "if available.  If unspecified, sil, min, and max default to 1000, 100, and\n"
61 "infinity respectively.\n";
62
63 STANDARD_LOCAL_USER;
64
65 LOCAL_USER_DECL;
66
67 static int background_detect_exec(struct ast_channel *chan, void *data)
68 {
69         int res = 0;
70         struct localuser *u;
71         char *tmp;
72         char *options;
73         char *stringp;
74         struct ast_frame *fr;
75         int notsilent=0;
76         struct timeval start = { 0, 0};
77         int sil = 1000;
78         int min = 100;
79         int max = -1;
80         int x;
81         int origrformat=0;
82         struct ast_dsp *dsp;
83         
84         if (ast_strlen_zero(data)) {
85                 ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n");
86                 return -1;
87         }
88
89         LOCAL_USER_ADD(u);
90
91         tmp = ast_strdupa(data);
92
93         stringp=tmp;
94         strsep(&stringp, "|");
95         options = strsep(&stringp, "|");
96         if (options) {
97                 if ((sscanf(options, "%d", &x) == 1) && (x > 0))
98                         sil = x;
99                 options = strsep(&stringp, "|");
100                 if (options) {
101                         if ((sscanf(options, "%d", &x) == 1) && (x > 0))
102                                 min = x;
103                         options = strsep(&stringp, "|");
104                         if (options) {
105                                 if ((sscanf(options, "%d", &x) == 1) && (x > 0))
106                                         max = x;
107                         }
108                 }
109         }
110         ast_log(LOG_DEBUG, "Preparing detect of '%s', sil=%d,min=%d,max=%d\n", 
111                                                 tmp, sil, min, max);
112         if (chan->_state != AST_STATE_UP) {
113                 /* Otherwise answer unless we're supposed to send this while on-hook */
114                 res = ast_answer(chan);
115         }
116         if (!res) {
117                 origrformat = chan->readformat;
118                 if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR))) 
119                         ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
120         }
121         if (!(dsp = ast_dsp_new())) {
122                 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
123                 res = -1;
124         }
125         if (!res) {
126                 ast_stopstream(chan);
127                 res = ast_streamfile(chan, tmp, chan->language);
128                 if (!res) {
129                         while(chan->stream) {
130                                 res = ast_sched_wait(chan->sched);
131                                 if ((res < 0) && !chan->timingfunc) {
132                                         res = 0;
133                                         break;
134                                 }
135                                 if (res < 0)
136                                         res = 1000;
137                                 res = ast_waitfor(chan, res);
138                                 if (res < 0) {
139                                         ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
140                                         break;
141                                 } else if (res > 0) {
142                                         fr = ast_read(chan);
143                                         if (!fr) {
144                                                 res = -1;
145                                                 break;
146                                         } else if (fr->frametype == AST_FRAME_DTMF) {
147                                                 char t[2];
148                                                 t[0] = fr->subclass;
149                                                 t[1] = '\0';
150                                                 if (ast_canmatch_extension(chan, chan->context, t, 1, chan->cid.cid_num)) {
151                                                         /* They entered a valid  extension, or might be anyhow */
152                                                         res = fr->subclass;
153                                                         ast_frfree(fr);
154                                                         break;
155                                                 }
156                                         } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR)) {
157                                                 int totalsilence;
158                                                 int ms;
159                                                 res = ast_dsp_silence(dsp, fr, &totalsilence);
160                                                 if (res && (totalsilence > sil)) {
161                                                         /* We've been quiet a little while */
162                                                         if (notsilent) {
163                                                                 /* We had heard some talking */
164                                                                 ms = ast_tvdiff_ms(ast_tvnow(), start);
165                                                                 ms -= sil;
166                                                                 if (ms < 0)
167                                                                         ms = 0;
168                                                                 if ((ms > min) && ((max < 0) || (ms < max))) {
169                                                                         char ms_str[10];
170                                                                         ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
171
172                                                                         /* Save detected talk time (in milliseconds) */ 
173                                                                         sprintf(ms_str, "%d", ms );     
174                                                                         pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
175                                                                         
176                                                                         ast_goto_if_exists(chan, chan->context, "talk", 1);
177                                                                         res = 0;
178                                                                         ast_frfree(fr);
179                                                                         break;
180                                                                 } else
181                                                                         ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
182                                                                 notsilent = 0;
183                                                         }
184                                                 } else {
185                                                         if (!notsilent) {
186                                                                 /* Heard some audio, mark the begining of the token */
187                                                                 start = ast_tvnow();
188                                                                 ast_log(LOG_DEBUG, "Start of voice token!\n");
189                                                                 notsilent = 1;
190                                                         }
191                                                 }
192                                                 
193                                         }
194                                         ast_frfree(fr);
195                                 }
196                                 ast_sched_runq(chan->sched);
197                         }
198                         ast_stopstream(chan);
199                 } else {
200                         ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
201                         res = 0;
202                 }
203         }
204         if (res > -1) {
205                 if (origrformat && ast_set_read_format(chan, origrformat)) {
206                         ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", 
207                                 chan->name, ast_getformatname(origrformat));
208                 }
209         }
210         if (dsp)
211                 ast_dsp_free(dsp);
212         LOCAL_USER_REMOVE(u);
213         return res;
214 }
215
216 int unload_module(void)
217 {
218         int res;
219
220         res = ast_unregister_application(app);
221         
222         STANDARD_HANGUP_LOCALUSERS;
223
224         return res;     
225 }
226
227 int load_module(void)
228 {
229         return ast_register_application(app, background_detect_exec, synopsis, descrip);
230 }
231
232 char *description(void)
233 {
234         return tdesc;
235 }
236
237 int usecount(void)
238 {
239         int res;
240         STANDARD_USECOUNT(res);
241         return res;
242 }
243
244 char *key()
245 {
246         return ASTERISK_GPL_KEY;
247 }