Some changes to app_amd.
authorMark Michelson <mmichelson@digium.com>
Fri, 28 Dec 2007 16:12:06 +0000 (16:12 +0000)
committerMark Michelson <mmichelson@digium.com>
Fri, 28 Dec 2007 16:12:06 +0000 (16:12 +0000)
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
apps/app_amd.c

diff --git a/CHANGES b/CHANGES
index f1a52fb..c9851d0 100644 (file)
--- 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
 ---------------------
index 556fcee..4e440d3 100644 (file)
@@ -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;
 }