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