Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:49 2009

## 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: 211526 $")
    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, "%30d", &x) == 1) && (x > 0))
    00101          sil = x;
    00102       options = strsep(&stringp, "|");
    00103       if (options) {
    00104          if ((sscanf(options, "%30d", &x) == 1) && (x > 0))
    00105             min = x;
    00106          options = strsep(&stringp, "|");
    00107          if (options) {
    00108             if ((sscanf(options, "%30d", &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 }