Fri Feb 10 06:34:19 2012

Asterisk developer's documentation


app_amd.c File Reference

Answering machine detection. More...

#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/dsp.h"
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/app.h"

Include dependency graph for app_amd.c:

Go to the source code of this file.

Defines

#define STATE_IN_SILENCE   2
#define STATE_IN_WORD   1

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int amd_exec (struct ast_channel *chan, const char *data)
static void isAnsweringMachine (struct ast_channel *chan, const char *data)
static int load_config (int reload)
static int load_module (void)
static int reload (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Answering Machine Detection Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static const char app [] = "AMD"
static struct ast_module_infoast_module_info = &__mod_info
static int dfltAfterGreetingSilence = 800
static int dfltBetweenWordsSilence = 50
static int dfltGreeting = 1500
static int dfltInitialSilence = 2500
static int dfltMaximumNumberOfWords = 3
static int dfltMaximumWordLength = 5000
static int dfltMaxWaitTimeForFrame = 50
static int dfltMinimumWordLength = 100
static int dfltSilenceThreshold = 256
static int dfltTotalAnalysisTime = 5000


Detailed Description

Answering machine detection.

Author:
Claude Klimos (claude.klimos@aheeva.com)

Definition in file app_amd.c.


Define Documentation

#define STATE_IN_SILENCE   2

Definition at line 133 of file app_amd.c.

Referenced by isAnsweringMachine().

#define STATE_IN_WORD   1

Definition at line 132 of file app_amd.c.

Referenced by isAnsweringMachine().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 510 of file app_amd.c.

static void __unreg_module ( void   )  [static]

Definition at line 510 of file app_amd.c.

static int amd_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 414 of file app_amd.c.

References isAnsweringMachine().

Referenced by load_module().

00415 {
00416    isAnsweringMachine(chan, data);
00417 
00418    return 0;
00419 }

static void isAnsweringMachine ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 149 of file app_amd.c.

References ast_party_caller::ani, args, AST_APP_ARG, ast_channel_name(), ast_codec_get_samples(), ast_debug, AST_DECLARE_APP_ARGS, ast_dsp_free(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), ast_format_clear(), ast_format_copy(), AST_FORMAT_SLINEAR, AST_FRAME_CNG, AST_FRAME_NULL, AST_FRAME_VOICE, ast_frfree, ast_getformatname(), ast_log(), ast_read(), ast_set_read_format(), ast_set_read_format_by_id(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_verb, ast_waitfor(), ast_channel::caller, DEFAULT_SAMPLES_PER_MS, f, ast_frame::frametype, ast_party_redirecting::from, ast_format::id, LOG_WARNING, ast_party_id::number, parse(), pbx_builtin_setvar_helper(), ast_channel::readformat, ast_channel::redirecting, S_COR, STATE_IN_SILENCE, STATE_IN_WORD, ast_party_number::str, and ast_party_number::valid.

Referenced by amd_exec().

00150 {
00151    int res = 0;
00152    struct ast_frame *f = NULL;
00153    struct ast_dsp *silenceDetector = NULL;
00154    int dspsilence = 0, framelength = 0;
00155    struct ast_format readFormat;
00156    int inInitialSilence = 1;
00157    int inGreeting = 0;
00158    int voiceDuration = 0;
00159    int silenceDuration = 0;
00160    int iTotalTime = 0;
00161    int iWordsCount = 0;
00162    int currentState = STATE_IN_WORD;
00163    int consecutiveVoiceDuration = 0;
00164    char amdCause[256] = "", amdStatus[256] = "";
00165    char *parse = ast_strdupa(data);
00166 
00167    /* Lets set the initial values of the variables that will control the algorithm.
00168       The initial values are the default ones. If they are passed as arguments
00169       when invoking the application, then the default values will be overwritten
00170       by the ones passed as parameters. */
00171    int initialSilence       = dfltInitialSilence;
00172    int greeting             = dfltGreeting;
00173    int afterGreetingSilence = dfltAfterGreetingSilence;
00174    int totalAnalysisTime    = dfltTotalAnalysisTime;
00175    int minimumWordLength    = dfltMinimumWordLength;
00176    int betweenWordsSilence  = dfltBetweenWordsSilence;
00177    int maximumNumberOfWords = dfltMaximumNumberOfWords;
00178    int silenceThreshold     = dfltSilenceThreshold;
00179    int maximumWordLength    = dfltMaximumWordLength;
00180    int maxWaitTimeForFrame  = dfltMaxWaitTimeForFrame;
00181 
00182    AST_DECLARE_APP_ARGS(args,
00183       AST_APP_ARG(argInitialSilence);
00184       AST_APP_ARG(argGreeting);
00185       AST_APP_ARG(argAfterGreetingSilence);
00186       AST_APP_ARG(argTotalAnalysisTime);
00187       AST_APP_ARG(argMinimumWordLength);
00188       AST_APP_ARG(argBetweenWordsSilence);
00189       AST_APP_ARG(argMaximumNumberOfWords);
00190       AST_APP_ARG(argSilenceThreshold);
00191       AST_APP_ARG(argMaximumWordLength);
00192    );
00193 
00194    ast_format_clear(&readFormat);
00195    ast_verb(3, "AMD: %s %s %s (Fmt: %s)\n", ast_channel_name(chan),
00196       S_COR(chan->caller.ani.number.valid, chan->caller.ani.number.str, "(N/A)"),
00197       S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, "(N/A)"),
00198       ast_getformatname(&chan->readformat));
00199 
00200    /* Lets parse the arguments. */
00201    if (!ast_strlen_zero(parse)) {
00202       /* Some arguments have been passed. Lets parse them and overwrite the defaults. */
00203       AST_STANDARD_APP_ARGS(args, parse);
00204       if (!ast_strlen_zero(args.argInitialSilence))
00205          initialSilence = atoi(args.argInitialSilence);
00206       if (!ast_strlen_zero(args.argGreeting))
00207          greeting = atoi(args.argGreeting);
00208       if (!ast_strlen_zero(args.argAfterGreetingSilence))
00209          afterGreetingSilence = atoi(args.argAfterGreetingSilence);
00210       if (!ast_strlen_zero(args.argTotalAnalysisTime))
00211          totalAnalysisTime = atoi(args.argTotalAnalysisTime);
00212       if (!ast_strlen_zero(args.argMinimumWordLength))
00213          minimumWordLength = atoi(args.argMinimumWordLength);
00214       if (!ast_strlen_zero(args.argBetweenWordsSilence))
00215          betweenWordsSilence = atoi(args.argBetweenWordsSilence);
00216       if (!ast_strlen_zero(args.argMaximumNumberOfWords))
00217          maximumNumberOfWords = atoi(args.argMaximumNumberOfWords);
00218       if (!ast_strlen_zero(args.argSilenceThreshold))
00219          silenceThreshold = atoi(args.argSilenceThreshold);
00220       if (!ast_strlen_zero(args.argMaximumWordLength))
00221          maximumWordLength = atoi(args.argMaximumWordLength);
00222    } else {
00223       ast_debug(1, "AMD using the default parameters.\n");
00224    }
00225 
00226    /* Find lowest ms value, that will be max wait time for a frame */
00227    if (maxWaitTimeForFrame > initialSilence)
00228       maxWaitTimeForFrame = initialSilence;
00229    if (maxWaitTimeForFrame > greeting)
00230       maxWaitTimeForFrame = greeting;
00231    if (maxWaitTimeForFrame > afterGreetingSilence)
00232       maxWaitTimeForFrame = afterGreetingSilence;
00233    if (maxWaitTimeForFrame > totalAnalysisTime)
00234       maxWaitTimeForFrame = totalAnalysisTime;
00235    if (maxWaitTimeForFrame > minimumWordLength)
00236       maxWaitTimeForFrame = minimumWordLength;
00237    if (maxWaitTimeForFrame > betweenWordsSilence)
00238       maxWaitTimeForFrame = betweenWordsSilence;
00239 
00240    /* Now we're ready to roll! */
00241    ast_verb(3, "AMD: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
00242       "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d] \n",
00243             initialSilence, greeting, afterGreetingSilence, totalAnalysisTime,
00244             minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold, maximumWordLength);
00245 
00246    /* Set read format to signed linear so we get signed linear frames in */
00247    ast_format_copy(&readFormat, &chan->readformat);
00248    if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR) < 0 ) {
00249       ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to set to linear mode, giving up\n", ast_channel_name(chan));
00250       pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
00251       pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
00252       return;
00253    }
00254 
00255    /* Create a new DSP that will detect the silence */
00256    if (!(silenceDetector = ast_dsp_new())) {
00257       ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to create silence detector :(\n", ast_channel_name(chan));
00258       pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
00259       pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
00260       return;
00261    }
00262 
00263    /* Set silence threshold to specified value */
00264    ast_dsp_set_threshold(silenceDetector, silenceThreshold);
00265 
00266    /* Now we go into a loop waiting for frames from the channel */
00267    while ((res = ast_waitfor(chan, 2 * maxWaitTimeForFrame)) > -1) {
00268 
00269       /* If we fail to read in a frame, that means they hung up */
00270       if (!(f = ast_read(chan))) {
00271          ast_verb(3, "AMD: Channel [%s]. HANGUP\n", ast_channel_name(chan));
00272          ast_debug(1, "Got hangup\n");
00273          strcpy(amdStatus, "HANGUP");
00274          res = 1;
00275          break;
00276       }
00277 
00278       if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_NULL || f->frametype == AST_FRAME_CNG) {
00279          /* If the total time exceeds the analysis time then give up as we are not too sure */
00280          if (f->frametype == AST_FRAME_VOICE) {
00281             framelength = (ast_codec_get_samples(f) / DEFAULT_SAMPLES_PER_MS);
00282          } else {
00283             framelength = 2 * maxWaitTimeForFrame;
00284          }
00285 
00286          iTotalTime += framelength;
00287          if (iTotalTime >= totalAnalysisTime) {
00288             ast_verb(3, "AMD: Channel [%s]. Too long...\n", ast_channel_name(chan));
00289             ast_frfree(f);
00290             strcpy(amdStatus , "NOTSURE");
00291             sprintf(amdCause , "TOOLONG-%d", iTotalTime);
00292             break;
00293          }
00294 
00295          /* Feed the frame of audio into the silence detector and see if we get a result */
00296          if (f->frametype != AST_FRAME_VOICE)
00297             dspsilence += 2 * maxWaitTimeForFrame;
00298          else {
00299             dspsilence = 0;
00300             ast_dsp_silence(silenceDetector, f, &dspsilence);
00301          }
00302 
00303          if (dspsilence > 0) {
00304             silenceDuration = dspsilence;
00305             
00306             if (silenceDuration >= betweenWordsSilence) {
00307                if (currentState != STATE_IN_SILENCE ) {
00308                   ast_verb(3, "AMD: Channel [%s]. Changed state to STATE_IN_SILENCE\n", ast_channel_name(chan));
00309                }
00310                /* Find words less than word duration */
00311                if (consecutiveVoiceDuration < minimumWordLength && consecutiveVoiceDuration > 0){
00312                   ast_verb(3, "AMD: Channel [%s]. Short Word Duration: %d\n", ast_channel_name(chan), consecutiveVoiceDuration);
00313                }
00314                currentState  = STATE_IN_SILENCE;
00315                consecutiveVoiceDuration = 0;
00316             }
00317 
00318             if (inInitialSilence == 1  && silenceDuration >= initialSilence) {
00319                ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n",
00320                   ast_channel_name(chan), silenceDuration, initialSilence);
00321                ast_frfree(f);
00322                strcpy(amdStatus , "MACHINE");
00323                sprintf(amdCause , "INITIALSILENCE-%d-%d", silenceDuration, initialSilence);
00324                res = 1;
00325                break;
00326             }
00327             
00328             if (silenceDuration >= afterGreetingSilence  &&  inGreeting == 1) {
00329                ast_verb(3, "AMD: Channel [%s]. HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
00330                   ast_channel_name(chan), silenceDuration, afterGreetingSilence);
00331                ast_frfree(f);
00332                strcpy(amdStatus , "HUMAN");
00333                sprintf(amdCause , "HUMAN-%d-%d", silenceDuration, afterGreetingSilence);
00334                res = 1;
00335                break;
00336             }
00337             
00338          } else {
00339             consecutiveVoiceDuration += framelength;
00340             voiceDuration += framelength;
00341 
00342             /* If I have enough consecutive voice to say that I am in a Word, I can only increment the
00343                number of words if my previous state was Silence, which means that I moved into a word. */
00344             if (consecutiveVoiceDuration >= minimumWordLength && currentState == STATE_IN_SILENCE) {
00345                iWordsCount++;
00346                ast_verb(3, "AMD: Channel [%s]. Word detected. iWordsCount:%d\n", ast_channel_name(chan), iWordsCount);
00347                currentState = STATE_IN_WORD;
00348             }
00349             if (consecutiveVoiceDuration >= maximumWordLength){
00350                ast_verb(3, "AMD: Channel [%s]. Maximum Word Length detected. [%d]\n", ast_channel_name(chan), consecutiveVoiceDuration);
00351                ast_frfree(f);
00352                strcpy(amdStatus , "MACHINE");
00353                sprintf(amdCause , "MAXWORDLENGTH-%d", consecutiveVoiceDuration);
00354                break;
00355             }
00356             if (iWordsCount >= maximumNumberOfWords) {
00357                ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: iWordsCount:%d\n", ast_channel_name(chan), iWordsCount);
00358                ast_frfree(f);
00359                strcpy(amdStatus , "MACHINE");
00360                sprintf(amdCause , "MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords);
00361                res = 1;
00362                break;
00363             }
00364 
00365             if (inGreeting == 1 && voiceDuration >= greeting) {
00366                ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", ast_channel_name(chan), voiceDuration, greeting);
00367                ast_frfree(f);
00368                strcpy(amdStatus , "MACHINE");
00369                sprintf(amdCause , "LONGGREETING-%d-%d", voiceDuration, greeting);
00370                res = 1;
00371                break;
00372             }
00373 
00374             if (voiceDuration >= minimumWordLength ) {
00375                if (silenceDuration > 0)
00376                   ast_verb(3, "AMD: Channel [%s]. Detected Talk, previous silence duration: %d\n", ast_channel_name(chan), silenceDuration);
00377                silenceDuration = 0;
00378             }
00379             if (consecutiveVoiceDuration >= minimumWordLength && inGreeting == 0) {
00380                /* Only go in here once to change the greeting flag when we detect the 1st word */
00381                if (silenceDuration > 0)
00382                   ast_verb(3, "AMD: Channel [%s]. Before Greeting Time:  silenceDuration: %d voiceDuration: %d\n", ast_channel_name(chan), silenceDuration, voiceDuration);
00383                inInitialSilence = 0;
00384                inGreeting = 1;
00385             }
00386             
00387          }
00388       }
00389       ast_frfree(f);
00390    }
00391    
00392    if (!res) {
00393       /* It took too long to get a frame back. Giving up. */
00394       ast_verb(3, "AMD: Channel [%s]. Too long...\n", ast_channel_name(chan));
00395       strcpy(amdStatus , "NOTSURE");
00396       sprintf(amdCause , "TOOLONG-%d", iTotalTime);
00397    }
00398 
00399    /* Set the status and cause on the channel */
00400    pbx_builtin_setvar_helper(chan , "AMDSTATUS" , amdStatus);
00401    pbx_builtin_setvar_helper(chan , "AMDCAUSE" , amdCause);
00402 
00403    /* Restore channel read format */
00404    if (readFormat.id && ast_set_read_format(chan, &readFormat))
00405       ast_log(LOG_WARNING, "AMD: Unable to restore read format on '%s'\n", ast_channel_name(chan));
00406 
00407    /* Free the DSP used to detect silence */
00408    ast_dsp_free(silenceDetector);
00409 
00410    return;
00411 }

static int load_config ( int  reload  )  [static]

Definition at line 421 of file app_amd.c.

References ast_category_browse(), ast_config_destroy(), ast_config_load, ast_dsp_get_threshold_from_settings(), ast_log(), ast_variable_browse(), ast_verb, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, ast_variable::lineno, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, THRESHOLD_SILENCE, ast_variable::value, and var.

00422 {
00423    struct ast_config *cfg = NULL;
00424    char *cat = NULL;
00425    struct ast_variable *var = NULL;
00426    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00427 
00428    dfltSilenceThreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
00429 
00430    if (!(cfg = ast_config_load("amd.conf", config_flags))) {
00431       ast_log(LOG_ERROR, "Configuration file amd.conf missing.\n");
00432       return -1;
00433    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00434       return 0;
00435    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00436       ast_log(LOG_ERROR, "Config file amd.conf is in an invalid format.  Aborting.\n");
00437       return -1;
00438    }
00439 
00440    cat = ast_category_browse(cfg, NULL);
00441 
00442    while (cat) {
00443       if (!strcasecmp(cat, "general") ) {
00444          var = ast_variable_browse(cfg, cat);
00445          while (var) {
00446             if (!strcasecmp(var->name, "initial_silence")) {
00447                dfltInitialSilence = atoi(var->value);
00448             } else if (!strcasecmp(var->name, "greeting")) {
00449                dfltGreeting = atoi(var->value);
00450             } else if (!strcasecmp(var->name, "after_greeting_silence")) {
00451                dfltAfterGreetingSilence = atoi(var->value);
00452             } else if (!strcasecmp(var->name, "silence_threshold")) {
00453                dfltSilenceThreshold = atoi(var->value);
00454             } else if (!strcasecmp(var->name, "total_analysis_time")) {
00455                dfltTotalAnalysisTime = atoi(var->value);
00456             } else if (!strcasecmp(var->name, "min_word_length")) {
00457                dfltMinimumWordLength = atoi(var->value);
00458             } else if (!strcasecmp(var->name, "between_words_silence")) {
00459                dfltBetweenWordsSilence = atoi(var->value);
00460             } else if (!strcasecmp(var->name, "maximum_number_of_words")) {
00461                dfltMaximumNumberOfWords = atoi(var->value);
00462             } else if (!strcasecmp(var->name, "maximum_word_length")) {
00463                dfltMaximumWordLength = atoi(var->value);
00464 
00465             } else {
00466                ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n",
00467                   app, cat, var->name, var->lineno);
00468             }
00469             var = var->next;
00470          }
00471       }
00472       cat = ast_category_browse(cfg, cat);
00473    }
00474 
00475    ast_config_destroy(cfg);
00476 
00477    ast_verb(3, "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
00478       "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d]\n",
00479       dfltInitialSilence, dfltGreeting, dfltAfterGreetingSilence, dfltTotalAnalysisTime,
00480       dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold, dfltMaximumWordLength);
00481 
00482    return 0;
00483 }

static int load_module ( void   )  [static]

static int reload ( void   )  [static]

Definition at line 499 of file app_amd.c.

References AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and load_config().

00500 {
00501    if (load_config(1))
00502       return AST_MODULE_LOAD_DECLINE;
00503    return AST_MODULE_LOAD_SUCCESS;
00504 }

static int unload_module ( void   )  [static]

Definition at line 485 of file app_amd.c.

References ast_unregister_application().

00486 {
00487    return ast_unregister_application(app);
00488 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Answering Machine Detection Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 510 of file app_amd.c.

const char app[] = "AMD" [static]

Definition at line 130 of file app_amd.c.

Definition at line 510 of file app_amd.c.

int dfltAfterGreetingSilence = 800 [static]

Definition at line 138 of file app_amd.c.

int dfltBetweenWordsSilence = 50 [static]

Definition at line 141 of file app_amd.c.

int dfltGreeting = 1500 [static]

Definition at line 137 of file app_amd.c.

int dfltInitialSilence = 2500 [static]

Definition at line 136 of file app_amd.c.

int dfltMaximumNumberOfWords = 3 [static]

Definition at line 142 of file app_amd.c.

int dfltMaximumWordLength = 5000 [static]

Definition at line 144 of file app_amd.c.

int dfltMaxWaitTimeForFrame = 50 [static]

Definition at line 147 of file app_amd.c.

int dfltMinimumWordLength = 100 [static]

Definition at line 140 of file app_amd.c.

int dfltSilenceThreshold = 256 [static]

Definition at line 143 of file app_amd.c.

int dfltTotalAnalysisTime = 5000 [static]

Definition at line 139 of file app_amd.c.


Generated on Fri Feb 10 06:34:19 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6