/* * CallWeaver -- An open source telephony toolkit. * * Copyright (C) 1999 - 2005, Digium, Inc. * * WaitForSilence Application by David C. Troy * Version 1.00 2004-01-29 * * Mark Spencer * * See http://www.callweaver.org for more information about * the CallWeaver project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2. See the LICENSE file * at the top of the source tree. */ /*! \file * * \brief Wait for Silence * - Waits for up to 'x' milliseconds of silence, 'y' times * - WaitForSilence(500,2) will wait for 1/2 second of silence, twice * - WaitForSilence(1000,1) will wait for 1 second of silence, once * */ #ifdef HAVE_CONFIG_H #include "confdefs.h" #endif #include #include #include #include #include #include #include "callweaver.h" CALLWEAVER_FILE_VERSION("$HeadURL$", "$Revision$") #include "callweaver/file.h" #include "callweaver/logger.h" #include "callweaver/channel.h" #include "callweaver/pbx.h" #include "callweaver/dsp.h" #include "callweaver/module.h" #include "callweaver/options.h" static char *tdesc = "Wait For Silence"; static void *waitforsilence_app; static const char *waitforsilence_name = "WaitForSilence"; static const char *waitforsilence_synopsis = "Waits for a specified amount of silence"; static const char *waitforsilence_syntax = "WaitForSilence(silencerequired[,iterations][,timeout][,threshold])"; static const char *waitforsilence_descrip = "Wait for Silence: Waits for up to 'silencerequired' \n" "milliseconds of silence, 'iterations' times or 1 if omitted, for TIME OUT of 'timeout. \n" "Threshold can be tweak by changing 'threshold'\n" "Set the channel variable WAITSTATUS with to one of these values:" "SILENCE - if silence of x ms was detected" "TIMEOUT - if silence of x ms was not detected." "Examples:\n" " - WaitForSilence(500, 2) will wait for 1/2 second of silence, twice\n" " - WaitForSilence(1000) will wait for 1 second of silence, once\n"; STANDARD_LOCAL_USER; LOCAL_USER_DECL; static int do_waiting(struct cw_channel *chan, int waitsilence, int maxsilence, int silencethreshold) { struct cw_frame *f; int totalsilence = 0; int dspsilence = 0; int gotsilence = 0; int rfmt = 0; int res = 0; struct cw_dsp *sildet; /* silence detector dsp */ time_t start, now; time(&start); rfmt = chan->readformat; /* Set to linear mode */ res = cw_set_read_format(chan, CW_FORMAT_SLINEAR); if (res < 0) { cw_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); return -1; } sildet = cw_dsp_new(); /* Create the silence detector */ if (!sildet) { cw_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } cw_dsp_set_threshold(sildet, silencethreshold); /* Await silence... */ f = NULL; for(;;) { res = cw_waitfor(chan, 2000); if (!res) { cw_log(LOG_WARNING, "One waitfor failed, trying another\n"); /* Try one more time in case of masq */ res = cw_waitfor(chan, 2000); if (!res) { cw_log(LOG_WARNING, "No audio available on %s??\n", chan->name); res = -1; } } if (res < 0) { f = NULL; break; } f = cw_read(chan); if (!f) break; if (f->frametype == CW_FRAME_VOICE) { dspsilence = 0; cw_dsp_silence(sildet, f, &dspsilence); if (dspsilence) { totalsilence = dspsilence; time(&start); } else { totalsilence = 0; } if (totalsilence >= waitsilence) { if (option_verbose > 2) cw_verbose(VERBOSE_PREFIX_3 "Exiting with %dms silence > %dms required\n", totalsilence, waitsilence); /* Ended happily with silence */ gotsilence = 1; pbx_builtin_setvar_helper(chan, "WAITSTATUS", "SILENCE"); cw_log(LOG_DEBUG, "WAITSTATUS was set to SILENCE\n"); cw_fr_free(f); break; } else if ( difftime(time(&now),start) >= maxsilence ) { pbx_builtin_setvar_helper(chan, "WAITSTATUS", "TIMEOUT"); cw_log(LOG_DEBUG, "WAITSTATUS was set to TIMEOUT\n"); cw_fr_free(f); break; } } cw_fr_free(f); } if (rfmt && cw_set_read_format(chan, rfmt)) { cw_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", cw_getformatname(rfmt), chan->name); } cw_dsp_free(sildet); return gotsilence; } static int waitforsilence_exec(struct cw_channel *chan, int argc, char **argv) { int res = 1; struct localuser *u; int maxsilence; int iterations = 1, i; int waitsilence; int silencethreshold = 64; if (argc < 0 || argc > 4 || (argc > 0 && !isdigit(argv[0][0])) || (argc == 2 && !isdigit(argv[1][0])) || (argc == 3 && !isdigit(argv[2][0])) || (argc == 4 && !isdigit(argv[3][0]))) { cw_log(LOG_ERROR, "Syntax: %s\n", waitforsilence_syntax); return -1; } waitsilence = (argc > 0 ? atoi(argv[0]) : 1000); iterations = (argc > 1 ? atoi(argv[1]) : 1); maxsilence = (argc > 2 ? atoi(argv[2]) : (waitsilence * 2) / 1000); silencethreshold = (argc > 3 ? atoi(argv[3]) : 64); LOCAL_USER_ADD(u); res = cw_answer(chan); /* Answer the channel */ if (option_verbose > 2) cw_verbose(VERBOSE_PREFIX_3 "Waiting %d time(s) for %d ms silence with threshold of %d\n", iterations, waitsilence, silencethreshold); res = 1; for (i=0; (i 0) res = 0; return res; } int unload_module(void) { int res = 0; STANDARD_HANGUP_LOCALUSERS; res |= cw_unregister_application(waitforsilence_app); return res; } int load_module(void) { waitforsilence_app = cw_register_application(waitforsilence_name, waitforsilence_exec, waitforsilence_synopsis, waitforsilence_syntax, waitforsilence_descrip); return 0; } char *description(void) { return tdesc; } int usecount(void) { int res; STANDARD_USECOUNT(res); return res; }