Thu Jul 9 13:40:22 2009

Asterisk developer's documentation


app_waitforsilence.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  * WaitForSilence Application by David C. Troy <dave@popvox.com>
00007  * Version 1.11 2006-06-29
00008  *
00009  * Mark Spencer <markster@digium.com>
00010  *
00011  * See http://www.asterisk.org for more information about
00012  * the Asterisk project. Please do not directly contact
00013  * any of the maintainers of this project for assistance;
00014  * the project provides a web site, mailing lists and IRC
00015  * channels for your use.
00016  *
00017  * This program is free software, distributed under the terms of
00018  * the GNU General Public License Version 2. See the LICENSE file
00019  * at the top of the source tree.
00020  */
00021 
00022 /*! \file
00023  *
00024  * \brief Wait for Silence
00025  *   - Waits for up to 'x' milliseconds of silence, 'y' times \n
00026  *   - WaitForSilence(500,2) will wait for 1/2 second of silence, twice \n
00027  *   - WaitForSilence(1000,1) will wait for 1 second of silence, once \n
00028  *   - WaitForSilence(300,3,10) will wait for 300ms of silence, 3 times, and return after 10sec \n
00029  *
00030  * \author David C. Troy <dave@popvox.com>
00031  *
00032  * \ingroup applications
00033  */
00034 
00035 #include "asterisk.h"
00036 
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 174946 $")
00038 
00039 #include "asterisk/file.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/dsp.h"
00043 #include "asterisk/module.h"
00044 
00045 static char *app = "WaitForSilence";
00046 static char *synopsis = "Waits for a specified amount of silence";
00047 static char *descrip =
00048 "  WaitForSilence(silencerequired[,iterations][,timeout]):\n"
00049 "Wait for Silence: Waits for up to 'silencerequired' \n"
00050 "milliseconds of silence, 'iterations' times or once if omitted.\n"
00051 "An optional timeout specified the number of seconds to return\n"
00052 "after, even if we do not receive the specified amount of silence.\n"
00053 "Use 'timeout' with caution, as it may defeat the purpose of this\n"
00054 "application, which is to wait indefinitely until silence is detected\n"
00055 "on the line.  This is particularly useful for reverse-911-type\n"
00056 "call broadcast applications where you need to wait for an answering\n"
00057 "machine to complete its spiel before playing a message.\n"
00058 "The timeout parameter is specified only to avoid an infinite loop in\n"
00059 "cases where silence is never achieved.  Typically you will want to\n"
00060 "include two or more calls to WaitForSilence when dealing with an answering\n"
00061 "machine; first waiting for the spiel to finish, then waiting for the beep, etc.\n\n"
00062   "Examples:\n"
00063 "  - WaitForSilence(500,2) will wait for 1/2 second of silence, twice\n"
00064 "  - WaitForSilence(1000) will wait for 1 second of silence, once\n"
00065 "  - WaitForSilence(300,3,10) will wait for 300ms silence, 3 times,\n"
00066 "     and returns after 10 sec, even if silence is not detected\n\n"
00067 "Sets the channel variable WAITSTATUS with to one of these values:\n"
00068 "SILENCE - if exited with silence detected\n"
00069 "TIMEOUT - if exited without silence detected after timeout\n";
00070 
00071 static int do_waiting(struct ast_channel *chan, int silencereqd, time_t waitstart, int timeout) {
00072    struct ast_frame *f = NULL;
00073    int dspsilence = 0;
00074    static int silencethreshold = 128;
00075    int rfmt = 0;
00076    int res = 0;
00077    struct ast_dsp *sildet;  /* silence detector dsp */
00078    time_t now;
00079 
00080    rfmt = chan->readformat; /* Set to linear mode */
00081    if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)) < 0) {
00082       ast_log(LOG_WARNING, "Unable to set channel to linear mode, giving up\n");
00083       return -1;
00084    }
00085 
00086    /* Create the silence detector */
00087    if (!(sildet = ast_dsp_new())) {
00088       ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00089       return -1;
00090    }
00091    ast_dsp_set_threshold(sildet, silencethreshold);
00092 
00093    /* Await silence... */
00094    for (;;) {
00095       /* Start with no silence received */
00096       dspsilence = 0;
00097 
00098       res = ast_waitfor(chan, silencereqd);
00099 
00100       /* Must have gotten a hangup; let's exit */
00101       if (res < 0) {
00102          pbx_builtin_setvar_helper(chan, "WAITSTATUS", "HANGUP");
00103          break;
00104       }
00105       
00106       /* We waited and got no frame; sounds like digital silence or a muted digital channel */
00107       if (res == 0) {
00108          dspsilence = silencereqd;
00109       } else {
00110          /* Looks like we did get a frame, so let's check it out */
00111          if (!(f = ast_read(chan))) {
00112             pbx_builtin_setvar_helper(chan, "WAITSTATUS", "HANGUP");
00113             break;
00114          }
00115          if (f->frametype == AST_FRAME_VOICE) {
00116             ast_dsp_silence(sildet, f, &dspsilence);
00117          }
00118          ast_frfree(f);
00119       }
00120 
00121       ast_verb(6, "Got %dms silence< %dms required\n", dspsilence, silencereqd);
00122 
00123       if (dspsilence >= silencereqd) {
00124          ast_verb(3, "Exiting with %dms silence >= %dms required\n", dspsilence, silencereqd);
00125          /* Ended happily with silence */
00126          res = 1;
00127          pbx_builtin_setvar_helper(chan, "WAITSTATUS", "SILENCE");
00128          ast_debug(1, "WAITSTATUS was set to SILENCE\n");
00129          break;
00130       }
00131 
00132       if ( timeout && (difftime(time(&now),waitstart) >= timeout) ) {
00133          pbx_builtin_setvar_helper(chan, "WAITSTATUS", "TIMEOUT");
00134          ast_debug(1, "WAITSTATUS was set to TIMEOUT\n");
00135          res = 0;
00136          break;
00137       }
00138    }
00139 
00140 
00141    if (rfmt && ast_set_read_format(chan, rfmt)) {
00142       ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00143    }
00144    ast_dsp_free(sildet);
00145    return res;
00146 }
00147 
00148 static int waitforsilence_exec(struct ast_channel *chan, void *data)
00149 {
00150    int res = 1;
00151    int silencereqd = 1000;
00152    int timeout = 0;
00153    int iterations = 1, i;
00154    time_t waitstart;
00155 
00156    if (chan->_state != AST_STATE_UP) {
00157       res = ast_answer(chan); /* Answer the channel */
00158    }
00159 
00160    if (!data || ( (sscanf(data, "%d,%d,%d", &silencereqd, &iterations, &timeout) != 3) &&
00161       (sscanf(data, "%d|%d", &silencereqd, &iterations) != 2) &&
00162       (sscanf(data, "%d", &silencereqd) != 1) ) ) {
00163       ast_log(LOG_WARNING, "Using default value of 1000ms, 1 iteration, no timeout\n");
00164    }
00165 
00166    ast_verb(3, "Waiting %d time(s) for %d ms silence with %d timeout\n", iterations, silencereqd, timeout);
00167 
00168    time(&waitstart);
00169    res = 1;
00170    for (i=0; (i<iterations) && (res == 1); i++) {
00171       res = do_waiting(chan, silencereqd, waitstart, timeout);
00172    }
00173    if (res > 0)
00174       res = 0;
00175    return res;
00176 }
00177 
00178 
00179 static int unload_module(void)
00180 {
00181    return ast_unregister_application(app);
00182 }
00183 
00184 static int load_module(void)
00185 {
00186    return ast_register_application(app, waitforsilence_exec, synopsis, descrip);
00187 }
00188 
00189 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Wait For Silence");
00190 

Generated on Thu Jul 9 13:40:22 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7