Index: apps/app_meetme.c =================================================================== --- apps/app_meetme.c (revision 89245) +++ apps/app_meetme.c (working copy) @@ -1516,6 +1516,9 @@ long time_left_ms = 0; struct timeval nexteventts = { 0, }; int to; + int silencethreshold; + + silencethreshold = ast_dsp_get_threshold_from_settings(); if (!(user = ast_calloc(1, sizeof(*user)))) return ret; @@ -1709,7 +1712,7 @@ "%s/meetme/meetme-username-%s-%d", ast_config_AST_SPOOL_DIR, conf->confno, user->user_no); if (confflags & CONFFLAG_INTROUSERNOREVIEW) - res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, 128, 0, NULL); + res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, silencethreshold, 0, NULL); else res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL); if (res == -1) Index: apps/app_minivm.c =================================================================== --- apps/app_minivm.c (revision 89245) +++ apps/app_minivm.c (working copy) @@ -2291,6 +2291,8 @@ { int error = 0; + global_silencethreshold = ast_dsp_get_threshold_from_settings(); + while (var) { /* Mail command */ if (!strcmp(var->name, "mailcmd")) { Index: apps/app_voicemail.c =================================================================== --- apps/app_voicemail.c (revision 89245) +++ apps/app_voicemail.c (working copy) @@ -8156,7 +8156,7 @@ } /* Silence treshold */ - silencethreshold = 256; + silencethreshold = ast_dsp_get_threshold_from_settings(); if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold"))) silencethreshold = atoi(val); Index: apps/app_dial.c =================================================================== --- apps/app_dial.c (revision 89245) +++ apps/app_dial.c (working copy) @@ -1093,6 +1093,7 @@ char callerid[60]; int res; char *l; + int silencethreshold; if (!ast_strlen_zero(chan->cid.cid_num)) { l = ast_strdupa(chan->cid.cid_num); @@ -1169,8 +1170,9 @@ "At the tone, please say your name:" */ + silencethreshold = ast_dsp_get_threshold_from_settings(); ast_answer(chan); - res = ast_play_and_record(chan, "priv-recordintro", pa->privintro, 4, "gsm", &duration, 128, 2000, 0); /* NOTE: I've reduced the total time to 4 sec */ + res = ast_play_and_record(chan, "priv-recordintro", pa->privintro, 4, "gsm", &duration, silencethreshold, 2000, 0); /* NOTE: I've reduced the total time to 4 sec */ /* don't think we'll need a lock removed, we took care of conflicts by naming the pa.privintro file */ if (res == -1) { Index: apps/app_waitforsilence.c =================================================================== --- apps/app_waitforsilence.c (revision 89245) +++ apps/app_waitforsilence.c (working copy) @@ -29,6 +29,11 @@ * * \author David C. Troy * + * \brief Wait For Noise + * The same as Wait For Silence but listenes noise on the chennel that is above the threshold specified\n + * + * \author Philipp Skadorov + * * \ingroup applications */ @@ -49,10 +54,10 @@ #include "asterisk/module.h" #include "asterisk/options.h" -static char *app = "WaitForSilence"; -static char *synopsis = "Waits for a specified amount of silence"; -static char *descrip = -" WaitForSilence(silencerequired[,iterations][,timeout]):\n" +static char *app_silence = "WaitForSilence"; +static char *synopsis_silence = "Waits for a specified amount of silence"; +static char *descrip_silence = +" WaitForSilence(silencerequired[|iterations][|timeout]) \n" "Wait for Silence: Waits for up to 'silencerequired' \n" "milliseconds of silence, 'iterations' times or once if omitted.\n" "An optional timeout specified the number of seconds to return\n" @@ -67,23 +72,35 @@ "include two or more calls to WaitForSilence when dealing with an answering\n" "machine; first waiting for the spiel to finish, then waiting for the beep, etc.\n\n" "Examples:\n" -" - WaitForSilence(500,2) will wait for 1/2 second of silence, twice\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" -" - WaitForSilence(300,3,10) will wait for 300ms silence, 3 times,\n" +" - WaitForSilence(300|3|10) will wait for 300ms silence, 3 times,\n" " and returns after 10 sec, even if silence is not detected\n\n" "Sets the channel variable WAITSTATUS with to one of these values:\n" "SILENCE - if exited with silence detected\n" "TIMEOUT - if exited without silence detected after timeout\n"; -static int do_waiting(struct ast_channel *chan, int silencereqd, time_t waitstart, int timeout) { +static char *app_noise = "WaitForNoise"; +static char *synopsis_noise = "Waits for a specified amount of noise"; +static char *descrip_noise = +"WaitForNoise(noiserequired[|iterations][|timeout]) \n" +"Wait for Noise: The same as Wait for Silance but waits for noise that is above\n"; + +static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart, int timeout, int wait_for_silence) { struct ast_frame *f; - int dspsilence = 0; - static int silencethreshold = 128; + int dsptime = 0; int rfmt = 0; int res = 0; struct ast_dsp *sildet; /* silence detector dsp */ time_t now; + const char * format_string = ""; + int silencethreshold = ast_dsp_get_threshold_from_settings(); + + /*Either silence or noise calc depending on wait_for_silence flag*/ + int (*ast_dsp_func)(struct ast_dsp*, struct ast_frame*, int*) = + wait_for_silence ? ast_dsp_silence : ast_dsp_noise; + rfmt = chan->readformat; /* Set to linear mode */ res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { @@ -102,9 +119,9 @@ f = NULL; for(;;) { /* Start with no silence received */ - dspsilence = 0; + dsptime = 0; - res = ast_waitfor(chan, silencereqd); + res = ast_waitfor(chan, timereqd); /* Must have gotten a hangup; let's exit */ if (res <= 0) { @@ -114,32 +131,46 @@ /* We waited and got no frame; sounds like digital silence or a muted digital channel */ if (!res) { - dspsilence = silencereqd; + dsptime = timereqd; } else { /* Looks like we did get a frame, so let's check it out */ f = ast_read(chan); if (!f) break; if (f && f->frametype == AST_FRAME_VOICE) { - ast_dsp_silence(sildet, f, &dspsilence); + ast_dsp_func(sildet, f, &dsptime); ast_frfree(f); } } - ast_verb(3, "Got %dms silence< %dms required\n", dspsilence, silencereqd); + if (option_verbose > 6) { + format_string = wait_for_silence? + VERBOSE_PREFIX_3 "Got %dms silence silence < %dms required\n": + VERBOSE_PREFIX_3 "Got %dms silence noise < %dms required\n"; - if (dspsilence >= silencereqd) { - ast_verb(3, "Exiting with %dms silence >= %dms required\n", dspsilence, silencereqd); + ast_verbose(format_string, dsptime, timereqd); + } + if (dsptime >= timereqd) { + if (option_verbose > 2) + format_string = wait_for_silence? + VERBOSE_PREFIX_3 "Exiting with %dms silence >= %dms required\n" : + VERBOSE_PREFIX_3 "Exiting with %dms silence >= %dms required\n"; + ast_verbose(format_string, dsptime, timereqd); /* Ended happily with silence */ res = 1; - pbx_builtin_setvar_helper(chan, "WAITSTATUS", "SILENCE"); - ast_debug(1, "WAITSTATUS was set to SILENCE\n"); + pbx_builtin_setvar_helper(chan, "WAITSTATUS", wait_for_silence ? "SILENCE" : "NOISE"); + if(wait_for_silence) { + ast_log(LOG_DEBUG, "WAITSTATUS was set to SILENCE\n"); + } + else { + ast_log(LOG_DEBUG, "WAITSTATUS was set to NOISE\n"); + } break; } if ( timeout && (difftime(time(&now),waitstart) >= timeout) ) { pbx_builtin_setvar_helper(chan, "WAITSTATUS", "TIMEOUT"); - ast_debug(1, "WAITSTATUS was set to TIMEOUT\n"); + ast_log(LOG_DEBUG, "WAITSTATUS was set to TIMEOUT\n"); res = 0; break; } @@ -153,43 +184,63 @@ return res; } -static int waitforsilence_exec(struct ast_channel *chan, void *data) +/*Waits either for silence or for noise depending on wait_for_silence flag*/ +static int waitfor_exec(struct ast_channel *chan, void *data, int wait_for_silence) { int res = 1; - int silencereqd = 1000; + int timereqd = 1000; int timeout = 0; int iterations = 1, i; time_t waitstart; res = ast_answer(chan); /* Answer the channel */ - if (!data || ( (sscanf(data, "%d,%d,%d", &silencereqd, &iterations, &timeout) != 3) && - (sscanf(data, "%d|%d", &silencereqd, &iterations) != 2) && - (sscanf(data, "%d", &silencereqd) != 1) ) ) { + if (!data || ( (sscanf(data, "%d|%d|%d", &timereqd, &iterations, &timeout) != 3) && + (sscanf(data, "%d|%d", &timereqd, &iterations) != 2) && + (sscanf(data, "%d", &timereqd) != 1) ) ) { ast_log(LOG_WARNING, "Using default value of 1000ms, 1 iteration, no timeout\n"); } - ast_verb(3, "Waiting %d time(s) for %d ms silence with %d timeout\n", iterations, silencereqd, timeout); + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Waiting %d time(s) for %d ms silence with %d timeout\n", iterations, timereqd, timeout); time(&waitstart); res = 1; for (i=0; (i 0) res = 0; return res; } +static int waitforsilence_exec(struct ast_channel *chan, void *data) +{ + return waitfor_exec(chan, data, 1); +} +static int waitfornoise_exec(struct ast_channel *chan, void *data) +{ + return waitfor_exec(chan, data, 0); +} + static int unload_module(void) { - return ast_unregister_application(app); + int res; + + res = ast_unregister_application(app_silence); + res |= ast_unregister_application(app_noise); + + ast_module_user_hangup_all(); + + return res; } static int load_module(void) { - return ast_register_application(app, waitforsilence_exec, synopsis, descrip); + int res = ast_register_application(app_silence, waitforsilence_exec, synopsis_silence, descrip_silence); + res |= ast_register_application(app_noise, waitfornoise_exec, synopsis_noise, descrip_noise); + return res; } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Wait For Silence"); Index: apps/app_amd.c =================================================================== --- apps/app_amd.c (revision 89245) +++ apps/app_amd.c (working copy) @@ -49,7 +49,7 @@ static char *descrip = " AMD([initialSilence],[greeting],[afterGreetingSilence],[totalAnalysisTime]\n" " ,[minimumWordLength],[betweenWordsSilence],[maximumNumberOfWords]\n" -" ,[silenceThreshold])\n" +" ,[silencethreshold])\n" " This application attempts to detect answering machines at the beginning\n" " of outbound calls. Simply call this application after the call\n" " has been answered (outbound only, of course).\n" @@ -68,7 +68,7 @@ " consider the audio that follows as a new word.\n" "- 'maximumNumberOfWords'is the maximum number of words in the greeting. \n" " If exceeded then MACHINE.\n" -"- 'silenceThreshold' is the silence threshold.\n" +"- 'silencethreshold' is the silence threshold.\n" "This application sets the following channel variables upon completion:\n" " AMDSTATUS - This is the status of the answering machine detection.\n" " Possible values are:\n" @@ -93,7 +93,6 @@ static int dfltBetweenWordsSilence = 50; static int dfltMaximumNumberOfWords = 3; static int dfltSilenceThreshold = 256; - static void isAnsweringMachine(struct ast_channel *chan, void *data) { int res = 0; @@ -123,7 +122,7 @@ int minimumWordLength = dfltMinimumWordLength; int betweenWordsSilence = dfltBetweenWordsSilence; int maximumNumberOfWords = dfltMaximumNumberOfWords; - int silenceThreshold = dfltSilenceThreshold; + int silencethreshold; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(argInitialSilence); @@ -138,6 +137,7 @@ ast_verb(3, "AMD: %s %s %s (Fmt: %d)\n", chan->name ,chan->cid.cid_ani, chan->cid.cid_rdnis, chan->readformat); + silencethreshold = ast_dsp_get_threshold_from_settings(); /* Lets parse the arguments. */ if (!ast_strlen_zero(parse)) { /* Some arguments have been passed. Lets parse them and overwrite the defaults. */ @@ -157,16 +157,16 @@ if (!ast_strlen_zero(args.argMaximumNumberOfWords)) maximumNumberOfWords = atoi(args.argMaximumNumberOfWords); if (!ast_strlen_zero(args.argSilenceThreshold)) - silenceThreshold = atoi(args.argSilenceThreshold); + silencethreshold = atoi(args.argSilenceThreshold); } else { ast_debug(1, "AMD using the default parameters.\n"); } /* Now we're ready to roll! */ ast_verb(3, "AMD: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] " - "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] \n", + "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silencethreshold [%d] \n", initialSilence, greeting, afterGreetingSilence, totalAnalysisTime, - minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold ); + minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silencethreshold ); /* Set read format to signed linear so we get signed linear frames in */ readFormat = chan->readformat; @@ -186,7 +186,7 @@ } /* Set silence threshold to specified value */ - ast_dsp_set_threshold(silenceDetector, silenceThreshold); + ast_dsp_set_threshold(silenceDetector, silencethreshold); /* Now we go into a loop waiting for frames from the channel */ while ((res = ast_waitfor(chan, totalAnalysisTime)) > -1) { @@ -365,7 +365,7 @@ ast_config_destroy(cfg); ast_verb(3, "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] " - "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] \n", + "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silencethreshold [%d] \n", dfltInitialSilence, dfltGreeting, dfltAfterGreetingSilence, dfltTotalAnalysisTime, dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold ); Index: apps/app_record.c =================================================================== --- apps/app_record.c (revision 89245) +++ apps/app_record.c (working copy) @@ -116,6 +116,7 @@ int rfmt = 0; int ioflags; int waitres; + int silencethreshold; struct ast_silence_generator *silgen = NULL; struct ast_flags flags = { 0, }; AST_DECLARE_APP_ARGS(args, @@ -252,7 +253,8 @@ ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } - ast_dsp_set_threshold(sildet, 256); + silencethreshold = ast_dsp_get_threshold_from_settings(); + ast_dsp_set_threshold(sildet, silencethreshold); } /* Create the directory if it does not exist. */ Index: apps/app_followme.c =================================================================== --- apps/app_followme.c (revision 89245) +++ apps/app_followme.c (working copy) @@ -887,9 +887,13 @@ char *argstr; char namerecloc[255]; int duration = 0; + int silencethreshold; struct ast_channel *caller; struct ast_channel *outbound; static char toast[80]; + + + silencethreshold = ast_dsp_get_threshold_from_settings(); AST_DECLARE_APP_ARGS(args, AST_APP_ARG(followmeid); @@ -959,7 +963,7 @@ duration = 5; if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) - if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, 128, 0, NULL) < 0) + if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, silencethreshold, 0, NULL) < 0) goto outrun; if (!ast_fileexists(namerecloc, NULL, chan->language)) Index: include/asterisk/dsp.h =================================================================== --- include/asterisk/dsp.h (revision 89245) +++ include/asterisk/dsp.h (working copy) @@ -80,6 +80,10 @@ number of seconds of silence */ int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence); +/*! \brief Return non-zero if this is noise. Updates "totalnoise" with the total + number of seconds of noise */ +int ast_dsp_noise(struct ast_dsp *dsp, struct ast_frame *f, int *totalnoise); + /*! \brief Return non-zero if historically this should be a busy, request that ast_dsp_silence has already been called */ int ast_dsp_busydetect(struct ast_dsp *dsp); @@ -108,4 +112,7 @@ /*! \brief Get tcount (Threshold counter) */ int ast_dsp_get_tcount(struct ast_dsp *dsp); +/*! \brief Get silence threshold from dsp.conf*/ +int ast_dsp_get_threshold_from_settings(void); + #endif /* _ASTERISK_DSP_H */ Index: main/app.c =================================================================== --- main/app.c (revision 89245) +++ main/app.c (working copy) @@ -1262,7 +1262,7 @@ int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path) { - int silencethreshold = 128; + int silencethreshold; int maxsilence = 0; int res = 0; int cmd = 0; @@ -1280,6 +1280,8 @@ cmd = '3'; /* Want to start by recording */ + silencethreshold = ast_dsp_get_threshold_from_settings(); + while ((cmd >= 0) && (cmd != 't')) { switch (cmd) { case '1': Index: main/dsp.c =================================================================== --- main/dsp.c (revision 89245) +++ main/dsp.c (working copy) @@ -60,6 +60,7 @@ #include "asterisk/alaw.h" #include "asterisk/utils.h" #include "asterisk/options.h" +#include "asterisk/config.h" /*! Number of goertzels for progress detect */ enum gsamp_size { @@ -181,6 +182,9 @@ #define BELL_MF_RELATIVE_PEAK 12.6 /* 11dB */ #endif +/*config file for dsp settings*/ +#define CONFIG_FILE_NAME "dsp.conf" + #if !defined(BUSYDETECT_MARTIN) && !defined(BUSYDETECT) && !defined(BUSYDETECT_TONEONLY) && !defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE) #define BUSYDETECT_MARTIN #endif @@ -1197,7 +1201,7 @@ return __ast_dsp_call_progress(dsp, inf->data, inf->datalen / 2); } -static int __ast_dsp_silence(struct ast_dsp *dsp, short *s, int len, int *totalsilence) +static int __ast_dsp_silence_noise(struct ast_dsp *dsp, short *s, int len, int *totalsilence, int *totalnoise) { int accum; int x; @@ -1249,6 +1253,9 @@ } if (totalsilence) *totalsilence = dsp->totalsilence; + if (totalnoise) + *totalnoise = dsp->totalnoise; + return res; } @@ -1405,9 +1412,28 @@ } s = f->data; len = f->datalen/2; - return __ast_dsp_silence(dsp, s, len, totalsilence); + return __ast_dsp_silence_noise(dsp, s, len, totalsilence, NULL); } +int ast_dsp_noise(struct ast_dsp *dsp, struct ast_frame *f, int *totalnoise) +{ + short *s; + int len; + + if (f->frametype != AST_FRAME_VOICE) { + ast_log(LOG_WARNING, "Can't calculate noise on a non-voice frame\n"); + return 0; + } + if (f->subclass != AST_FORMAT_SLINEAR) { + ast_log(LOG_WARNING, "Can only calculate noise on signed-linear frames :(\n"); + return 0; + } + s = f->data; + len = f->datalen/2; + return __ast_dsp_silence_noise(dsp, s, len, NULL, totalnoise); +} + + struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, struct ast_frame *af) { int silence; @@ -1765,3 +1791,34 @@ { return dsp->tcount; } + +int ast_dsp_get_threshold_from_settings() +{ + static int threshold = -1; + const int default_threshold = 256; + + struct ast_flags config_flags = { 0 }; + struct ast_config *cfg; + struct ast_variable *var; + + if(-1 == threshold) { + threshold = default_threshold; + cfg = ast_config_load(CONFIG_FILE_NAME, config_flags); + if (!cfg) { + ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME); + } + else { + for (var = ast_variable_browse(cfg, "default"); var; var = var->next) { + if (!strcasecmp(var->name, "silencethreshold")){ + if(sscanf(var->value, "%d", &threshold) != 1) { + ast_log(LOG_WARNING, "Error processing file %s :(\n", CONFIG_FILE_NAME); + threshold = default_threshold; + } + break; + } + } + } + } + return threshold; +} + Index: res/res_agi.c =================================================================== --- res/res_agi.c (revision 89245) +++ res/res_agi.c (working copy) @@ -892,7 +892,9 @@ char *silencestr=NULL; int rfmt=0; + int silencethreshold; + /* XXX EAGI FIXME XXX */ if (argc < 6) @@ -932,7 +934,8 @@ ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } - ast_dsp_set_threshold(sildet, 256); + silencethreshold = ast_dsp_get_threshold_from_settings(); + ast_dsp_set_threshold(sildet, silencethreshold); } /* backward compatibility, if no offset given, arg[6] would have been