Mon May 14 04:43:51 2007

Asterisk developer's documentation


app_nv_faxdetect.c File Reference

#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 Documentation

#define CALLERID_FIELD   cid.cid_num

Definition at line 64 of file app_nv_faxdetect.c.


Function Documentation

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.

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 }


Variable Documentation

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.

char* synopsis = "Detects fax sounds on all channel types (IAX and SIP too)" [static]

Definition at line 41 of file app_nv_faxdetect.c.


Generated on Mon May 14 04:43:51 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1