#include <asterisk.h>
#include <stdio.h>
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/dsp.h>
#include <asterisk/utils.h>
#include <string.h>
#include <stdlib.h>
Include dependency graph for app_nv_faxdetect.c:
Go to the source code of this file.
Defines | |
#define | CALLERID_FIELD cid.cid_num |
Functions | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Newman's fax detection application") | |
static int | load_module (void) |
static int | nv_detectfax_exec (struct ast_channel *chan, void *data) |
static int | unload_module (void) |
Variables | |
static char * | app = "NVFaxDetect" |
static char * | descrip |
static char * | synopsis = "Detects fax sounds on all channel types (IAX and SIP too)" |
#define CALLERID_FIELD cid.cid_num |
Definition at line 64 of file app_nv_faxdetect.c.
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Newman's fax detection application" | ||||
) |
static int load_module | ( | void | ) | [static] |
Definition at line 291 of file app_nv_faxdetect.c.
References app, ast_register_application(), descrip, nv_detectfax_exec(), and synopsis.
00292 { 00293 return ast_register_application(app, nv_detectfax_exec, synopsis, descrip); 00294 }
static int nv_detectfax_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 65 of file app_nv_faxdetect.c.
References ast_channel::_state, ast_answer(), ast_canmatch_extension(), ast_dsp_digitmode(), ast_dsp_free(), ast_dsp_new(), ast_dsp_process(), ast_dsp_set_features(), ast_dsp_set_threshold(), ast_dsp_silence(), ast_exists_extension(), AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree(), ast_getformatname(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_read(), ast_set_read_format(), AST_STATE_UP, ast_strlen_zero(), ast_waitfor(), DSP_DIGITMODE_DTMF, DSP_DIGITMODE_RELAXDTMF, DSP_FEATURE_DTMF_DETECT, DSP_FEATURE_FAX_DETECT, ast_frame::frametype, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, pbx_builtin_setvar_helper(), ast_channel::readformat, strsep(), ast_frame::subclass, t, timeout, and ast_dsp::totalsilence.
Referenced by load_module().
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 /* Otherwise answer unless we're supposed to send this while on-hook */ 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 if (!ignoretalk) 00155 features |= DSP_FEATURE_SILENCE_SUPPRESS; 00156 */ 00157 if (!ignorefax) 00158 features |= DSP_FEATURE_FAX_DETECT; 00159 00160 //if (!ignoredtmf) 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 /* Fax tone -- Handle and return NULL */ 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 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ 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 /* They entered a valid extension, or might be anyhow */ 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 /* We've been quiet a little while */ 00234 if (notsilent) { 00235 00236 /* We had heard some talking */ 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 /* Save detected talk time (in milliseconds) */ 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 /* Heard some audio, mark the begining of the token */ 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 }
static int unload_module | ( | void | ) | [static] |
Definition at line 287 of file app_nv_faxdetect.c.
References app, and ast_unregister_application().
00288 { 00289 return ast_unregister_application(app); 00290 }
char* app = "NVFaxDetect" [static] |
Definition at line 40 of file app_nv_faxdetect.c.
char* descrip [static] |
Definition at line 42 of file app_nv_faxdetect.c.
Definition at line 41 of file app_nv_faxdetect.c.