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
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 106140 $")
00031
00032 #include "asterisk/lock.h"
00033 #include "asterisk/file.h"
00034 #include "asterisk/channel.h"
00035 #include "asterisk/pbx.h"
00036 #include "asterisk/module.h"
00037 #include "asterisk/translate.h"
00038 #include "asterisk/utils.h"
00039 #include "asterisk/dsp.h"
00040 #include "asterisk/app.h"
00041
00042 static char *app = "BackgroundDetect";
00043
00044 static char *synopsis = "Background a file with talk detect";
00045
00046 static char *descrip =
00047 " BackgroundDetect(filename[,sil[,min,[max]]]): Plays back a given\n"
00048 "filename, waiting for interruption from a given digit (the digit must\n"
00049 "start the beginning of a valid extension, or it will be ignored).\n"
00050 "During the playback of the file, audio is monitored in the receive\n"
00051 "direction, and if a period of non-silence which is greater than 'min' ms\n"
00052 "yet less than 'max' ms is followed by silence for at least 'sil' ms then\n"
00053 "the audio playback is aborted and processing jumps to the 'talk' extension\n"
00054 "if available. If unspecified, sil, min, and max default to 1000, 100, and\n"
00055 "infinity respectively.\n";
00056
00057
00058 static int background_detect_exec(struct ast_channel *chan, void *data)
00059 {
00060 int res = 0;
00061 char *tmp;
00062 struct ast_frame *fr;
00063 int notsilent = 0;
00064 struct timeval start = { 0, 0};
00065 int sil = 1000;
00066 int min = 100;
00067 int max = -1;
00068 int x;
00069 int origrformat=0;
00070 struct ast_dsp *dsp = NULL;
00071 AST_DECLARE_APP_ARGS(args,
00072 AST_APP_ARG(filename);
00073 AST_APP_ARG(silence);
00074 AST_APP_ARG(min);
00075 AST_APP_ARG(max);
00076 );
00077
00078 if (ast_strlen_zero(data)) {
00079 ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n");
00080 return -1;
00081 }
00082
00083 tmp = ast_strdupa(data);
00084 AST_STANDARD_APP_ARGS(args, tmp);
00085
00086 if (!ast_strlen_zero(args.silence) && (sscanf(args.silence, "%d", &x) == 1) && (x > 0))
00087 sil = x;
00088 if (!ast_strlen_zero(args.min) && (sscanf(args.min, "%d", &x) == 1) && (x > 0))
00089 min = x;
00090 if (!ast_strlen_zero(args.max) && (sscanf(args.max, "%d", &x) == 1) && (x > 0))
00091 max = x;
00092
00093 ast_debug(1, "Preparing detect of '%s', sil=%d, min=%d, max=%d\n", args.filename, sil, min, max);
00094 do {
00095 if (chan->_state != AST_STATE_UP) {
00096 if ((res = ast_answer(chan)))
00097 break;
00098 }
00099
00100 origrformat = chan->readformat;
00101 if ((ast_set_read_format(chan, AST_FORMAT_SLINEAR))) {
00102 ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
00103 res = -1;
00104 break;
00105 }
00106
00107 if (!(dsp = ast_dsp_new())) {
00108 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
00109 res = -1;
00110 break;
00111 }
00112 ast_stopstream(chan);
00113 if (ast_streamfile(chan, tmp, chan->language)) {
00114 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
00115 break;
00116 }
00117
00118 while (chan->stream) {
00119 res = ast_sched_wait(chan->sched);
00120 if ((res < 0) && !chan->timingfunc) {
00121 res = 0;
00122 break;
00123 }
00124 if (res < 0)
00125 res = 1000;
00126 res = ast_waitfor(chan, res);
00127 if (res < 0) {
00128 ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
00129 break;
00130 } else if (res > 0) {
00131 fr = ast_read(chan);
00132 if (!fr) {
00133 res = -1;
00134 break;
00135 } else if (fr->frametype == AST_FRAME_DTMF) {
00136 char t[2];
00137 t[0] = fr->subclass;
00138 t[1] = '\0';
00139 if (ast_canmatch_extension(chan, chan->context, t, 1, chan->cid.cid_num)) {
00140
00141 res = fr->subclass;
00142 ast_frfree(fr);
00143 break;
00144 }
00145 } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR)) {
00146 int totalsilence;
00147 int ms;
00148 res = ast_dsp_silence(dsp, fr, &totalsilence);
00149 if (res && (totalsilence > sil)) {
00150
00151 if (notsilent) {
00152
00153 ms = ast_tvdiff_ms(ast_tvnow(), start);
00154 ms -= sil;
00155 if (ms < 0)
00156 ms = 0;
00157 if ((ms > min) && ((max < 0) || (ms < max))) {
00158 char ms_str[10];
00159 ast_debug(1, "Found qualified token of %d ms\n", ms);
00160
00161
00162 sprintf(ms_str, "%d", ms );
00163 pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
00164
00165 ast_goto_if_exists(chan, chan->context, "talk", 1);
00166 res = 0;
00167 ast_frfree(fr);
00168 break;
00169 } else {
00170 ast_debug(1, "Found unqualified token of %d ms\n", ms);
00171 }
00172 notsilent = 0;
00173 }
00174 } else {
00175 if (!notsilent) {
00176
00177 start = ast_tvnow();
00178 ast_debug(1, "Start of voice token!\n");
00179 notsilent = 1;
00180 }
00181 }
00182 }
00183 ast_frfree(fr);
00184 }
00185 ast_sched_runq(chan->sched);
00186 }
00187 ast_stopstream(chan);
00188 } while (0);
00189
00190 if (res > -1) {
00191 if (origrformat && ast_set_read_format(chan, origrformat)) {
00192 ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n",
00193 chan->name, ast_getformatname(origrformat));
00194 }
00195 }
00196 if (dsp)
00197 ast_dsp_free(dsp);
00198 return res;
00199 }
00200
00201 static int unload_module(void)
00202 {
00203 return ast_unregister_application(app);
00204 }
00205
00206 static int load_module(void)
00207 {
00208 return ast_register_application(app, background_detect_exec, synopsis, descrip);
00209 }
00210
00211 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Playback with Talk Detection");