From d9e0bb0e8486c10ff92853e73abbe62f07dff157 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Fri, 28 Dec 2007 16:12:06 +0000 Subject: [PATCH] Some changes to app_amd. The channel name is printed in verbose messages maximumWordLength option added. Duration of words that do not meet the minimum word duration will be logged The duration of pre-greeting silence will be logged Only consider us in the greeting if we actually detected a valid word duration. (closes issue #11650, reported and patched by davevg) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@95167 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- CHANGES | 2 ++ apps/app_amd.c | 59 ++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/CHANGES b/CHANGES index f1a52fb1b0..c9851d001c 100644 --- a/CHANGES +++ b/CHANGES @@ -312,6 +312,8 @@ Other Dialplan Application Changes of asking for verification of each name, one at a time. * Privacy() no longer uses privacy.conf, as all options are specifyable as direct options to the app. + * AMD() has a new "maximum word length" option. "show application AMD" from the CLI + for more details Music On Hold Changes --------------------- diff --git a/apps/app_amd.c b/apps/app_amd.c index 556fceec6e..4e440d3887 100644 --- a/apps/app_amd.c +++ b/apps/app_amd.c @@ -45,7 +45,7 @@ static char *synopsis = "Attempts to detect answering machines"; static char *descrip = " AMD([initialSilence],[greeting],[afterGreetingSilence],[totalAnalysisTime]\n" " ,[minimumWordLength],[betweenWordsSilence],[maximumNumberOfWords]\n" -" ,[silenceThreshold])\n" +" ,[silenceThreshold],[|maximumWordLength])\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" @@ -65,6 +65,7 @@ static char *descrip = "- 'maximumNumberOfWords'is the maximum number of words in the greeting. \n" " If exceeded then MACHINE.\n" "- 'silenceThreshold' is the silence threshold.\n" +"- 'maximumWordLength' is the maximum duration of a word to accept. If exceeded then MACHINE\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" @@ -75,7 +76,8 @@ static char *descrip = " INITIALSILENCE-<%d silenceDuration>-<%d initialSilence>\n" " HUMAN-<%d silenceDuration>-<%d afterGreetingSilence>\n" " MAXWORDS-<%d wordsCount>-<%d maximumNumberOfWords>\n" -" LONGGREETING-<%d voiceDuration>-<%d greeting>\n"; +" LONGGREETING-<%d voiceDuration>-<%d greeting>\n" +" MAXWORDLENGTH-<%d consecutiveVoiceDuration>\n"; #define STATE_IN_WORD 1 #define STATE_IN_SILENCE 2 @@ -89,6 +91,7 @@ static int dfltMinimumWordLength = 100; static int dfltBetweenWordsSilence = 50; static int dfltMaximumNumberOfWords = 3; static int dfltSilenceThreshold = 256; +static int dfltMaximumWordLength = 5000; /* Setting this to a large default so it is not used unless specify it in the configs or command line */ static void isAnsweringMachine(struct ast_channel *chan, void *data) { @@ -120,6 +123,7 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data) int betweenWordsSilence = dfltBetweenWordsSilence; int maximumNumberOfWords = dfltMaximumNumberOfWords; int silenceThreshold = dfltSilenceThreshold; + int maximumWordLength = dfltMaximumWordLength; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(argInitialSilence); @@ -130,6 +134,7 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data) AST_APP_ARG(argBetweenWordsSilence); AST_APP_ARG(argMaximumNumberOfWords); AST_APP_ARG(argSilenceThreshold); + AST_APP_ARG(argMaximumWordLength); ); ast_verb(3, "AMD: %s %s %s (Fmt: %d)\n", chan->name ,chan->cid.cid_ani, chan->cid.cid_rdnis, chan->readformat); @@ -154,15 +159,17 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data) maximumNumberOfWords = atoi(args.argMaximumNumberOfWords); if (!ast_strlen_zero(args.argSilenceThreshold)) silenceThreshold = atoi(args.argSilenceThreshold); + if (!ast_strlen_zero(args.argMaximumWordLength)) + maximumWordLength = atoi(args.argMaximumWordLength); } 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] maximumWordLength [%d] \n", initialSilence, greeting, afterGreetingSilence, totalAnalysisTime, - minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold ); + minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold, maximumWordLength); /* Set read format to signed linear so we get signed linear frames in */ readFormat = chan->readformat; @@ -188,7 +195,7 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data) while ((res = ast_waitfor(chan, totalAnalysisTime)) > -1) { /* If we fail to read in a frame, that means they hung up */ if (!(f = ast_read(chan))) { - ast_verb(3, "AMD: HANGUP\n"); + ast_verb(3, "AMD: Channel [%s]. HANGUP\n", chan->name); ast_debug(1, "Got hangup\n"); strcpy(amdStatus, "HANGUP"); break; @@ -215,15 +222,19 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data) if (silenceDuration >= betweenWordsSilence) { if (currentState != STATE_IN_SILENCE ) { previousState = currentState; - ast_verb(3, "AMD: Changed state to STATE_IN_SILENCE\n"); + ast_verb(3, "AMD: Channel [%s]. Changed state to STATE_IN_SILENCE\n", chan->name); } + /* Find words less than word duration */ + if (consecutiveVoiceDuration < minimumWordLength && consecutiveVoiceDuration > 0){ + ast_verb(3, "AMD: Channel [%s]. Short Word Duration: %d\n", chan->name, consecutiveVoiceDuration); + } currentState = STATE_IN_SILENCE; consecutiveVoiceDuration = 0; } if (inInitialSilence == 1 && silenceDuration >= initialSilence) { - ast_verb(3, "AMD: ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n", - silenceDuration, initialSilence); + ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n", + chan->name, silenceDuration, initialSilence); ast_frfree(f); strcpy(amdStatus , "MACHINE"); sprintf(amdCause , "INITIALSILENCE-%d-%d", silenceDuration, initialSilence); @@ -231,8 +242,8 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data) } if (silenceDuration >= afterGreetingSilence && inGreeting == 1) { - ast_verb(3, "AMD: HUMAN: silenceDuration:%d afterGreetingSilence:%d\n", - silenceDuration, afterGreetingSilence); + ast_verb(3, "AMD: Channel [%s]. HUMAN: silenceDuration:%d afterGreetingSilence:%d\n", + chan->name, silenceDuration, afterGreetingSilence); ast_frfree(f); strcpy(amdStatus , "HUMAN"); sprintf(amdCause , "HUMAN-%d-%d", silenceDuration, afterGreetingSilence); @@ -247,13 +258,19 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data) number of words if my previous state was Silence, which means that I moved into a word. */ if (consecutiveVoiceDuration >= minimumWordLength && currentState == STATE_IN_SILENCE) { iWordsCount++; - ast_verb(3, "AMD: Word detected. iWordsCount:%d\n", iWordsCount); + ast_verb(3, "AMD: Channel [%s]. Word detected. iWordsCount:%d\n", chan->name, iWordsCount); previousState = currentState; currentState = STATE_IN_WORD; } - + if (consecutiveVoiceDuration >= maximumWordLength){ + ast_verb(3, "AMD: Channel [%s]. Maximum Word Length detected. [%d]\n", chan->name, consecutiveVoiceDuration); + ast_frfree(f); + strcpy(amdStatus , "MACHINE"); + sprintf(amdCause , "MAXWORDLENGTH-%d", consecutiveVoiceDuration); + break; + } if (iWordsCount >= maximumNumberOfWords) { - ast_verb(3, "AMD: ANSWERING MACHINE: iWordsCount:%d\n", iWordsCount); + ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: iWordsCount:%d\n", chan->name, iWordsCount); ast_frfree(f); strcpy(amdStatus , "MACHINE"); sprintf(amdCause , "MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords); @@ -261,7 +278,7 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data) } if (inGreeting == 1 && voiceDuration >= greeting) { - ast_verb(3, "AMD: ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", voiceDuration, greeting); + ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", chan->name, voiceDuration, greeting); ast_frfree(f); strcpy(amdStatus , "MACHINE"); sprintf(amdCause , "LONGGREETING-%d-%d", voiceDuration, greeting); @@ -269,7 +286,14 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data) } if (voiceDuration >= minimumWordLength ) { + if (silenceDuration > 0) + ast_verb(3, "AMD: Channel [%s]. Detected Talk, previous silence duration: %d\n", chan->name, silenceDuration); silenceDuration = 0; + } + if (consecutiveVoiceDuration >= minimumWordLength && inGreeting == 0){ + /* Only go in here once to change the greeting flag when we detect the 1st word */ + if (silenceDuration > 0) + ast_verb(3, "AMD: Channel [%s]. Before Greeting Time: silenceDuration: %d voiceDuration: %d\n", chan->name, silenceDuration, voiceDuration); inInitialSilence = 0; inGreeting = 1; } @@ -343,6 +367,9 @@ static int load_config(int reload) dfltBetweenWordsSilence = atoi(var->value); } else if (!strcasecmp(var->name, "maximum_number_of_words")) { dfltMaximumNumberOfWords = atoi(var->value); + } else if (!strcasecmp(var->name, "maximum_word_length")) { + dfltMaximumWordLength = atoi(var->value); + } else { ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n", app, cat, var->name, var->lineno); @@ -356,9 +383,9 @@ static int load_config(int reload) 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] maximumWordLength [%d]\n", dfltInitialSilence, dfltGreeting, dfltAfterGreetingSilence, dfltTotalAnalysisTime, - dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold ); + dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold, dfltMaximumWordLength); return 0; }