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
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 358907 $")
00035
00036 #include "asterisk/lock.h"
00037 #include "asterisk/file.h"
00038 #include "asterisk/channel.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/module.h"
00041 #include "asterisk/translate.h"
00042 #include "asterisk/utils.h"
00043 #include "asterisk/dsp.h"
00044 #include "asterisk/app.h"
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 static char *app = "BackgroundDetect";
00079
00080 static int background_detect_exec(struct ast_channel *chan, const char *data)
00081 {
00082 int res = 0;
00083 char *tmp;
00084 struct ast_frame *fr;
00085 int notsilent = 0;
00086 struct timeval start = { 0, 0 };
00087 struct timeval detection_start = { 0, 0 };
00088 int sil = 1000;
00089 int min = 100;
00090 int max = -1;
00091 int analysistime = -1;
00092 int continue_analysis = 1;
00093 int x;
00094 struct ast_format origrformat;
00095 struct ast_dsp *dsp = NULL;
00096 AST_DECLARE_APP_ARGS(args,
00097 AST_APP_ARG(filename);
00098 AST_APP_ARG(silence);
00099 AST_APP_ARG(min);
00100 AST_APP_ARG(max);
00101 AST_APP_ARG(analysistime);
00102 );
00103
00104 ast_format_clear(&origrformat);
00105 if (ast_strlen_zero(data)) {
00106 ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n");
00107 return -1;
00108 }
00109
00110 tmp = ast_strdupa(data);
00111 AST_STANDARD_APP_ARGS(args, tmp);
00112
00113 if (!ast_strlen_zero(args.silence) && (sscanf(args.silence, "%30d", &x) == 1) && (x > 0)) {
00114 sil = x;
00115 }
00116 if (!ast_strlen_zero(args.min) && (sscanf(args.min, "%30d", &x) == 1) && (x > 0)) {
00117 min = x;
00118 }
00119 if (!ast_strlen_zero(args.max) && (sscanf(args.max, "%30d", &x) == 1) && (x > 0)) {
00120 max = x;
00121 }
00122 if (!ast_strlen_zero(args.analysistime) && (sscanf(args.analysistime, "%30d", &x) == 1) && (x > 0)) {
00123 analysistime = x;
00124 }
00125
00126 ast_debug(1, "Preparing detect of '%s', sil=%d, min=%d, max=%d, analysistime=%d\n", args.filename, sil, min, max, analysistime);
00127 do {
00128 if (ast_channel_state(chan) != AST_STATE_UP) {
00129 if ((res = ast_answer(chan))) {
00130 break;
00131 }
00132 }
00133
00134 ast_format_copy(&origrformat, ast_channel_readformat(chan));
00135 if ((ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR))) {
00136 ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
00137 res = -1;
00138 break;
00139 }
00140
00141 if (!(dsp = ast_dsp_new())) {
00142 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
00143 res = -1;
00144 break;
00145 }
00146 ast_stopstream(chan);
00147 if (ast_streamfile(chan, tmp, ast_channel_language(chan))) {
00148 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", ast_channel_name(chan), (char *)data);
00149 break;
00150 }
00151 detection_start = ast_tvnow();
00152 while (ast_channel_stream(chan)) {
00153 res = ast_sched_wait(ast_channel_sched(chan));
00154 if ((res < 0) && !ast_channel_timingfunc(chan)) {
00155 res = 0;
00156 break;
00157 }
00158 if (res < 0) {
00159 res = 1000;
00160 }
00161 res = ast_waitfor(chan, res);
00162 if (res < 0) {
00163 ast_log(LOG_WARNING, "Waitfor failed on %s\n", ast_channel_name(chan));
00164 break;
00165 } else if (res > 0) {
00166 fr = ast_read(chan);
00167 if (continue_analysis && analysistime >= 0) {
00168
00169
00170 if (ast_tvdiff_ms(ast_tvnow(), detection_start) >= analysistime) {
00171 continue_analysis = 0;
00172 ast_verb(3, "BackgroundDetect: Talk analysis time complete on %s.\n", ast_channel_name(chan));
00173 }
00174 }
00175
00176 if (!fr) {
00177 res = -1;
00178 break;
00179 } else if (fr->frametype == AST_FRAME_DTMF) {
00180 char t[2];
00181 t[0] = fr->subclass.integer;
00182 t[1] = '\0';
00183 if (ast_canmatch_extension(chan, ast_channel_context(chan), t, 1,
00184 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
00185
00186 res = fr->subclass.integer;
00187 ast_frfree(fr);
00188 break;
00189 }
00190 } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass.format.id == AST_FORMAT_SLINEAR) && continue_analysis) {
00191 int totalsilence;
00192 int ms;
00193 res = ast_dsp_silence(dsp, fr, &totalsilence);
00194 if (res && (totalsilence > sil)) {
00195
00196 if (notsilent) {
00197
00198 ms = ast_tvdiff_ms(ast_tvnow(), start);
00199 ms -= sil;
00200 if (ms < 0)
00201 ms = 0;
00202 if ((ms > min) && ((max < 0) || (ms < max))) {
00203 char ms_str[12];
00204 ast_debug(1, "Found qualified token of %d ms\n", ms);
00205
00206
00207 snprintf(ms_str, sizeof(ms_str), "%d", ms);
00208 pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
00209
00210 ast_goto_if_exists(chan, ast_channel_context(chan), "talk", 1);
00211 res = 0;
00212 ast_frfree(fr);
00213 break;
00214 } else {
00215 ast_debug(1, "Found unqualified token of %d ms\n", ms);
00216 }
00217 notsilent = 0;
00218 }
00219 } else {
00220 if (!notsilent) {
00221
00222 start = ast_tvnow();
00223 ast_debug(1, "Start of voice token!\n");
00224 notsilent = 1;
00225 }
00226 }
00227 }
00228 ast_frfree(fr);
00229 }
00230 ast_sched_runq(ast_channel_sched(chan));
00231 }
00232 ast_stopstream(chan);
00233 } while (0);
00234
00235 if (res > -1) {
00236 if (origrformat.id && ast_set_read_format(chan, &origrformat)) {
00237 ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n",
00238 ast_channel_name(chan), ast_getformatname(&origrformat));
00239 }
00240 }
00241 if (dsp) {
00242 ast_dsp_free(dsp);
00243 }
00244 return res;
00245 }
00246
00247 static int unload_module(void)
00248 {
00249 return ast_unregister_application(app);
00250 }
00251
00252 static int load_module(void)
00253 {
00254 return ast_register_application_xml(app, background_detect_exec);
00255 }
00256
00257 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Playback with Talk Detection");