Fri Aug 24 02:22:47 2007

Asterisk developer's documentation


app_nv_backgrounddetect.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/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 Documentation

#define CALLERID_FIELD   cid.cid_num

Definition at line 66 of file app_nv_backgrounddetect.c.


Function Documentation

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.

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 }


Variable Documentation

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.

char* synopsis = "Background a file with talk and fax detect (IAX and SIP too)" [static]

Definition at line 43 of file app_nv_backgrounddetect.c.


Generated on Fri Aug 24 02:22:47 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1