More code optimizations. Thanks kpfleming!
[asterisk/asterisk.git] / apps / app_amd.c
index bcbacb5..8312958 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "asterisk.h"
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
 #include "asterisk/module.h"
 #include "asterisk/lock.h"
 #include "asterisk/options.h"
@@ -60,7 +64,7 @@ static char *descrip =
 "This application sets the following channel variable upon completion:\n"
 "    AMDSTATUS - This is the status of the answering machine detection.\n"
 "                Possible values are:\n"
-"                MACHINE | PERSON | NOTSURE | HANGUP\n"
+"                MACHINE | HUMAN | NOTSURE | HANGUP\n"
 "    AMDCAUSE - Indicates the cause that led to the conclusion.\n"
 "               Possible values are:\n"
 "               TOOLONG-<%d total_time>\n"
@@ -70,8 +74,6 @@ static char *descrip =
 "               LONGGREETING-<%d voiceDuration>-<%d greeting>\n";
 
 
-STANDARD_LOCAL_USER;
-
 LOCAL_USER_DECL;
 
 #define STATE_IN_WORD       1
@@ -89,7 +91,7 @@ static int dfltSilenceThreshold     = 256;
 
 static void isAnsweringMachine(struct ast_channel *chan, void *data)
 {
-       int res = 0;
+       int res = 0, ret = 0;
 
        struct ast_frame *f = NULL;
 
@@ -134,8 +136,8 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data)
                             AST_APP_ARG(argMaximumNumberOfWords);
                             AST_APP_ARG(argSilenceThreshold);
        );
-
-       ast_verbose(VERBOSE_PREFIX_3 "AMD: %s %s %s (Fmt: %d)\n", chan->name ,chan->cid.cid_ani, chan->cid.cid_rdnis, chan->readformat);
+       if (option_verbose > 2)
+               ast_verbose(VERBOSE_PREFIX_3 "AMD: %s %s %s (Fmt: %d)\n", chan->name ,chan->cid.cid_ani, chan->cid.cid_rdnis, chan->readformat);
 
        /* Lets parse the arguments. */
        if (ast_strlen_zero(data)) {
@@ -178,8 +180,9 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data)
        }
 
        /* Now we're ready to roll! */
-
-       ast_verbose(VERBOSE_PREFIX_3 "AMD: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
+       
+       if (option_verbose > 2)
+               ast_verbose(VERBOSE_PREFIX_3 "AMD: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
                "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] \n",
                                initialSilence, greeting, afterGreetingSilence, totalAnalysisTime,
                                minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold );
@@ -202,42 +205,45 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data)
        }
        ast_dsp_set_threshold(silenceDetector, silenceThreshold );
 
-       while (ast_waitfor(chan, -1) > -1)
+       while ((ret = ast_waitfor(chan, totalAnalysisTime)))
        {
-               f = ast_read(chan);
-               if (!f ) {
-                       /* No Frame: Called Party Must Have Dropped */
-                       ast_verbose(VERBOSE_PREFIX_3 "AMD: HANGUP\n");
-                       ast_log(LOG_DEBUG, "Got hangup\n");
+               if (ret < 0 || !(f = ast_read(chan))) {
+                       /* No Frame OR Error on ast_waitfor : Called Party Must Have Dropped */
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "AMD: HANGUP\n");
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Got hangup\n");
                        strcpy(amdStatus , "HANGUP" );
                        strcpy(amdCause , "" );
                        break;
                }
-               framelength = (ast_codec_get_samples(f) / 8);
-               iTotalTime += framelength;
-               if (iTotalTime >= totalAnalysisTime ) {
-                       ast_verbose(VERBOSE_PREFIX_3 "AMD: Channel [%s]. Too long...\n", chan->name );
-                       ast_frfree(f);
-                       strcpy(amdStatus , "NOTSURE" );
-                       sprintf(amdCause , "TOOLONG-%d", iTotalTime );
-                       break;
-               }
                if (f->frametype == AST_FRAME_VOICE ) {
+                       framelength = (ast_codec_get_samples(f) / DEFAULT_SAMPLES_PER_MS);
+                       iTotalTime += framelength;
+                       if (iTotalTime >= totalAnalysisTime ) {
+                               if (option_verbose > 2) 
+                                       ast_verbose(VERBOSE_PREFIX_3 "AMD: Channel [%s]. Too long...\n", chan->name );
+                               ast_frfree(f);
+                               strcpy(amdStatus , "NOTSURE" );
+                               sprintf(amdCause , "TOOLONG-%d", iTotalTime );
+                               break;
+                       }
                        dspsilence = 0;
                        ast_dsp_silence(silenceDetector, f, &dspsilence);
                        if (dspsilence ) {
                                silenceDuration = dspsilence;
-                               /* ast_verbose(VERBOSE_PREFIX_3 "AMD: %d SILENCE: silenceDuration:%d afterGreetingSilence:%d inGreeting:%d\n", currentState, silenceDuration, afterGreetingSilence, inGreeting ); */
                                if (silenceDuration >= betweenWordsSilence ) {
                                        if (currentState != STATE_IN_SILENCE ) {
                                                previousState = currentState;
-                                               ast_verbose(VERBOSE_PREFIX_3 "AMD: Changed state to STATE_IN_SILENCE\n");
+                                               if (option_verbose > 2)
+                                                       ast_verbose(VERBOSE_PREFIX_3 "AMD: Changed state to STATE_IN_SILENCE\n");
                                        }
                                        currentState  = STATE_IN_SILENCE;
                                        consecutiveVoiceDuration = 0;
                                }
                                if (inInitialSilence == 1  && silenceDuration >= initialSilence ) {
-                                       ast_verbose(VERBOSE_PREFIX_3 "AMD: ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n",
+                                       if (option_verbose > 2)
+                                               ast_verbose(VERBOSE_PREFIX_3 "AMD: ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n",
                                                        silenceDuration, initialSilence );
                                        ast_frfree(f);
                                        strcpy(amdStatus , "MACHINE" );
@@ -246,31 +252,33 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data)
                                }
 
                                if (silenceDuration >= afterGreetingSilence  &&  inGreeting == 1 ) {
-                                       ast_verbose(VERBOSE_PREFIX_3 "AMD: HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
+                                       if (option_verbose > 2)
+                                               ast_verbose(VERBOSE_PREFIX_3 "AMD: HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
                                                        silenceDuration, afterGreetingSilence );
                                        ast_frfree(f);
-                                       strcpy(amdStatus , "PERSON" );
+                                       strcpy(amdStatus , "HUMAN" );
                                        sprintf(amdCause , "HUMAN-%d-%d", silenceDuration, afterGreetingSilence );
                                        break;
                                }
                        } else {
                                consecutiveVoiceDuration += framelength;
                                voiceDuration += framelength;
-                               /* ast_verbose(VERBOSE_PREFIX_3 "AMD: %d VOICE: ConsecutiveVoice:%d voiceDuration:%d inGreeting:%d\n", currentState, consecutiveVoiceDuration, voiceDuration, inGreeting ); */
 
                                /* If I have enough consecutive voice to say that I am in a Word, I can only increment the
                                        number of words if my previous state was Silence, which means that I moved into a word. */
                                if (consecutiveVoiceDuration >= minimumWordLength ) {
                                        if (currentState == STATE_IN_SILENCE ) {
                                                iWordsCount++;
-                                               ast_verbose(VERBOSE_PREFIX_3 "AMD: Word detected. iWordsCount:%d\n", iWordsCount );
+                                               if (option_verbose > 2)
+                                                       ast_verbose(VERBOSE_PREFIX_3 "AMD: Word detected. iWordsCount:%d\n", iWordsCount );
                                                previousState = currentState;
                                                currentState = STATE_IN_WORD;
                                        }
                                }
 
                                if (iWordsCount >= maximumNumberOfWords ) {
-                                       ast_verbose(VERBOSE_PREFIX_3 "AMD: ANSWERING MACHINE: iWordsCount:%d\n", iWordsCount );
+                                       if (option_verbose > 2)
+                                               ast_verbose(VERBOSE_PREFIX_3 "AMD: ANSWERING MACHINE: iWordsCount:%d\n", iWordsCount );
                                        ast_frfree(f);
                                        strcpy(amdStatus , "MACHINE" );
                                        sprintf(amdCause , "MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords );
@@ -278,9 +286,9 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data)
                                }
 
                                if (inGreeting == 1  &&  voiceDuration >= greeting ) {
-                                       ast_verbose(VERBOSE_PREFIX_3 "AMD: ANSWERING MACHINE: voiceDuration:%d greeting:%d\n",
-                                                       voiceDuration, greeting );
-                                       ast_frfree(f);
+                                       if (option_verbose > 2)
+                                       ast_verbose(VERBOSE_PREFIX_3 "AMD: ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", voiceDuration, greeting);
+                                        ast_frfree(f);
                                        strcpy(amdStatus , "MACHINE" );
                                        sprintf(amdCause , "LONGGREETING-%d-%d", voiceDuration, greeting );
                                        break;
@@ -294,12 +302,19 @@ static void isAnsweringMachine(struct ast_channel *chan, void *data)
                }
                ast_frfree(f);
        }
+       if (!ret) {
+               /* It took too long to get a frame back. Giving up. */
+               if (option_verbose > 2)
+                       ast_verbose(VERBOSE_PREFIX_3 "AMD: Channel [%s]. Too long...\n", chan->name );
+               strcpy(amdStatus , "NOTSURE" );
+               sprintf(amdCause , "TOOLONG-%d", iTotalTime );
+       }
 
        pbx_builtin_setvar_helper(chan , "AMDSTATUS" , amdStatus );
        pbx_builtin_setvar_helper(chan , "AMDCAUSE" , amdCause );
 
        /* If We Started With A Valid Read Format, Return To It... */
-       if (readFormat) {
+       if (readFormat && chan->_state == AST_STATE_UP) {
                res = ast_set_read_format(chan, readFormat );
                if (res)
                        ast_log(LOG_WARNING, "AMD: Unable to restore read format on '%s'\n", chan->name);
@@ -369,7 +384,8 @@ static void load_config(void)
        }
        ast_config_destroy(cfg);
 
-       ast_verbose(VERBOSE_PREFIX_3 "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
+       if (option_verbose > 2)
+               ast_verbose(VERBOSE_PREFIX_3 "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
                "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] \n",
                                dfltInitialSilence, dfltGreeting, dfltAfterGreetingSilence, dfltTotalAnalysisTime,
                                dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold );