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: 211528 $")
00031
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <string.h>
00035
00036 #include "asterisk/lock.h"
00037 #include "asterisk/file.h"
00038 #include "asterisk/logger.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/module.h"
00042 #include "asterisk/translate.h"
00043 #include "asterisk/utils.h"
00044 #include "asterisk/dsp.h"
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
00062 static int background_detect_exec(struct ast_channel *chan, void *data)
00063 {
00064 int res = 0;
00065 struct ast_module_user *u;
00066 char *tmp;
00067 char *options;
00068 char *stringp;
00069 struct ast_frame *fr;
00070 int notsilent=0;
00071 struct timeval start = { 0, 0};
00072 int sil = 1000;
00073 int min = 100;
00074 int max = -1;
00075 int x;
00076 int origrformat=0;
00077 struct ast_dsp *dsp;
00078
00079 if (ast_strlen_zero(data)) {
00080 ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n");
00081 return -1;
00082 }
00083
00084 u = ast_module_user_add(chan);
00085
00086 tmp = ast_strdupa(data);
00087
00088 stringp=tmp;
00089 strsep(&stringp, "|");
00090 options = strsep(&stringp, "|");
00091 if (options) {
00092 if ((sscanf(options, "%30d", &x) == 1) && (x > 0))
00093 sil = x;
00094 options = strsep(&stringp, "|");
00095 if (options) {
00096 if ((sscanf(options, "%30d", &x) == 1) && (x > 0))
00097 min = x;
00098 options = strsep(&stringp, "|");
00099 if (options) {
00100 if ((sscanf(options, "%30d", &x) == 1) && (x > 0))
00101 max = x;
00102 }
00103 }
00104 }
00105 ast_log(LOG_DEBUG, "Preparing detect of '%s', sil=%d,min=%d,max=%d\n",
00106 tmp, sil, min, max);
00107 if (chan->_state != AST_STATE_UP) {
00108
00109 res = ast_answer(chan);
00110 }
00111 if (!res) {
00112 origrformat = chan->readformat;
00113 if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)))
00114 ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
00115 }
00116 if (!(dsp = ast_dsp_new())) {
00117 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
00118 res = -1;
00119 }
00120 if (!res) {
00121 ast_stopstream(chan);
00122 res = ast_streamfile(chan, tmp, chan->language);
00123 if (!res) {
00124 while(chan->stream) {
00125 res = ast_sched_wait(chan->sched);
00126 if ((res < 0) && !chan->timingfunc) {
00127 res = 0;
00128 break;
00129 }
00130 if (res < 0)
00131 res = 1000;
00132 res = ast_waitfor(chan, res);
00133 if (res < 0) {
00134 ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
00135 break;
00136 } else if (res > 0) {
00137 fr = ast_read(chan);
00138 if (!fr) {
00139 res = -1;
00140 break;
00141 } else if (fr->frametype == AST_FRAME_DTMF) {
00142 char t[2];
00143 t[0] = fr->subclass;
00144 t[1] = '\0';
00145 if (ast_canmatch_extension(chan, chan->context, t, 1, chan->cid.cid_num)) {
00146
00147 res = fr->subclass;
00148 ast_frfree(fr);
00149 break;
00150 }
00151 } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR)) {
00152 int totalsilence;
00153 int ms;
00154 res = ast_dsp_silence(dsp, fr, &totalsilence);
00155 if (res && (totalsilence > sil)) {
00156
00157 if (notsilent) {
00158
00159 ms = ast_tvdiff_ms(ast_tvnow(), start);
00160 ms -= sil;
00161 if (ms < 0)
00162 ms = 0;
00163 if ((ms > min) && ((max < 0) || (ms < max))) {
00164 char ms_str[10];
00165 ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
00166
00167
00168 sprintf(ms_str, "%d", ms );
00169 pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
00170
00171 ast_goto_if_exists(chan, chan->context, "talk", 1);
00172 res = 0;
00173 ast_frfree(fr);
00174 break;
00175 } else
00176 ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
00177 notsilent = 0;
00178 }
00179 } else {
00180 if (!notsilent) {
00181
00182 start = ast_tvnow();
00183 ast_log(LOG_DEBUG, "Start of voice token!\n");
00184 notsilent = 1;
00185 }
00186 }
00187
00188 }
00189 ast_frfree(fr);
00190 }
00191 ast_sched_runq(chan->sched);
00192 }
00193 ast_stopstream(chan);
00194 } else {
00195 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
00196 res = 0;
00197 }
00198 }
00199 if (res > -1) {
00200 if (origrformat && ast_set_read_format(chan, origrformat)) {
00201 ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n",
00202 chan->name, ast_getformatname(origrformat));
00203 }
00204 }
00205 if (dsp)
00206 ast_dsp_free(dsp);
00207 ast_module_user_remove(u);
00208 return res;
00209 }
00210
00211 static int unload_module(void)
00212 {
00213 int res;
00214
00215 res = ast_unregister_application(app);
00216
00217 ast_module_user_hangup_all();
00218
00219 return res;
00220 }
00221
00222 static int load_module(void)
00223 {
00224 return ast_register_application(app, background_detect_exec, synopsis, descrip);
00225 }
00226
00227 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Playback with Talk Detection");