#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/utils.h>
#include <asterisk/dsp.h>
#include <string.h>
#include <stdlib.h>
Include dependency graph for app_nv_backgrounddetect.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 playback with talk and fax detection") | |
static int | load_module (void) |
static int | nv_background_detect_exec (struct ast_channel *chan, void *data) |
static int | unload_module (void) |
Variables | |
static char * | app = "NVBackgroundDetect" |
static char * | descrip |
static char * | synopsis = "Background a file with talk and fax detect (IAX and SIP too)" |
#define CALLERID_FIELD cid.cid_num |
Definition at line 66 of file app_nv_backgrounddetect.c.
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Newman's playback with talk and fax detection" | ||||
) |
static int load_module | ( | void | ) | [static] |
Definition at line 321 of file app_nv_backgrounddetect.c.
References app, ast_register_application(), descrip, nv_background_detect_exec(), and synopsis.
00322 { 00323 return ast_register_application(app, nv_background_detect_exec, synopsis, descrip); 00324 }
static int nv_background_detect_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 68 of file app_nv_backgrounddetect.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_sched_runq(), ast_sched_wait(), ast_set_read_format(), AST_STATE_UP, ast_stopstream(), ast_streamfile(), 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, and ast_dsp::totalsilence.
Referenced by load_module().
00069 { 00070 int res = 0; 00071 struct ast_module_user *u; 00072 char tmp[256] = "\0"; 00073 char *p = NULL; 00074 char *filename = NULL; 00075 char *options = NULL; 00076 char *silstr = NULL; 00077 char *minstr = NULL; 00078 char *maxstr = NULL; 00079 struct ast_frame *fr = NULL; 00080 struct ast_frame *fr2 = NULL; 00081 int notsilent = 0; 00082 struct timeval start = { 0, 0 }, end = { 00083 0, 0}; 00084 int sildur = 1000; 00085 int mindur = 100; 00086 int maxdur = -1; 00087 int skipanswer = 0; 00088 int noextneeded = 0; 00089 int ignoredtmf = 0; 00090 int ignorefax = 0; 00091 int ignoretalk = 0; 00092 int x = 0; 00093 int origrformat = 0; 00094 int features = 0; 00095 struct ast_dsp *dsp = NULL; 00096 00097 pbx_builtin_setvar_helper(chan, "FAX_DETECTED", ""); 00098 pbx_builtin_setvar_helper(chan, "FAXEXTEN", ""); 00099 pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", ""); 00100 pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ""); 00101 00102 if (!data || ast_strlen_zero((char *) data)) { 00103 ast_log(LOG_WARNING, "NVBackgroundDetect requires an argument (filename)\n"); 00104 return -1; 00105 } 00106 00107 strncpy(tmp, (char *) data, sizeof(tmp) - 1); 00108 p = tmp; 00109 00110 filename = strsep(&p, "|"); 00111 options = strsep(&p, "|"); 00112 silstr = strsep(&p, "|"); 00113 minstr = strsep(&p, "|"); 00114 maxstr = strsep(&p, "|"); 00115 00116 if (options) { 00117 if (strchr(options, 'n')) 00118 skipanswer = 1; 00119 if (strchr(options, 'x')) 00120 noextneeded = 1; 00121 if (strchr(options, 'd')) 00122 ignoredtmf = 1; 00123 if (strchr(options, 'f')) 00124 ignorefax = 1; 00125 if (strchr(options, 't')) 00126 ignoretalk = 1; 00127 } 00128 00129 if (silstr) { 00130 if ((sscanf(silstr, "%d", &x) == 1) && (x > 0)) 00131 sildur = x; 00132 } 00133 00134 if (minstr) { 00135 if ((sscanf(minstr, "%d", &x) == 1) && (x > 0)) 00136 mindur = x; 00137 } 00138 00139 if (maxstr) { 00140 if ((sscanf(maxstr, "%d", &x) == 1) && (x > 0)) 00141 maxdur = x; 00142 } 00143 00144 ast_log(LOG_DEBUG, "Preparing detect of '%s' (sildur=%dms, mindur=%dms, maxdur=%dms)\n", tmp, sildur, mindur, maxdur); 00145 00146 u = ast_module_user_add(chan); 00147 if (chan->_state != AST_STATE_UP && !skipanswer) { 00148 /* Otherwise answer unless we're supposed to send this while on-hook */ 00149 res = ast_answer(chan); 00150 } 00151 if (!res) { 00152 origrformat = chan->readformat; 00153 if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR))) 00154 ast_log(LOG_WARNING, "Unable to set read format to linear!\n"); 00155 } 00156 if (!(dsp = ast_dsp_new())) { 00157 ast_log(LOG_WARNING, "Unable to allocate DSP!\n"); 00158 res = -1; 00159 } 00160 00161 if (dsp) { 00162 /* 00163 if (!ignoretalk) 00164 features |= DSP_FEATURE_SILENCE_SUPPRESS; 00165 */ 00166 if (!ignorefax) 00167 features |= DSP_FEATURE_FAX_DETECT; 00168 //if (!ignoredtmf) 00169 features |= DSP_FEATURE_DTMF_DETECT; 00170 00171 ast_dsp_set_threshold(dsp, 256); 00172 ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF); 00173 ast_dsp_digitmode(dsp, DSP_DIGITMODE_DTMF); 00174 } 00175 00176 if (!res) { 00177 ast_stopstream(chan); 00178 res = ast_streamfile(chan, tmp, chan->language); 00179 if (!res) { 00180 while (chan->stream) { 00181 res = ast_sched_wait(chan->sched); 00182 if ((res < 0) && !chan->timingfunc) { 00183 res = 0; 00184 break; 00185 } 00186 if (res < 0) 00187 res = 1000; 00188 res = ast_waitfor(chan, res); 00189 if (res < 0) { 00190 ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name); 00191 break; 00192 } else if (res > 0) { 00193 fr = ast_read(chan); 00194 if (!fr) { 00195 ast_log(LOG_DEBUG, "Got hangup\n"); 00196 res = -1; 00197 break; 00198 } 00199 00200 fr2 = ast_dsp_process(chan, dsp, fr); 00201 if (!fr2) { 00202 ast_log(LOG_WARNING, "Bad DSP received (what happened?)\n"); 00203 fr2 = fr; 00204 } 00205 00206 if (fr2->frametype == AST_FRAME_DTMF) { 00207 if (fr2->subclass == 'f' && !ignorefax) { 00208 /* Fax tone -- Handle and return NULL */ 00209 ast_log(LOG_DEBUG, "Fax detected on %s\n", chan->name); 00210 if (strcmp(chan->exten, "fax")) { 00211 ast_log(LOG_NOTICE, "Redirecting %s to fax extension\n", chan->name); 00212 pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1"); 00213 pbx_builtin_setvar_helper(chan, "FAXEXTEN", chan->exten); 00214 if (ast_exists_extension(chan, chan->context, "fax", 1, chan->CALLERID_FIELD)) { 00215 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ 00216 strncpy(chan->exten, "fax", sizeof(chan->exten) - 1); 00217 chan->priority = 0; 00218 } else 00219 ast_log(LOG_WARNING, "Fax detected, but no fax extension\n"); 00220 } else 00221 ast_log(LOG_WARNING, "Already in a fax extension, not redirecting\n"); 00222 00223 res = 0; 00224 ast_frfree(fr); 00225 break; 00226 } else if (!ignoredtmf) { 00227 ast_log(LOG_DEBUG, "DTMF detected on %s\n", chan->name); 00228 char t[2]; 00229 t[0] = fr2->subclass; 00230 t[1] = '\0'; 00231 if (noextneeded || ast_canmatch_extension(chan, chan->context, t, 1, chan->CALLERID_FIELD)) { 00232 pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "1"); 00233 /* They entered a valid extension, or might be anyhow */ 00234 if (noextneeded) { 00235 ast_log(LOG_NOTICE, "DTMF received (not matching to exten)\n"); 00236 res = 0; 00237 } else { 00238 ast_log(LOG_NOTICE, "DTMF received (matching to exten)\n"); 00239 res = fr2->subclass; 00240 } 00241 ast_frfree(fr); 00242 break; 00243 } else 00244 ast_log(LOG_DEBUG, "Valid extension requested and DTMF did not match\n"); 00245 } 00246 } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR) && !ignoretalk) { 00247 int totalsilence; 00248 int ms; 00249 res = ast_dsp_silence(dsp, fr, &totalsilence); 00250 if (res && (totalsilence > sildur)) { 00251 /* We've been quiet a little while */ 00252 if (notsilent) { 00253 /* We had heard some talking */ 00254 gettimeofday(&end, NULL); 00255 ms = (end.tv_sec - start.tv_sec) * 1000; 00256 ms += (end.tv_usec - start.tv_usec) / 1000; 00257 ms -= sildur; 00258 if (ms < 0) 00259 ms = 0; 00260 if ((ms > mindur) && ((maxdur < 0) || (ms < maxdur))) { 00261 char ms_str[10]; 00262 ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms); 00263 ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", chan->name); 00264 00265 /* Save detected talk time (in milliseconds) */ 00266 sprintf(ms_str, "%d", ms); 00267 pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str); 00268 00269 if (ast_exists_extension(chan, chan->context, "talk", 1, chan->CALLERID_FIELD)) { 00270 strncpy(chan->exten, "talk", sizeof(chan->exten) - 1); 00271 chan->priority = 0; 00272 } else 00273 ast_log(LOG_WARNING, "Talk detected, but no talk extension\n"); 00274 res = 0; 00275 ast_frfree(fr); 00276 break; 00277 } else 00278 ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms); 00279 notsilent = 0; 00280 } 00281 } else { 00282 if (!notsilent) { 00283 /* Heard some audio, mark the begining of the token */ 00284 gettimeofday(&start, NULL); 00285 ast_log(LOG_DEBUG, "Start of voice token!\n"); 00286 notsilent = 1; 00287 } 00288 } 00289 } 00290 ast_frfree(fr); 00291 } 00292 ast_sched_runq(chan->sched); 00293 } 00294 ast_stopstream(chan); 00295 } else { 00296 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *) data); 00297 res = 0; 00298 } 00299 } else 00300 ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); 00301 00302 if (res > -1) { 00303 if (origrformat && ast_set_read_format(chan, origrformat)) { 00304 ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", chan->name, ast_getformatname(origrformat)); 00305 } 00306 } 00307 00308 if (dsp) 00309 ast_dsp_free(dsp); 00310 00311 ast_module_user_remove(u); 00312 00313 return res; 00314 }
static int unload_module | ( | void | ) | [static] |
Definition at line 316 of file app_nv_backgrounddetect.c.
References app, and ast_unregister_application().
00317 { 00318 return ast_unregister_application(app); 00319 }
char* app = "NVBackgroundDetect" [static] |
Definition at line 41 of file app_nv_backgrounddetect.c.
char* descrip [static] |
Definition at line 45 of file app_nv_backgrounddetect.c.
Definition at line 43 of file app_nv_backgrounddetect.c.