Sat Sep 16 05:47:40 2006

Asterisk developer's documentation


app_talkdetect.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Playback a file with audio detect
00022  * 
00023  * \ingroup applications
00024  */
00025  
00026 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <string.h>
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
00033 
00034 #include "asterisk/lock.h"
00035 #include "asterisk/file.h"
00036 #include "asterisk/logger.h"
00037 #include "asterisk/channel.h"
00038 #include "asterisk/pbx.h"
00039 #include "asterisk/module.h"
00040 #include "asterisk/translate.h"
00041 #include "asterisk/utils.h"
00042 #include "asterisk/dsp.h"
00043 
00044 static char *tdesc = "Playback with Talk Detection";
00045 
00046 static char *app = "BackgroundDetect";
00047 
00048 static char *synopsis = "Background a file with talk detect";
00049 
00050 static char *descrip = 
00051 "  BackgroundDetect(filename[|sil[|min|[max]]]):  Plays  back  a  given\n"
00052 "filename, waiting for interruption from a given digit (the digit must\n"
00053 "start the beginning of a valid extension, or it will be ignored).\n"
00054 "During the playback of the file, audio is monitored in the receive\n"
00055 "direction, and if a period of non-silence which is greater than 'min' ms\n"
00056 "yet less than 'max' ms is followed by silence for at least 'sil' ms then\n"
00057 "the audio playback is aborted and processing jumps to the 'talk' extension\n"
00058 "if available.  If unspecified, sil, min, and max default to 1000, 100, and\n"
00059 "infinity respectively.\n";
00060 
00061 STANDARD_LOCAL_USER;
00062 
00063 LOCAL_USER_DECL;
00064 
00065 static int background_detect_exec(struct ast_channel *chan, void *data)
00066 {
00067    int res = 0;
00068    struct localuser *u;
00069    char *tmp;
00070    char *options;
00071    char *stringp;
00072    struct ast_frame *fr;
00073    int notsilent=0;
00074    struct timeval start = { 0, 0};
00075    int sil = 1000;
00076    int min = 100;
00077    int max = -1;
00078    int x;
00079    int origrformat=0;
00080    struct ast_dsp *dsp;
00081    
00082    if (ast_strlen_zero(data)) {
00083       ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n");
00084       return -1;
00085    }
00086 
00087    LOCAL_USER_ADD(u);
00088 
00089    tmp = ast_strdupa(data);
00090    if (!tmp) {
00091       ast_log(LOG_ERROR, "Out of memory\n");
00092       LOCAL_USER_REMOVE(u);
00093       return -1;
00094    }  
00095 
00096    stringp=tmp;
00097    strsep(&stringp, "|");
00098    options = strsep(&stringp, "|");
00099    if (options) {
00100       if ((sscanf(options, "%d", &x) == 1) && (x > 0))
00101          sil = x;
00102       options = strsep(&stringp, "|");
00103       if (options) {
00104          if ((sscanf(options, "%d", &x) == 1) && (x > 0))
00105             min = x;
00106          options = strsep(&stringp, "|");
00107          if (options) {
00108             if ((sscanf(options, "%d", &x) == 1) && (x > 0))
00109                max = x;
00110          }
00111       }
00112    }
00113    ast_log(LOG_DEBUG, "Preparing detect of '%s', sil=%d,min=%d,max=%d\n", 
00114                   tmp, sil, min, max);
00115    if (chan->_state != AST_STATE_UP) {
00116       /* Otherwise answer unless we're supposed to send this while on-hook */
00117       res = ast_answer(chan);
00118    }
00119    if (!res) {
00120       origrformat = chan->readformat;
00121       if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR))) 
00122          ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
00123    }
00124    if (!(dsp = ast_dsp_new())) {
00125       ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
00126       res = -1;
00127    }
00128    if (!res) {
00129       ast_stopstream(chan);
00130       res = ast_streamfile(chan, tmp, chan->language);
00131       if (!res) {
00132          while(chan->stream) {
00133             res = ast_sched_wait(chan->sched);
00134             if ((res < 0) && !chan->timingfunc) {
00135                res = 0;
00136                break;
00137             }
00138             if (res < 0)
00139                res = 1000;
00140             res = ast_waitfor(chan, res);
00141             if (res < 0) {
00142                ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
00143                break;
00144             } else if (res > 0) {
00145                fr = ast_read(chan);
00146                if (!fr) {
00147                   res = -1;
00148                   break;
00149                } else if (fr->frametype == AST_FRAME_DTMF) {
00150                   char t[2];
00151                   t[0] = fr->subclass;
00152                   t[1] = '\0';
00153                   if (ast_canmatch_extension(chan, chan->context, t, 1, chan->cid.cid_num)) {
00154                      /* They entered a valid  extension, or might be anyhow */
00155                      res = fr->subclass;
00156                      ast_frfree(fr);
00157                      break;
00158                   }
00159                } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR)) {
00160                   int totalsilence;
00161                   int ms;
00162                   res = ast_dsp_silence(dsp, fr, &totalsilence);
00163                   if (res && (totalsilence > sil)) {
00164                      /* We've been quiet a little while */
00165                      if (notsilent) {
00166                         /* We had heard some talking */
00167                         ms = ast_tvdiff_ms(ast_tvnow(), start);
00168                         ms -= sil;
00169                         if (ms < 0)
00170                            ms = 0;
00171                         if ((ms > min) && ((max < 0) || (ms < max))) {
00172                            char ms_str[10];
00173                            ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
00174 
00175                            /* Save detected talk time (in milliseconds) */ 
00176                            sprintf(ms_str, "%d", ms );   
00177                            pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
00178                            
00179                            ast_goto_if_exists(chan, chan->context, "talk", 1);
00180                            res = 0;
00181                            ast_frfree(fr);
00182                            break;
00183                         } else
00184                            ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
00185                         notsilent = 0;
00186                      }
00187                   } else {
00188                      if (!notsilent) {
00189                         /* Heard some audio, mark the begining of the token */
00190                         start = ast_tvnow();
00191                         ast_log(LOG_DEBUG, "Start of voice token!\n");
00192                         notsilent = 1;
00193                      }
00194                   }
00195                   
00196                }
00197                ast_frfree(fr);
00198             }
00199             ast_sched_runq(chan->sched);
00200          }
00201          ast_stopstream(chan);
00202       } else {
00203          ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
00204          res = 0;
00205       }
00206    }
00207    if (res > -1) {
00208       if (origrformat && ast_set_read_format(chan, origrformat)) {
00209          ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", 
00210             chan->name, ast_getformatname(origrformat));
00211       }
00212    }
00213    if (dsp)
00214       ast_dsp_free(dsp);
00215    LOCAL_USER_REMOVE(u);
00216    return res;
00217 }
00218 
00219 int unload_module(void)
00220 {
00221    int res;
00222 
00223    res = ast_unregister_application(app);
00224    
00225    STANDARD_HANGUP_LOCALUSERS;
00226 
00227    return res; 
00228 }
00229 
00230 int load_module(void)
00231 {
00232    return ast_register_application(app, background_detect_exec, synopsis, descrip);
00233 }
00234 
00235 char *description(void)
00236 {
00237    return tdesc;
00238 }
00239 
00240 int usecount(void)
00241 {
00242    int res;
00243    STANDARD_USECOUNT(res);
00244    return res;
00245 }
00246 
00247 char *key()
00248 {
00249    return ASTERISK_GPL_KEY;
00250 }

Generated on Sat Sep 16 05:47:40 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7