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: http://svn.digium.com/svn/asterisk/trunk@95167 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
02ba367421
commit
a0cbc07523
2
CHANGES
2
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
|
||||
---------------------
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Reference in New Issue