152static const char app[] = 
"AMD";
 
  154#define STATE_IN_WORD       1 
  155#define STATE_IN_SILENCE    2 
  177    int audioFrameCount = 0;
 
  180    struct timeval amd_tvstart;
 
  181    int dspsilence = 0, framelength = 0;
 
  183    int inInitialSilence = 1;
 
  185    int voiceDuration = 0;
 
  186    int silenceDuration = 0;
 
  190    int consecutiveVoiceDuration = 0;
 
  191    char amdCause[256] = 
"", amdStatus[256] = 
"";
 
  208    const char *audioFile = 
NULL;
 
  239            initialSilence = atoi(
args.argInitialSilence);
 
  241            greeting = atoi(
args.argGreeting);
 
  243            afterGreetingSilence = atoi(
args.argAfterGreetingSilence);
 
  245            totalAnalysisTime = atoi(
args.argTotalAnalysisTime);
 
  247            minimumWordLength = atoi(
args.argMinimumWordLength);
 
  249            betweenWordsSilence = atoi(
args.argBetweenWordsSilence);
 
  251            maximumNumberOfWords = atoi(
args.argMaximumNumberOfWords);
 
  253            silenceThreshold = atoi(
args.argSilenceThreshold);
 
  255            maximumWordLength = atoi(
args.argMaximumWordLength);
 
  257            audioFile = 
args.audioFile;
 
  260        ast_debug(1, 
"AMD using the default parameters.\n");
 
  264    if (maxWaitTimeForFrame > initialSilence)
 
  265        maxWaitTimeForFrame = initialSilence;
 
  266    if (maxWaitTimeForFrame > greeting)
 
  267        maxWaitTimeForFrame = greeting;
 
  268    if (maxWaitTimeForFrame > afterGreetingSilence)
 
  269        maxWaitTimeForFrame = afterGreetingSilence;
 
  270    if (maxWaitTimeForFrame > totalAnalysisTime)
 
  271        maxWaitTimeForFrame = totalAnalysisTime;
 
  272    if (maxWaitTimeForFrame > minimumWordLength)
 
  273        maxWaitTimeForFrame = minimumWordLength;
 
  274    if (maxWaitTimeForFrame > betweenWordsSilence)
 
  275        maxWaitTimeForFrame = betweenWordsSilence;
 
  278    ast_verb(3, 
"AMD: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] " 
  279        "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d] \n",
 
  280                initialSilence, greeting, afterGreetingSilence, totalAnalysisTime,
 
  281                minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold, maximumWordLength);
 
  312    while ((res = 
ast_waitfor(chan, 2 * maxWaitTimeForFrame)) > -1) {
 
  317            ms = 2 * maxWaitTimeForFrame - res;
 
  324            strcpy(amdStatus, 
"HANGUP");
 
  332            strcpy(amdStatus , 
"NOTSURE");
 
  333            if ( audioFrameCount == 0 ) {
 
  334                ast_verb(3, 
"AMD: Channel [%s]. No audio data received in [%d] seconds.\n", 
ast_channel_name(chan), totalAnalysisTime);
 
  335                sprintf(amdCause , 
"NOAUDIODATA-%d", iTotalTime);
 
  339            sprintf(amdCause , 
"TOOLONG-%d", iTotalTime);
 
  354            iTotalTime += framelength;
 
  356            ast_debug(1, 
"AMD: Channel [%s] frametype [%s] iTotalTime [%d] framelength [%d] totalAnalysisTime [%d]\n",
 
  359                      iTotalTime, framelength, totalAnalysisTime);
 
  362            if (iTotalTime >= totalAnalysisTime) {
 
  365                strcpy(amdStatus , 
"NOTSURE");
 
  366                sprintf(amdCause , 
"TOOLONG-%d", iTotalTime);
 
  372                dspsilence += framelength;
 
  378            if (dspsilence > 0) {
 
  379                silenceDuration = dspsilence;
 
  381                if (silenceDuration >= betweenWordsSilence) {
 
  386                    if (consecutiveVoiceDuration < minimumWordLength && consecutiveVoiceDuration > 0){
 
  390                    consecutiveVoiceDuration = 0;
 
  393                if (inInitialSilence == 1  && silenceDuration >= initialSilence) {
 
  394                    ast_verb(3, 
"AMD: Channel [%s]. ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n",
 
  397                    strcpy(amdStatus , 
"MACHINE");
 
  398                    sprintf(amdCause , 
"INITIALSILENCE-%d-%d", silenceDuration, initialSilence);
 
  403                if (silenceDuration >= afterGreetingSilence  &&  inGreeting == 1) {
 
  404                    ast_verb(3, 
"AMD: Channel [%s]. HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
 
  407                    strcpy(amdStatus , 
"HUMAN");
 
  408                    sprintf(amdCause , 
"HUMAN-%d-%d", silenceDuration, afterGreetingSilence);
 
  414                consecutiveVoiceDuration += framelength;
 
  415                voiceDuration += framelength;
 
  419                if (consecutiveVoiceDuration >= minimumWordLength && currentState == 
STATE_IN_SILENCE) {
 
  424                if (consecutiveVoiceDuration >= maximumWordLength){
 
  425                    ast_verb(3, 
"AMD: Channel [%s]. Maximum Word Length detected. [%d]\n", 
ast_channel_name(chan), consecutiveVoiceDuration);
 
  427                    strcpy(amdStatus , 
"MACHINE");
 
  428                    sprintf(amdCause , 
"MAXWORDLENGTH-%d", consecutiveVoiceDuration);
 
  431                if (iWordsCount > maximumNumberOfWords) {
 
  434                    strcpy(amdStatus , 
"MACHINE");
 
  435                    sprintf(amdCause , 
"MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords);
 
  440                if (inGreeting == 1 && voiceDuration >= greeting) {
 
  441                    ast_verb(3, 
"AMD: Channel [%s]. ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", 
ast_channel_name(chan), voiceDuration, greeting);
 
  443                    strcpy(amdStatus , 
"MACHINE");
 
  444                    sprintf(amdCause , 
"LONGGREETING-%d-%d", voiceDuration, greeting);
 
  449                if (voiceDuration >= minimumWordLength ) {
 
  450                    if (silenceDuration > 0)
 
  451                        ast_verb(3, 
"AMD: Channel [%s]. Detected Talk, previous silence duration: %d\n", 
ast_channel_name(chan), silenceDuration);
 
  454                if (consecutiveVoiceDuration >= minimumWordLength && inGreeting == 0) {
 
  456                    if (silenceDuration > 0)
 
  457                        ast_verb(3, 
"AMD: Channel [%s]. Before Greeting Time:  silenceDuration: %d voiceDuration: %d\n", 
ast_channel_name(chan), silenceDuration, voiceDuration);
 
  458                    inInitialSilence = 0;
 
  465            if (iTotalTime >= totalAnalysisTime) {
 
  467                strcpy(amdStatus , 
"NOTSURE");
 
  468                sprintf(amdCause , 
"TOOLONG-%d", iTotalTime);
 
  478        strcpy(amdStatus , 
"NOTSURE");
 
  479        sprintf(amdCause , 
"TOOLONG-%d", iTotalTime);
 
 
  523        ast_log(
LOG_ERROR, 
"Config file amd.conf is in an invalid format.  Aborting.\n");
 
  530        if (!strcasecmp(cat, 
"general") ) {
 
  533                if (!strcasecmp(
var->name, 
"initial_silence")) {
 
  535                } 
else if (!strcasecmp(
var->name, 
"greeting")) {
 
  537                } 
else if (!strcasecmp(
var->name, 
"after_greeting_silence")) {
 
  539                } 
else if (!strcasecmp(
var->name, 
"silence_threshold")) {
 
  541                } 
else if (!strcasecmp(
var->name, 
"total_analysis_time")) {
 
  543                } 
else if (!strcasecmp(
var->name, 
"min_word_length")) {
 
  545                } 
else if (!strcasecmp(
var->name, 
"between_words_silence")) {
 
  547                } 
else if (!strcasecmp(
var->name, 
"maximum_number_of_words")) {
 
  549                } 
else if (!strcasecmp(
var->name, 
"maximum_word_length")) {
 
  551                } 
else if (!strcasecmp(
var->name, 
"playback_file")) {
 
  573    ast_verb(5, 
"AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] " 
  574        "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d]\n",
 
 
static int load_config(void)
static int dfltBetweenWordsSilence
static int amd_exec(struct ast_channel *chan, const char *data)
static int dfltInitialSilence
static int dfltMaximumNumberOfWords
static ast_mutex_t config_lock
static int dfltMinimumWordLength
static int dfltMaximumWordLength
static int load_module(void)
Load the module.
static int dfltTotalAnalysisTime
static char * dfltAudioFile
static int unload_module(void)
static void isAnsweringMachine(struct ast_channel *chan, const char *data)
static int dfltAfterGreetingSilence
static int dfltMaxWaitTimeForFrame
static int dfltSilenceThreshold
Asterisk main include file. File version handling, generic pbx functions.
#define DEFAULT_SAMPLES_PER_MS
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
const char * ast_channel_language(const struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
unsigned int ast_codec_samples_count(struct ast_frame *frame)
Get the number of samples contained within a frame.
Convenient Signal Processing routines.
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set the minimum average magnitude threshold to determine talking by the DSP.
void ast_dsp_free(struct ast_dsp *dsp)
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
int ast_stopstream(struct ast_channel *c)
Stops a stream.
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
@ CONFIG_FLAG_FILEUNCHANGED
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_verb(level,...)
Asterisk locking-related definitions:
#define ast_mutex_init(pmutex)
#define ast_mutex_unlock(a)
#define ast_mutex_destroy(a)
#define ast_mutex_lock(a)
Asterisk module definitions.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODULE_SUPPORT_EXTENDED
#define ASTERISK_GPL_KEY
The text the key() function should return.
int ast_unregister_application(const char *app)
Unregister an application.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Core PBX routines and definitions.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Main Channel structure associated with a channel.
Structure used to handle boolean flags.
Data structure associated with a single frame of data.
enum ast_frame_type frametype
Structure for mutex and tracking information.
Structure for variables, used for configurations and for channel variables.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.