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 <asterisk.h>
00027
00028 #include <stdio.h>
00029 #include <asterisk/lock.h>
00030 #include <asterisk/file.h>
00031 #include <asterisk/logger.h>
00032 #include <asterisk/channel.h>
00033 #include <asterisk/pbx.h>
00034 #include <asterisk/module.h>
00035 #include <asterisk/translate.h>
00036 #include <asterisk/dsp.h>
00037 #include <asterisk/utils.h>
00038 #include <string.h>
00039 #include <stdlib.h>
00040 static char *app = "NVFaxDetect";
00041 static char *synopsis = "Detects fax sounds on all channel types (IAX and SIP too)";
00042 static char *descrip = " NVFaxDetect([waitdur[|options[|sildur[|mindur[|maxdur]]]]]):\n"
00043 "This application listens for fax tones (on IAX and SIP channels too)\n"
00044 "for waitdur seconds of time. In addition, it can be interrupted by digits,\n"
00045 "or non-silence. Audio is only monitored in the receive direction. If\n"
00046 "digits interrupt, they must be the start of a valid extension unless the\n"
00047 "option is included to ignore. If fax is detected, it will jump to the\n"
00048 "'fax' extension. If a period of non-silence greater than 'mindur' ms,\n"
00049 "yet less than 'maxdur' ms is followed by silence at least 'sildur' ms\n"
00050 "then the app is aborted and processing jumps to the 'talk' extension.\n"
00051 "If all undetected, control will continue at the next priority.\n"
00052 " waitdur: Maximum number of seconds to wait (default=4)\n"
00053 " options:\n"
00054 " 'n': Attempt on-hook if unanswered (default=no)\n"
00055 " 'x': DTMF digits terminate without extension (default=no)\n"
00056 " 'd': Ignore DTMF digit detection (default=no)\n"
00057 " 'f': Ignore fax detection (default=no)\n"
00058 " 't': Ignore talk detection (default=no)\n"
00059 " sildur: Silence ms after mindur/maxdur before aborting (default=1000)\n"
00060 " mindur: Minimum non-silence ms needed (default=100)\n"
00061 " maxdur: Maximum non-silence ms allowed (default=0/forever)\n"
00062 "Returns -1 on hangup, and 0 on successful completion with no exit conditions.\n\n" "For questions or comments, please e-mail support@newmantelecom.com.\n";
00063
00064 #define CALLERID_FIELD cid.cid_num
00065 static int nv_detectfax_exec(struct ast_channel *chan, void *data)
00066 {
00067 int res = 0;
00068 struct ast_module_user *u;
00069 char tmp[256] = "\0";
00070 char *p = NULL;
00071 char *waitstr = NULL;
00072 char *options = NULL;
00073 char *silstr = NULL;
00074 char *minstr = NULL;
00075 char *maxstr = NULL;
00076 struct ast_frame *fr = NULL;
00077 struct ast_frame *fr2 = NULL;
00078 int notsilent = 0;
00079 struct timeval start = { 0, 0 }, end = {
00080 0, 0};
00081 int waitdur = 4;
00082 int sildur = 1000;
00083 int mindur = 100;
00084 int maxdur = -1;
00085 int skipanswer = 0;
00086 int noextneeded = 0;
00087 int ignoredtmf = 0;
00088 int ignorefax = 0;
00089 int ignoretalk = 0;
00090 int x = 0;
00091 int origrformat = 0;
00092 int features = 0;
00093 time_t timeout = 0;
00094 struct ast_dsp *dsp = NULL;
00095 pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "");
00096 pbx_builtin_setvar_helper(chan, "FAXEXTEN", "");
00097 pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "");
00098 pbx_builtin_setvar_helper(chan, "TALK_DETECTED", "");
00099 if (data || !ast_strlen_zero((char *) data)) {
00100 strncpy(tmp, (char *) data, sizeof(tmp) - 1);
00101 }
00102 p = tmp;
00103 waitstr = strsep(&p, "|");
00104 options = strsep(&p, "|");
00105 silstr = strsep(&p, "|");
00106 minstr = strsep(&p, "|");
00107 maxstr = strsep(&p, "|");
00108 if (waitstr) {
00109 if ((sscanf(waitstr, "%d", &x) == 1) && (x > 0))
00110 waitdur = x;
00111 }
00112 if (options) {
00113 if (strchr(options, 'n'))
00114 skipanswer = 1;
00115 if (strchr(options, 'x'))
00116 noextneeded = 1;
00117 if (strchr(options, 'd'))
00118 ignoredtmf = 1;
00119 if (strchr(options, 'f'))
00120 ignorefax = 1;
00121 if (strchr(options, 't'))
00122 ignoretalk = 1;
00123 }
00124 if (silstr) {
00125 if ((sscanf(silstr, "%d", &x) == 1) && (x > 0))
00126 sildur = x;
00127 }
00128 if (minstr) {
00129 if ((sscanf(minstr, "%d", &x) == 1) && (x > 0))
00130 mindur = x;
00131 }
00132 if (maxstr) {
00133 if ((sscanf(maxstr, "%d", &x) == 1) && (x > 0))
00134 maxdur = x;
00135 }
00136 ast_log(LOG_DEBUG, "Preparing detect of fax (waitdur=%dms, sildur=%dms, mindur=%dms, maxdur=%dms)\n", waitdur, sildur, mindur, maxdur);
00137 u = ast_module_user_add(chan);
00138 if (chan->_state != AST_STATE_UP && !skipanswer) {
00139
00140
00141 res = ast_answer(chan);
00142 }
00143 if (!res) {
00144 origrformat = chan->readformat;
00145 if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)))
00146 ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
00147 }
00148 if (!(dsp = ast_dsp_new())) {
00149 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
00150 res = -1;
00151 }
00152 if (dsp) {
00153
00154
00155
00156
00157 if (!ignorefax)
00158 features |= DSP_FEATURE_FAX_DETECT;
00159
00160
00161 features |= DSP_FEATURE_DTMF_DETECT;
00162 ast_dsp_set_threshold(dsp, 256);
00163 ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF);
00164 ast_dsp_digitmode(dsp, DSP_DIGITMODE_DTMF);
00165 }
00166 if (!res) {
00167 if (waitdur > 0)
00168 timeout = time(NULL) + (time_t) waitdur;
00169 while (ast_waitfor(chan, -1) > -1) {
00170 if (waitdur > 0 && time(NULL) > timeout) {
00171 res = 0;
00172 break;
00173 }
00174 fr = ast_read(chan);
00175 if (!fr) {
00176 ast_log(LOG_DEBUG, "Got hangup\n");
00177 res = -1;
00178 break;
00179 }
00180 fr2 = ast_dsp_process(chan, dsp, fr);
00181 if (!fr2) {
00182 ast_log(LOG_WARNING, "Bad DSP received (what happened?)\n");
00183 fr2 = fr;
00184 }
00185 if (fr2->frametype == AST_FRAME_DTMF) {
00186 if (fr2->subclass == 'f' && !ignorefax) {
00187
00188
00189 ast_log(LOG_DEBUG, "Fax detected on %s\n", chan->name);
00190 if (strcmp(chan->exten, "fax")) {
00191 ast_log(LOG_NOTICE, "Redirecting %s to fax extension\n", chan->name);
00192 pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1");
00193 pbx_builtin_setvar_helper(chan, "FAXEXTEN", chan->exten);
00194 if (ast_exists_extension(chan, chan->context, "fax", 1, chan->CALLERID_FIELD)) {
00195
00196
00197 strncpy(chan->exten, "fax", sizeof(chan->exten) - 1);
00198 chan->priority = 0;
00199 } else
00200 ast_log(LOG_WARNING, "Fax detected, but no fax extension\n");
00201 } else
00202 ast_log(LOG_WARNING, "Already in a fax extension, not redirecting\n");
00203 res = 0;
00204 ast_frfree(fr);
00205 break;
00206 } else if (!ignoredtmf) {
00207 ast_log(LOG_DEBUG, "DTMF detected on %s\n", chan->name);
00208 char t[2];
00209 t[0] = fr2->subclass;
00210 t[1] = '\0';
00211 if (noextneeded || ast_canmatch_extension(chan, chan->context, t, 1, chan->CALLERID_FIELD)) {
00212 pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "1");
00213
00214
00215 if (noextneeded) {
00216 ast_log(LOG_NOTICE, "DTMF received (not matching to exten)\n");
00217 res = 0;
00218 } else {
00219 ast_log(LOG_NOTICE, "DTMF received (matching to exten)\n");
00220 res = fr2->subclass;
00221 }
00222 ast_frfree(fr);
00223 break;
00224 } else
00225 ast_log(LOG_DEBUG, "Valid extension requested and DTMF did not match\n");
00226 }
00227 } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR) && !ignoretalk) {
00228 int totalsilence;
00229 int ms;
00230 res = ast_dsp_silence(dsp, fr, &totalsilence);
00231 if (res && (totalsilence > sildur)) {
00232
00233
00234 if (notsilent) {
00235
00236
00237 gettimeofday(&end, NULL);
00238 ms = (end.tv_sec - start.tv_sec) * 1000;
00239 ms += (end.tv_usec - start.tv_usec) / 1000;
00240 ms -= sildur;
00241 if (ms < 0)
00242 ms = 0;
00243 if ((ms > mindur) && ((maxdur < 0) || (ms < maxdur))) {
00244 char ms_str[10];
00245 ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
00246 ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", chan->name);
00247
00248
00249 sprintf(ms_str, "%d", ms);
00250 pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
00251 if (ast_exists_extension(chan, chan->context, "talk", 1, chan->CALLERID_FIELD)) {
00252 strncpy(chan->exten, "talk", sizeof(chan->exten) - 1);
00253 chan->priority = 0;
00254 } else
00255 ast_log(LOG_WARNING, "Talk detected, but no talk extension\n");
00256 res = 0;
00257 ast_frfree(fr);
00258 break;
00259 } else
00260 ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
00261 notsilent = 0;
00262 }
00263 } else {
00264 if (!notsilent) {
00265
00266
00267 gettimeofday(&start, NULL);
00268 ast_log(LOG_DEBUG, "Start of voice token!\n");
00269 notsilent = 1;
00270 }
00271 }
00272 }
00273 ast_frfree(fr);
00274 }
00275 } else
00276 ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
00277 if (res > -1) {
00278 if (origrformat && ast_set_read_format(chan, origrformat)) {
00279 ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", chan->name, ast_getformatname(origrformat));
00280 }
00281 }
00282 if (dsp)
00283 ast_dsp_free(dsp);
00284 ast_module_user_remove(u);
00285 return res;
00286 }
00287 static int unload_module(void)
00288 {
00289 ast_module_user_hangup_all();
00290 return ast_unregister_application(app);
00291 }
00292 static int load_module(void)
00293 {
00294 return ast_register_application(app, nv_detectfax_exec, synopsis, descrip);
00295 }
00296
00297 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Newman's fax detection application");