From 198829f2db3d8dcaa76188dc4fe6db06e7b8cbb8 Mon Sep 17 00:00:00 2001 From: tilghman Date: Wed, 5 Mar 2008 16:23:44 +0000 Subject: [PATCH] Create a centralized configuration option for silencethreshold (closes issue #11236) Reported by: philipps Patches: 20080218__bug11236.diff.txt uploaded by Corydon76 (license 14) Tested by: philipps git-svn-id: http://svn.digium.com/svn/asterisk/trunk@106072 f38db490-d61c-443f-a65b-d21fe96a405b --- CHANGES | 4 +- UPGRADE.txt | 3 + apps/app_amd.c | 2 + apps/app_dial.c | 5 +- apps/app_followme.c | 136 ++++++++++++++++++-------------------- apps/app_meetme.c | 2 +- apps/app_minivm.c | 5 +- apps/app_record.c | 2 +- apps/app_voicemail.c | 2 +- apps/app_waitforsilence.c | 90 +++++++++++++++++-------- configs/dsp.conf.sample | 7 ++ include/asterisk/dsp.h | 19 ++++++ main/app.c | 4 +- main/asterisk.c | 3 +- main/dsp.c | 71 +++++++++++++++++++- main/loader.c | 2 + res/res_agi.c | 2 +- 17 files changed, 248 insertions(+), 111 deletions(-) create mode 100644 configs/dsp.conf.sample diff --git a/CHANGES b/CHANGES index cf3011379..5616708f1 100644 --- a/CHANGES +++ b/CHANGES @@ -175,7 +175,7 @@ Skinny changes * Proper codec support in chan_skinny. * Added settings for IP and Ethernet QoS requests - +MGCP changes ------------ * Added separate settings for media QoS in mgcp.conf @@ -387,6 +387,8 @@ Other Dialplan Application Changes * The ChannelRedirect application no longer exits the dialplan if the given channel does not exist. It will now set the CHANNELREDIRECT_STATUS variable to SUCCESS upon success or NOCHANNEL if the given channel was not found. + * The silencethreshold setting that was previously configurable in multiple + applications is now settable globally via dsp.conf. Music On Hold Changes --------------------- diff --git a/UPGRADE.txt b/UPGRADE.txt index c860f4b00..6fb214227 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -56,6 +56,9 @@ Core: * The concise versions of various CLI commands are now deprecated. We recommend using the manager interface (AMI) for application integration with Asterisk. +* The silencethreshold used for various applications is now settable via a + centralized config option in dsp.conf. + Voicemail: * The voicemail configuration values 'maxmessage' and 'minmessage' have diff --git a/apps/app_amd.c b/apps/app_amd.c index cb867ba35..131cd01fd 100644 --- a/apps/app_amd.c +++ b/apps/app_amd.c @@ -371,6 +371,8 @@ static int load_config(int reload) struct ast_variable *var = NULL; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; + dfltSilenceThreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE); + if (!(cfg = ast_config_load("amd.conf", config_flags))) { ast_log(LOG_ERROR, "Configuration file amd.conf missing.\n"); return -1; diff --git a/apps/app_dial.c b/apps/app_dial.c index f93ba0de9..5698c1945 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -60,6 +60,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/privacy.h" #include "asterisk/stringfields.h" #include "asterisk/global_datastores.h" +#include "asterisk/dsp.h" static char *app = "Dial"; @@ -1115,6 +1116,7 @@ static int setup_privacy_args(struct privacy_args *pa, char callerid[60]; int res; char *l; + int silencethreshold; if (!ast_strlen_zero(chan->cid.cid_num)) { l = ast_strdupa(chan->cid.cid_num); @@ -1188,8 +1190,9 @@ static int setup_privacy_args(struct privacy_args *pa, "At the tone, please say your name:" */ + silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE); 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) { diff --git a/apps/app_followme.c b/apps/app_followme.c index c3c0d88a4..9dd130b9d 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -55,6 +55,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/causes.h" #include "asterisk/astdb.h" +#include "asterisk/dsp.h" #include "asterisk/app.h" static char *app = "FollowMe"; @@ -130,7 +131,7 @@ struct findme_user { int ynidx; long digts; int cleared; - AST_LIST_ENTRY(findme_user) entry; + AST_LIST_ENTRY(findme_user) entry; }; enum { @@ -183,7 +184,6 @@ static void free_numbers(struct call_followme *f) /* Free the whitelisted number */ ast_free(prev); AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers); - } @@ -258,7 +258,6 @@ static struct number *create_followme_number(char *number, int timeout, int numo { struct number *cur; char *tmp; - if (!(cur = ast_calloc(1, sizeof(*cur)))) return NULL; @@ -284,7 +283,7 @@ static int reload_followme(int reload) char numberstr[90]; int timeout; char *timeoutstr; - int numorder; + int numorder; const char *takecallstr; const char *declinecallstr; const char *tmpstr; @@ -307,7 +306,7 @@ static int reload_followme(int reload) } featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout"); - + if (!ast_strlen_zero(featuredigittostr)) { if (!sscanf(featuredigittostr, "%d", &featuredigittimeout)) featuredigittimeout = 5000; @@ -316,7 +315,7 @@ static int reload_followme(int reload) takecallstr = ast_variable_retrieve(cfg, "general", "takecall"); if (!ast_strlen_zero(takecallstr)) ast_copy_string(takecall, takecallstr, sizeof(takecall)); - + declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall"); if (!ast_strlen_zero(declinecallstr)) ast_copy_string(nextindp, declinecallstr, sizeof(nextindp)); @@ -369,7 +368,7 @@ static int reload_followme(int reload) /* Totally fail if we fail to find/create an entry */ if (!f) continue; - + if (!new) ast_mutex_lock(&f->lock); /* Re-initialize the profile */ @@ -399,8 +398,8 @@ static int reload_followme(int reload) timeout = 25; numorder = 0; } - - if (!numorder) { + + if (!numorder) { idx = 1; AST_LIST_TRAVERSE(&f->numbers, nm, entry) idx++; @@ -414,7 +413,7 @@ static int reload_followme(int reload) } var = var->next; } /* End while(var) loop */ - + if (!new) ast_mutex_unlock(&f->lock); else @@ -431,7 +430,7 @@ static int reload_followme(int reload) static void clear_caller(struct findme_user *tmpuser) { struct ast_channel *outbound; - + if (tmpuser && tmpuser->ochan && tmpuser->state >= 0) { outbound = tmpuser->ochan; if (!outbound->cdr) { @@ -460,12 +459,11 @@ static void clear_caller(struct findme_user *tmpuser) static void clear_calling_tree(struct findme_user_listptr *findme_user_list) { struct findme_user *tmpuser; - + AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { clear_caller(tmpuser); tmpuser->cleared = 1; } - } @@ -489,29 +487,29 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us /* ------------ wait_for_winner_channel start --------------- */ callfromname = ast_strdupa(tpargs->callfromprompt); - pressbuttonname = ast_strdupa(tpargs->optionsprompt); + pressbuttonname = ast_strdupa(tpargs->optionsprompt); if (AST_LIST_EMPTY(findme_user_list)) { ast_verb(3, "couldn't reach at this number.\n"); return NULL; } - + if (!caller) { ast_verb(3, "Original caller hungup. Cleanup.\n"); clear_calling_tree(findme_user_list); return NULL; } - + totalwait = nm->timeout * 1000; - + while (!ctstatus) { to = 1000; pos = 1; livechannels = 0; watchers[0] = caller; - - dg = 0; - winner = NULL; + + dg = 0; + winner = NULL; AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { if (tmpuser->state >= 0 && tmpuser->ochan) { if (tmpuser->state == 3) @@ -526,7 +524,7 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us } else { ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); return NULL; - } + } } else { tmpuser->state = 2; tmpuser->digts = 0; @@ -566,7 +564,6 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us tmpuser->ynidx = 0; if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) { tmpuser->state = 3; - } else { return NULL; } @@ -580,7 +577,7 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us livechannels++; } } - + tmpto = to; if (to < 0) { to = 1000; @@ -590,7 +587,7 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us winner = ast_waitfor_n(watchers, pos, &to); tmpto -= to; totalwait -= tmpto; - wtd = to; + wtd = to; if (totalwait <= 0) { ast_verb(3, "We've hit our timeout for this step. Drop everyone and move on to the next one. %ld\n", totalwait); clear_calling_tree(findme_user_list); @@ -631,8 +628,8 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); ast_frfree(f); return NULL; - } - } else { + } + } else { tmpuser->state = 2; if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language)) ast_sched_runq(tmpuser->ochan->sched); @@ -693,18 +690,18 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us if (!strcmp(tmpuser->yn, tpargs->takecall)) { ast_debug(1, "Match to take the call!\n"); ast_frfree(f); - return tmpuser->ochan; + return tmpuser->ochan; } if (!strcmp(tmpuser->yn, tpargs->nextindp)) { ast_debug(1, "Next in dial plan step requested.\n"); *status = 1; ast_frfree(f); return NULL; - } - + } + } } - + ast_frfree(f); } else { if (winner) { @@ -723,12 +720,12 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us } } } - } - + } + } else ast_debug(1, "timed out waiting for action\n"); } - + /* --- WAIT FOR WINNER NUMBER END! -----------*/ return NULL; } @@ -748,7 +745,7 @@ static void findmeexec(struct fm_args *tpargs) struct findme_user_listptr *findme_user_list; int status; - findme_user_list = ast_calloc(1, sizeof(*findme_user_list)); + findme_user_list = ast_calloc(1, sizeof(*findme_user_list)); AST_LIST_HEAD_INIT_NOLOCK(findme_user_list); /* We're going to figure out what the longest possible string of digits to collect is */ @@ -782,14 +779,14 @@ static void findmeexec(struct fm_args *tpargs) sprintf(dialarg, "%s", number); else sprintf(dialarg, "%s@%s", number, tpargs->context); - + tmpuser = ast_calloc(1, sizeof(*tmpuser)); if (!tmpuser) { ast_log(LOG_WARNING, "Out of memory!\n"); ast_free(findme_user_list); return; } - + outbound = ast_request("Local", ast_best_codec(caller->nativeformats), dialarg, &dg); if (outbound) { ast_set_callerid(outbound, caller->cid.cid_num, caller->cid.cid_name, caller->cid.cid_num); @@ -824,19 +821,17 @@ static void findmeexec(struct fm_args *tpargs) outbound = NULL; } } - } } else ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg)); - + number = rest; } while (number); - - status = 0; + + status = 0; if (!AST_LIST_EMPTY(findme_user_list)) winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs); - - + while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) { if (!fmuser->cleared && fmuser->ochan != winner) clear_caller(fmuser); @@ -845,21 +840,21 @@ static void findmeexec(struct fm_args *tpargs) fmuser = NULL; tmpuser = NULL; - headuser = NULL; + headuser = NULL; if (winner) break; if (!caller) { tpargs->status = 1; ast_free(findme_user_list); - return; + return; } idx++; - AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) + AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) { if (nm->order == idx) break; - + } } ast_free(findme_user_list); if (!winner) @@ -869,9 +864,7 @@ static void findmeexec(struct fm_args *tpargs) tpargs->outbound = winner; } - return; - } static int app_exec(struct ast_channel *chan, void *data) @@ -887,7 +880,6 @@ static int app_exec(struct ast_channel *chan, void *data) struct ast_channel *caller; struct ast_channel *outbound; static char toast[80]; - AST_DECLARE_APP_ARGS(args, AST_APP_ARG(followmeid); AST_APP_ARG(options); @@ -897,7 +889,7 @@ static int app_exec(struct ast_channel *chan, void *data) ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app); return -1; } - + if (!(argstr = ast_strdupa((char *)data))) { ast_log(LOG_ERROR, "Out of memory!\n"); return -1; @@ -916,7 +908,7 @@ static int app_exec(struct ast_channel *chan, void *data) break; } AST_RWLIST_UNLOCK(&followmes); - + ast_debug(1, "New profile %s.\n", args.followmeid); if (!f) { @@ -927,7 +919,7 @@ static int app_exec(struct ast_channel *chan, void *data) /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */ if (args.options) ast_app_parse_options(followme_opts, &targs.followmeflags, NULL, args.options); - + /* Lock the profile lock and copy out everything we need to run with before unlocking it again */ ast_mutex_lock(&f->lock); targs.mohclass = ast_strdupa(f->moh); @@ -948,38 +940,38 @@ static int app_exec(struct ast_channel *chan, void *data) AST_LIST_INSERT_TAIL(&targs.cnumbers, newnm, entry); } ast_mutex_unlock(&f->lock); - + if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_STATUSMSG)) ast_stream_and_wait(chan, targs.statusprompt, ""); - + snprintf(namerecloc,sizeof(namerecloc),"%s/followme.%s",ast_config_AST_SPOOL_DIR,chan->uniqueid); 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, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) goto outrun; - + if (!ast_fileexists(namerecloc, NULL, chan->language)) - ast_copy_string(namerecloc, "", sizeof(namerecloc)); - + ast_copy_string(namerecloc, "", sizeof(namerecloc)); + if (ast_streamfile(chan, targs.plsholdprompt, chan->language)) goto outrun; if (ast_waitstream(chan, "") < 0) goto outrun; ast_moh_start(chan, S_OR(targs.mohclass, NULL), NULL); - + targs.status = 0; targs.chan = chan; ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc)); - - findmeexec(&targs); - + + findmeexec(&targs); + while ((nm = AST_LIST_REMOVE_HEAD(&targs.cnumbers, entry))) ast_free(nm); - + if (!ast_strlen_zero(namerecloc)) - unlink(namerecloc); - + unlink(namerecloc); + if (targs.status != 100) { ast_moh_stop(chan); if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) @@ -989,12 +981,12 @@ static int app_exec(struct ast_channel *chan, void *data) caller = chan; outbound = targs.outbound; /* Bridge the two channels. */ - - memset(&config,0,sizeof(struct ast_bridge_config)); + + memset(&config, 0, sizeof(config)); ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); - + ast_moh_stop(caller); /* Be sure no generators are left on it */ ast_deactivate_generator(caller); @@ -1006,7 +998,7 @@ static int app_exec(struct ast_channel *chan, void *data) goto outrun; } time(&answer_time); - res = ast_bridge_call(caller,outbound,&config); + res = ast_bridge_call(caller, outbound, &config); time(&end_time); snprintf(toast, sizeof(toast), "%ld", (long)(end_time - start_time)); pbx_builtin_setvar_helper(caller, "DIALEDTIME", toast); @@ -1017,7 +1009,7 @@ static int app_exec(struct ast_channel *chan, void *data) } outrun: - + return res; } @@ -1051,7 +1043,7 @@ static int reload(void) { reload_followme(1); - return 0; + return 0; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Find-Me/Follow-Me Application", diff --git a/apps/app_meetme.c b/apps/app_meetme.c index 41c995009..471477a55 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -1699,7 +1699,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c "%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, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL); else res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL); if (res == -1) diff --git a/apps/app_minivm.c b/apps/app_minivm.c index ae76f9e89..f11537ed0 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -2360,7 +2360,6 @@ static int load_config(int reload) /* First, set some default settings */ global_externnotify[0] = '\0'; global_logfile[0] = '\0'; - global_silencethreshold = 256; global_vmmaxmessage = 2000; global_maxgreet = 2000; global_vmminmessage = 0; @@ -2375,6 +2374,8 @@ static int load_config(int reload) memset(&global_stats, 0, sizeof(global_stats)); global_stats.reset = ast_tvnow(); + global_silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE); + /* Make sure we could load configuration file */ if (!cfg) { ast_log(LOG_WARNING, "Failed to load configuration file. Module activated with default settings.\n"); @@ -2640,7 +2641,7 @@ static char *handle_minivm_show_settings(struct ast_cli_entry *e, int cmd, struc ast_cli(a->fd, "\n"); ast_cli(a->fd, " Mail command (shell): %s\n", global_mailcmd); ast_cli(a->fd, " Max silence: %d\n", global_maxsilence); - ast_cli(a->fd, " Silence treshold: %d\n", global_silencethreshold); + ast_cli(a->fd, " Silence threshold: %d\n", global_silencethreshold); ast_cli(a->fd, " Max message length (secs): %d\n", global_vmmaxmessage); ast_cli(a->fd, " Min message length (secs): %d\n", global_vmminmessage); ast_cli(a->fd, " Default format: %s\n", default_vmformat); diff --git a/apps/app_record.c b/apps/app_record.c index 7214e1f07..b062011a9 100644 --- a/apps/app_record.c +++ b/apps/app_record.c @@ -243,7 +243,7 @@ static int record_exec(struct ast_channel *chan, void *data) ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } - ast_dsp_set_threshold(sildet, 256); + ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE)); } /* Create the directory if it does not exist. */ diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 92e3859af..e250c1fe3 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -8399,7 +8399,7 @@ static int load_config(int reload) } /* Silence treshold */ - silencethreshold = 256; + silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE); if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold"))) silencethreshold = atoi(val); diff --git a/apps/app_waitforsilence.c b/apps/app_waitforsilence.c index e45f24344..c0fc47acf 100644 --- a/apps/app_waitforsilence.c +++ b/apps/app_waitforsilence.c @@ -29,6 +29,12 @@ * * \author David C. Troy * + * \brief Wait For Noise + * The same as Wait For Silence but listenes noise on the chennel that is above \n + * the pre-configured silence threshold from dsp.conf + * + * \author Philipp Skadorov + * * \ingroup applications */ @@ -42,9 +48,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/dsp.h" #include "asterisk/module.h" -static char *app = "WaitForSilence"; -static char *synopsis = "Waits for a specified amount of silence"; -static char *descrip = +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" @@ -68,15 +74,24 @@ static char *descrip = "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 the threshold specified\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; + /*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) { @@ -89,15 +104,15 @@ static int do_waiting(struct ast_channel *chan, int silencereqd, time_t waitstar ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } - ast_dsp_set_threshold(sildet, silencethreshold); + ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE)); /* Await silence... */ 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) { @@ -107,30 +122,36 @@ static int do_waiting(struct ast_channel *chan, int silencereqd, time_t waitstar /* 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 (wait_for_silence) + ast_verb(6, "Got %dms silence < %dms required\n", dsptime, timereqd); + else + ast_verb(6, "Got %dms noise < %dms required\n", dsptime, timereqd); - if (dspsilence >= silencereqd) { - ast_verb(3, "Exiting with %dms silence >= %dms required\n", dspsilence, silencereqd); + if (dsptime >= timereqd) { + if (wait_for_silence) + ast_verb(3, "Exiting with %dms silence >= %dms required\n", dsptime, timereqd); + else + ast_verb(3, "Exiting with %dms noise >= %dms required\n", 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"); + ast_debug(1, "WAITSTATUS was set to %s\n", wait_for_silence ? "SILENCE" : "NOISE"); break; } - if ( timeout && (difftime(time(&now),waitstart) >= timeout) ) { + if (timeout && (difftime(time(&now), waitstart) >= timeout)) { pbx_builtin_setvar_helper(chan, "WAITSTATUS", "TIMEOUT"); ast_debug(1, "WAITSTATUS was set to TIMEOUT\n"); res = 0; @@ -146,43 +167,60 @@ static int do_waiting(struct ast_channel *chan, int silencereqd, time_t waitstar return res; } -static int waitforsilence_exec(struct ast_channel *chan, void *data) +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); + ast_verb(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); + + return res; } static int load_module(void) { - return ast_register_application(app, waitforsilence_exec, synopsis, descrip); + int res; + + 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"); diff --git a/configs/dsp.conf.sample b/configs/dsp.conf.sample new file mode 100644 index 000000000..788b78cdb --- /dev/null +++ b/configs/dsp.conf.sample @@ -0,0 +1,7 @@ +[default] +; +; Length of sound (in milliseconds) before a period of silence is considered +; to be a change from talking to silence or a period of noise converts silence +; to talking. [default=256] +; +;silencethreshold=256 diff --git a/include/asterisk/dsp.h b/include/asterisk/dsp.h index 10ed53d1b..1235c3ae0 100644 --- a/include/asterisk/dsp.h +++ b/include/asterisk/dsp.h @@ -58,6 +58,13 @@ struct ast_dsp; +enum threshold { + /* Array offsets */ + THRESHOLD_SILENCE = 0, + /* Always the last */ + THRESHOLD_MAX = 1, +}; + struct ast_dsp *ast_dsp_new(void); void ast_dsp_free(struct ast_dsp *dsp); @@ -84,6 +91,10 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, 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); @@ -115,4 +126,12 @@ int ast_dsp_get_tstate(struct ast_dsp *dsp); /*! \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(enum threshold which); + +/* \brief Reloads dsp settings from dsp.conf*/ +int ast_dsp_reload(void); + +int ast_dsp_init(void); + #endif /* _ASTERISK_DSP_H */ diff --git a/main/app.c b/main/app.c index 5c3f8a444..7a2227fb9 100644 --- a/main/app.c +++ b/main/app.c @@ -1268,7 +1268,7 @@ int ast_unlock_path(const char *path) 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; @@ -1286,6 +1286,8 @@ int ast_record_review(struct ast_channel *chan, const char *playfile, const char cmd = '3'; /* Want to start by recording */ + silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE); + while ((cmd >= 0) && (cmd != 't')) { switch (cmd) { case '1': diff --git a/main/asterisk.c b/main/asterisk.c index 287b6ccd0..21aee3b6e 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -121,6 +121,7 @@ int daemon(int, int); /* defined in libresolv of all places */ #include "asterisk/linkedlists.h" #include "asterisk/devicestate.h" #include "asterisk/module.h" +#include "asterisk/dsp.h" #include "asterisk/doxyref.h" /* Doxygen documentation */ @@ -3218,7 +3219,7 @@ int main(int argc, char *argv[]) } ast_rtp_init(); - + ast_dsp_init(); ast_udptl_init(); if (ast_image_init()) { diff --git a/main/dsp.c b/main/dsp.c index 6945464d4..a9a787459 100644 --- a/main/dsp.c +++ b/main/dsp.c @@ -53,6 +53,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #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 { @@ -193,6 +194,8 @@ enum gsamp_thresh { #define SAMPLES_IN_FRAME 160 +#define CONFIG_FILE_NAME "dsp.conf" + typedef struct { int v2; int v3; @@ -272,6 +275,8 @@ static char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; static char bell_mf_positions[] = "1247C-358A--69*---0B----#"; +static int thresholds[THRESHOLD_MAX]; + static inline void goertzel_sample(goertzel_state_t *s, short sample) { int v1; @@ -1021,7 +1026,7 @@ int ast_dsp_call_progress(struct ast_dsp *dsp, struct ast_frame *inf) 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; @@ -1073,6 +1078,8 @@ static int __ast_dsp_silence(struct ast_dsp *dsp, short *s, int len, int *totals } if (totalsilence) *totalsilence = dsp->totalsilence; + if (totalnoise) + *totalnoise = dsp->totalnoise; return res; } @@ -1179,9 +1186,28 @@ int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence) } 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; @@ -1236,7 +1262,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(af->subclass)); return af; } - silence = __ast_dsp_silence(dsp, shortdata, len, NULL); + res = __ast_dsp_silence_noise(dsp, shortdata, len, &silence, NULL); if ((dsp->features & DSP_FEATURE_SILENCE_SUPPRESS) && silence) { memset(&dsp->f, 0, sizeof(dsp->f)); dsp->f.frametype = AST_FRAME_NULL; @@ -1516,3 +1542,42 @@ int ast_dsp_get_tcount(struct ast_dsp *dsp) { return dsp->tcount; } + +static int _dsp_init(int reload) +{ + struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; + struct ast_config *cfg; + struct ast_variable *var; + + cfg = ast_config_load(CONFIG_FILE_NAME, config_flags); + + if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED) { + const char *value; + + value = ast_variable_retrieve(cfg, "default", "silencethreshold"); + if (value && sscanf(value, "%d", &thresholds[THRESHOLD_SILENCE]) != 1) { + ast_log(LOG_WARNING, "%s: '%s' is not a valid silencethreshold value\n", CONFIG_FILE_NAME, var->value); + thresholds[THRESHOLD_SILENCE] = 256; + } else if (!value) + thresholds[THRESHOLD_SILENCE] = 256; + + ast_config_destroy(cfg); + } + return 0; +} + +int ast_dsp_get_threshold_from_settings(enum threshold which) +{ + return thresholds[which]; +} + +int ast_dsp_init(void) +{ + return _dsp_init(0); +} + +int ast_dsp_reload(void) +{ + return _dsp_init(1); +} + diff --git a/main/loader.c b/main/loader.c index 43d254c6f..d34da9f7d 100644 --- a/main/loader.c +++ b/main/loader.c @@ -47,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/http.h" #include "asterisk/lock.h" #include "asterisk/features.h" +#include "asterisk/dsp.h" #ifdef DLFCNCOMPAT #include "asterisk/dlfcn-compat.h" @@ -249,6 +250,7 @@ static struct reload_classes { { "http", ast_http_reload }, { "logger", logger_reload }, { "features", ast_features_reload }, + { "dsp", ast_dsp_reload}, { NULL, NULL } }; diff --git a/res/res_agi.c b/res/res_agi.c index 6e9b5291e..dcde56353 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -1296,7 +1296,7 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } - ast_dsp_set_threshold(sildet, 256); + ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE)); } /* backward compatibility, if no offset given, arg[6] would have been