2 * Asterisk -- A telephony toolkit for Linux.
4 * Playback a file with audio detect
6 * Copyright (C) 2004, Digium, Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/module.h>
20 #include <asterisk/translate.h>
21 #include <asterisk/utils.h>
22 #include <asterisk/dsp.h>
27 static char *tdesc = "Playback with Talk Detection";
29 static char *app = "BackgroundDetect";
31 static char *synopsis = "Background a file with talk detect";
33 static char *descrip =
34 " BackgroundDetect(filename[|sil[|min|[max]]]): Plays back a given\n"
35 "filename, waiting for interruption from a given digit (the digit must\n"
36 "start the beginning of a valid extension, or it will be ignored).\n"
37 "During the playback of the file, audio is monitored in the receive\n"
38 "direction, and if a period of non-silence which is greater than 'min' ms\n"
39 "yet less than 'max' ms is followed by silence for at least 'sil' ms then\n"
40 "the audio playback is aborted and processing jumps to the 'talk' extension\n"
41 "if available. If unspecified, sil, min, and max default to 1000, 100, and\n"
42 "infinity respectively. Returns -1 on hangup, and 0 on successful playback\n"
43 "completion with no exit conditions.\n";
49 static int background_detect_exec(struct ast_channel *chan, void *data)
58 struct timeval start = { 0, 0}, end = {0, 0};
65 if (!data || ast_strlen_zero((char *)data)) {
66 ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n");
69 strncpy(tmp, (char *)data, sizeof(tmp)-1);
71 strsep(&stringp, "|");
72 options = strsep(&stringp, "|");
74 if ((sscanf(options, "%d", &x) == 1) && (x > 0))
76 options = strsep(&stringp, "|");
78 if ((sscanf(options, "%d", &x) == 1) && (x > 0))
80 options = strsep(&stringp, "|");
82 if ((sscanf(options, "%d", &x) == 1) && (x > 0))
87 ast_log(LOG_DEBUG, "Preparing detect of '%s', sil=%d,min=%d,max=%d\n",
90 if (chan->_state != AST_STATE_UP) {
91 /* Otherwise answer unless we're supposed to send this while on-hook */
92 res = ast_answer(chan);
95 origrformat = chan->readformat;
96 if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)))
97 ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
99 if (!(dsp = ast_dsp_new())) {
100 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
104 ast_stopstream(chan);
105 res = ast_streamfile(chan, tmp, chan->language);
107 while(chan->stream) {
108 res = ast_sched_wait(chan->sched);
109 if ((res < 0) && !chan->timingfunc) {
115 res = ast_waitfor(chan, res);
117 ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
119 } else if (res > 0) {
124 } else if (fr->frametype == AST_FRAME_DTMF) {
128 if (ast_canmatch_extension(chan, chan->context, t, 1, chan->callerid)) {
129 /* They entered a valid extension, or might be anyhow */
134 } else if (fr->frametype == AST_FRAME_VOICE) {
137 res = ast_dsp_silence(dsp, fr, &totalsilence);
138 if (res && (totalsilence > sil)) {
139 /* We've been quiet a little while */
141 /* We had heard some talking */
142 gettimeofday(&end, NULL);
143 ms = (end.tv_sec - start.tv_sec) * 1000;
144 ms += (end.tv_usec - start.tv_usec) / 1000;
148 if ((ms > min) && ((max < 0) || (ms < max))) {
149 ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
150 if (ast_exists_extension(chan, chan->context, "talk", 1, chan->callerid)) {
151 strncpy(chan->exten, "talk", sizeof(chan->exten) -1 );
158 ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
163 /* Heard some audio, mark the begining of the token */
164 gettimeofday(&start, NULL);
165 ast_log(LOG_DEBUG, "Start of voice token!\n");
174 ast_stopstream(chan);
176 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
181 if (origrformat && ast_set_read_format(chan, origrformat)) {
182 ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n",
183 chan->name, ast_getformatname(origrformat));
188 LOCAL_USER_REMOVE(u);
192 int unload_module(void)
194 STANDARD_HANGUP_LOCALUSERS;
195 return ast_unregister_application(app);
198 int load_module(void)
200 return ast_register_application(app, background_detect_exec, synopsis, descrip);
203 char *description(void)
211 STANDARD_USECOUNT(res);
217 return ASTERISK_GPL_KEY;