Minor formatting change to test a mantis change ...
[asterisk-bristuff.git] / apps / app_talkdetect.c
blobfb862440dd8cff4d6d46512b74b0bfee401daf9f
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
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.
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.
19 /*! \file
21 * \brief Playback a file with audio detect
23 * \author Mark Spencer <markster@digium.com>
25 * \ingroup applications
28 #include "asterisk.h"
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32 #include "asterisk/lock.h"
33 #include "asterisk/file.h"
34 #include "asterisk/channel.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/module.h"
37 #include "asterisk/translate.h"
38 #include "asterisk/utils.h"
39 #include "asterisk/dsp.h"
40 #include "asterisk/app.h"
42 static char *app = "BackgroundDetect";
44 static char *synopsis = "Background a file with talk detect";
46 static char *descrip =
47 " BackgroundDetect(filename[,sil[,min,[max]]]): Plays back a given\n"
48 "filename, waiting for interruption from a given digit (the digit must\n"
49 "start the beginning of a valid extension, or it will be ignored).\n"
50 "During the playback of the file, audio is monitored in the receive\n"
51 "direction, and if a period of non-silence which is greater than 'min' ms\n"
52 "yet less than 'max' ms is followed by silence for at least 'sil' ms then\n"
53 "the audio playback is aborted and processing jumps to the 'talk' extension\n"
54 "if available. If unspecified, sil, min, and max default to 1000, 100, and\n"
55 "infinity respectively.\n";
58 static int background_detect_exec(struct ast_channel *chan, void *data)
60 int res = 0;
61 char *tmp;
62 struct ast_frame *fr;
63 int notsilent = 0;
64 struct timeval start = { 0, 0};
65 int sil = 1000;
66 int min = 100;
67 int max = -1;
68 int x;
69 int origrformat=0;
70 struct ast_dsp *dsp = NULL;
71 AST_DECLARE_APP_ARGS(args,
72 AST_APP_ARG(filename);
73 AST_APP_ARG(silence);
74 AST_APP_ARG(min);
75 AST_APP_ARG(max);
78 if (ast_strlen_zero(data)) {
79 ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n");
80 return -1;
83 tmp = ast_strdupa(data);
84 AST_STANDARD_APP_ARGS(args, tmp);
86 if (!ast_strlen_zero(args.silence) && (sscanf(args.silence, "%d", &x) == 1) && (x > 0))
87 sil = x;
88 if (!ast_strlen_zero(args.min) && (sscanf(args.min, "%d", &x) == 1) && (x > 0))
89 min = x;
90 if (!ast_strlen_zero(args.max) && (sscanf(args.max, "%d", &x) == 1) && (x > 0))
91 max = x;
93 ast_debug(1, "Preparing detect of '%s', sil=%d, min=%d, max=%d\n", args.filename, sil, min, max);
94 do {
95 if (chan->_state != AST_STATE_UP) {
96 if ((res = ast_answer(chan)))
97 break;
100 origrformat = chan->readformat;
101 if ((ast_set_read_format(chan, AST_FORMAT_SLINEAR))) {
102 ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
103 res = -1;
104 break;
107 if (!(dsp = ast_dsp_new())) {
108 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
109 res = -1;
110 break;
112 ast_stopstream(chan);
113 if (ast_streamfile(chan, tmp, chan->language)) {
114 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
115 break;
118 while (chan->stream) {
119 res = ast_sched_wait(chan->sched);
120 if ((res < 0) && !chan->timingfunc) {
121 res = 0;
122 break;
124 if (res < 0)
125 res = 1000;
126 res = ast_waitfor(chan, res);
127 if (res < 0) {
128 ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
129 break;
130 } else if (res > 0) {
131 fr = ast_read(chan);
132 if (!fr) {
133 res = -1;
134 break;
135 } else if (fr->frametype == AST_FRAME_DTMF) {
136 char t[2];
137 t[0] = fr->subclass;
138 t[1] = '\0';
139 if (ast_canmatch_extension(chan, chan->context, t, 1, chan->cid.cid_num)) {
140 /* They entered a valid extension, or might be anyhow */
141 res = fr->subclass;
142 ast_frfree(fr);
143 break;
145 } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR)) {
146 int totalsilence;
147 int ms;
148 res = ast_dsp_silence(dsp, fr, &totalsilence);
149 if (res && (totalsilence > sil)) {
150 /* We've been quiet a little while */
151 if (notsilent) {
152 /* We had heard some talking */
153 ms = ast_tvdiff_ms(ast_tvnow(), start);
154 ms -= sil;
155 if (ms < 0)
156 ms = 0;
157 if ((ms > min) && ((max < 0) || (ms < max))) {
158 char ms_str[10];
159 ast_debug(1, "Found qualified token of %d ms\n", ms);
161 /* Save detected talk time (in milliseconds) */
162 sprintf(ms_str, "%d", ms );
163 pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
165 ast_goto_if_exists(chan, chan->context, "talk", 1);
166 res = 0;
167 ast_frfree(fr);
168 break;
169 } else {
170 ast_debug(1, "Found unqualified token of %d ms\n", ms);
172 notsilent = 0;
174 } else {
175 if (!notsilent) {
176 /* Heard some audio, mark the begining of the token */
177 start = ast_tvnow();
178 ast_debug(1, "Start of voice token!\n");
179 notsilent = 1;
183 ast_frfree(fr);
185 ast_sched_runq(chan->sched);
187 ast_stopstream(chan);
188 } while (0);
190 if (res > -1) {
191 if (origrformat && ast_set_read_format(chan, origrformat)) {
192 ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n",
193 chan->name, ast_getformatname(origrformat));
196 if (dsp)
197 ast_dsp_free(dsp);
198 return res;
201 static int unload_module(void)
203 return ast_unregister_application(app);
206 static int load_module(void)
208 return ast_register_application(app, background_detect_exec, synopsis, descrip);
211 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Playback with Talk Detection");