00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <string.h>
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
00033
00034 #include "asterisk/lock.h"
00035 #include "asterisk/file.h"
00036 #include "asterisk/logger.h"
00037 #include "asterisk/channel.h"
00038 #include "asterisk/pbx.h"
00039 #include "asterisk/module.h"
00040 #include "asterisk/translate.h"
00041 #include "asterisk/utils.h"
00042 #include "asterisk/dsp.h"
00043
00044 static char *tdesc = "Playback with Talk Detection";
00045
00046 static char *app = "BackgroundDetect";
00047
00048 static char *synopsis = "Background a file with talk detect";
00049
00050 static char *descrip =
00051 " BackgroundDetect(filename[|sil[|min|[max]]]): Plays back a given\n"
00052 "filename, waiting for interruption from a given digit (the digit must\n"
00053 "start the beginning of a valid extension, or it will be ignored).\n"
00054 "During the playback of the file, audio is monitored in the receive\n"
00055 "direction, and if a period of non-silence which is greater than 'min' ms\n"
00056 "yet less than 'max' ms is followed by silence for at least 'sil' ms then\n"
00057 "the audio playback is aborted and processing jumps to the 'talk' extension\n"
00058 "if available. If unspecified, sil, min, and max default to 1000, 100, and\n"
00059 "infinity respectively.\n";
00060
00061 STANDARD_LOCAL_USER;
00062
00063 LOCAL_USER_DECL;
00064
00065 static int background_detect_exec(struct ast_channel *chan, void *data)
00066 {
00067 int res = 0;
00068 struct localuser *u;
00069 char *tmp;
00070 char *options;
00071 char *stringp;
00072 struct ast_frame *fr;
00073 int notsilent=0;
00074 struct timeval start = { 0, 0};
00075 int sil = 1000;
00076 int min = 100;
00077 int max = -1;
00078 int x;
00079 int origrformat=0;
00080 struct ast_dsp *dsp;
00081
00082 if (ast_strlen_zero(data)) {
00083 ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n");
00084 return -1;
00085 }
00086
00087 LOCAL_USER_ADD(u);
00088
00089 tmp = ast_strdupa(data);
00090 if (!tmp) {
00091 ast_log(LOG_ERROR, "Out of memory\n");
00092 LOCAL_USER_REMOVE(u);
00093 return -1;
00094 }
00095
00096 stringp=tmp;
00097 strsep(&stringp, "|");
00098 options = strsep(&stringp, "|");
00099 if (options) {
00100 if ((sscanf(options, "%d", &x) == 1) && (x > 0))
00101 sil = x;
00102 options = strsep(&stringp, "|");
00103 if (options) {
00104 if ((sscanf(options, "%d", &x) == 1) && (x > 0))
00105 min = x;
00106 options = strsep(&stringp, "|");
00107 if (options) {
00108 if ((sscanf(options, "%d", &x) == 1) && (x > 0))
00109 max = x;
00110 }
00111 }
00112 }
00113 ast_log(LOG_DEBUG, "Preparing detect of '%s', sil=%d,min=%d,max=%d\n",
00114 tmp, sil, min, max);
00115 if (chan->_state != AST_STATE_UP) {
00116
00117 res = ast_answer(chan);
00118 }
00119 if (!res) {
00120 origrformat = chan->readformat;
00121 if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)))
00122 ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
00123 }
00124 if (!(dsp = ast_dsp_new())) {
00125 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
00126 res = -1;
00127 }
00128 if (!res) {
00129 ast_stopstream(chan);
00130 res = ast_streamfile(chan, tmp, chan->language);
00131 if (!res) {
00132 while(chan->stream) {
00133 res = ast_sched_wait(chan->sched);
00134 if ((res < 0) && !chan->timingfunc) {
00135 res = 0;
00136 break;
00137 }
00138 if (res < 0)
00139 res = 1000;
00140 res = ast_waitfor(chan, res);
00141 if (res < 0) {
00142 ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
00143 break;
00144 } else if (res > 0) {
00145 fr = ast_read(chan);
00146 if (!fr) {
00147 res = -1;
00148 break;
00149 } else if (fr->frametype == AST_FRAME_DTMF) {
00150 char t[2];
00151 t[0] = fr->subclass;
00152 t[1] = '\0';
00153 if (ast_canmatch_extension(chan, chan->context, t, 1, chan->cid.cid_num)) {
00154
00155 res = fr->subclass;
00156 ast_frfree(fr);
00157 break;
00158 }
00159 } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR)) {
00160 int totalsilence;
00161 int ms;
00162 res = ast_dsp_silence(dsp, fr, &totalsilence);
00163 if (res && (totalsilence > sil)) {
00164
00165 if (notsilent) {
00166
00167 ms = ast_tvdiff_ms(ast_tvnow(), start);
00168 ms -= sil;
00169 if (ms < 0)
00170 ms = 0;
00171 if ((ms > min) && ((max < 0) || (ms < max))) {
00172 char ms_str[10];
00173 ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
00174
00175
00176 sprintf(ms_str, "%d", ms );
00177 pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
00178
00179 ast_goto_if_exists(chan, chan->context, "talk", 1);
00180 res = 0;
00181 ast_frfree(fr);
00182 break;
00183 } else
00184 ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
00185 notsilent = 0;
00186 }
00187 } else {
00188 if (!notsilent) {
00189
00190 start = ast_tvnow();
00191 ast_log(LOG_DEBUG, "Start of voice token!\n");
00192 notsilent = 1;
00193 }
00194 }
00195
00196 }
00197 ast_frfree(fr);
00198 }
00199 ast_sched_runq(chan->sched);
00200 }
00201 ast_stopstream(chan);
00202 } else {
00203 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
00204 res = 0;
00205 }
00206 }
00207 if (res > -1) {
00208 if (origrformat && ast_set_read_format(chan, origrformat)) {
00209 ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n",
00210 chan->name, ast_getformatname(origrformat));
00211 }
00212 }
00213 if (dsp)
00214 ast_dsp_free(dsp);
00215 LOCAL_USER_REMOVE(u);
00216 return res;
00217 }
00218
00219 int unload_module(void)
00220 {
00221 int res;
00222
00223 res = ast_unregister_application(app);
00224
00225 STANDARD_HANGUP_LOCALUSERS;
00226
00227 return res;
00228 }
00229
00230 int load_module(void)
00231 {
00232 return ast_register_application(app, background_detect_exec, synopsis, descrip);
00233 }
00234
00235 char *description(void)
00236 {
00237 return tdesc;
00238 }
00239
00240 int usecount(void)
00241 {
00242 int res;
00243 STANDARD_USECOUNT(res);
00244 return res;
00245 }
00246
00247 char *key()
00248 {
00249 return ASTERISK_GPL_KEY;
00250 }