143 static const char app[] =
"AMD";
145 #define STATE_IN_WORD 1 146 #define STATE_IN_SILENCE 2 165 int audioFrameCount = 0;
168 struct timeval amd_tvstart;
169 int dspsilence = 0, framelength = 0;
171 int inInitialSilence = 1;
173 int voiceDuration = 0;
174 int silenceDuration = 0;
178 int consecutiveVoiceDuration = 0;
179 char amdCause[256] =
"", amdStatus[256] =
"";
219 initialSilence = atoi(
args.argInitialSilence);
221 greeting = atoi(
args.argGreeting);
223 afterGreetingSilence = atoi(
args.argAfterGreetingSilence);
225 totalAnalysisTime = atoi(
args.argTotalAnalysisTime);
227 minimumWordLength = atoi(
args.argMinimumWordLength);
229 betweenWordsSilence = atoi(
args.argBetweenWordsSilence);
231 maximumNumberOfWords = atoi(
args.argMaximumNumberOfWords);
233 silenceThreshold = atoi(
args.argSilenceThreshold);
235 maximumWordLength = atoi(
args.argMaximumWordLength);
237 ast_debug(1,
"AMD using the default parameters.\n");
241 if (maxWaitTimeForFrame > initialSilence)
242 maxWaitTimeForFrame = initialSilence;
243 if (maxWaitTimeForFrame > greeting)
244 maxWaitTimeForFrame = greeting;
245 if (maxWaitTimeForFrame > afterGreetingSilence)
246 maxWaitTimeForFrame = afterGreetingSilence;
247 if (maxWaitTimeForFrame > totalAnalysisTime)
248 maxWaitTimeForFrame = totalAnalysisTime;
249 if (maxWaitTimeForFrame > minimumWordLength)
250 maxWaitTimeForFrame = minimumWordLength;
251 if (maxWaitTimeForFrame > betweenWordsSilence)
252 maxWaitTimeForFrame = betweenWordsSilence;
255 ast_verb(3,
"AMD: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] " 256 "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d] \n",
257 initialSilence, greeting, afterGreetingSilence, totalAnalysisTime,
258 minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold, maximumWordLength);
284 while ((res =
ast_waitfor(chan, 2 * maxWaitTimeForFrame)) > -1) {
289 ms = 2 * maxWaitTimeForFrame - res;
296 strcpy(amdStatus,
"HANGUP");
304 strcpy(amdStatus ,
"NOTSURE");
305 if ( audioFrameCount == 0 ) {
306 ast_verb(3,
"AMD: Channel [%s]. No audio data received in [%d] seconds.\n",
ast_channel_name(chan), totalAnalysisTime);
307 sprintf(amdCause ,
"NOAUDIODATA-%d", iTotalTime);
311 sprintf(amdCause ,
"TOOLONG-%d", iTotalTime);
326 iTotalTime += framelength;
328 ast_debug(1,
"AMD: Channel [%s] frametype [%s] iTotalTime [%d] framelength [%d] totalAnalysisTime [%d]\n",
331 iTotalTime, framelength, totalAnalysisTime);
334 if (iTotalTime >= totalAnalysisTime) {
337 strcpy(amdStatus ,
"NOTSURE");
338 sprintf(amdCause ,
"TOOLONG-%d", iTotalTime);
344 dspsilence += framelength;
350 if (dspsilence > 0) {
351 silenceDuration = dspsilence;
353 if (silenceDuration >= betweenWordsSilence) {
358 if (consecutiveVoiceDuration < minimumWordLength && consecutiveVoiceDuration > 0){
362 consecutiveVoiceDuration = 0;
365 if (inInitialSilence == 1 && silenceDuration >= initialSilence) {
366 ast_verb(3,
"AMD: Channel [%s]. ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n",
369 strcpy(amdStatus ,
"MACHINE");
370 sprintf(amdCause ,
"INITIALSILENCE-%d-%d", silenceDuration, initialSilence);
375 if (silenceDuration >= afterGreetingSilence && inGreeting == 1) {
376 ast_verb(3,
"AMD: Channel [%s]. HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
379 strcpy(amdStatus ,
"HUMAN");
380 sprintf(amdCause ,
"HUMAN-%d-%d", silenceDuration, afterGreetingSilence);
386 consecutiveVoiceDuration += framelength;
387 voiceDuration += framelength;
391 if (consecutiveVoiceDuration >= minimumWordLength && currentState ==
STATE_IN_SILENCE) {
396 if (consecutiveVoiceDuration >= maximumWordLength){
397 ast_verb(3,
"AMD: Channel [%s]. Maximum Word Length detected. [%d]\n",
ast_channel_name(chan), consecutiveVoiceDuration);
399 strcpy(amdStatus ,
"MACHINE");
400 sprintf(amdCause ,
"MAXWORDLENGTH-%d", consecutiveVoiceDuration);
403 if (iWordsCount > maximumNumberOfWords) {
406 strcpy(amdStatus ,
"MACHINE");
407 sprintf(amdCause ,
"MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords);
412 if (inGreeting == 1 && voiceDuration >= greeting) {
413 ast_verb(3,
"AMD: Channel [%s]. ANSWERING MACHINE: voiceDuration:%d greeting:%d\n",
ast_channel_name(chan), voiceDuration, greeting);
415 strcpy(amdStatus ,
"MACHINE");
416 sprintf(amdCause ,
"LONGGREETING-%d-%d", voiceDuration, greeting);
421 if (voiceDuration >= minimumWordLength ) {
422 if (silenceDuration > 0)
423 ast_verb(3,
"AMD: Channel [%s]. Detected Talk, previous silence duration: %d\n",
ast_channel_name(chan), silenceDuration);
426 if (consecutiveVoiceDuration >= minimumWordLength && inGreeting == 0) {
428 if (silenceDuration > 0)
429 ast_verb(3,
"AMD: Channel [%s]. Before Greeting Time: silenceDuration: %d voiceDuration: %d\n",
ast_channel_name(chan), silenceDuration, voiceDuration);
430 inInitialSilence = 0;
437 if (iTotalTime >= totalAnalysisTime) {
439 strcpy(amdStatus ,
"NOTSURE");
440 sprintf(amdCause ,
"TOOLONG-%d", iTotalTime);
450 strcpy(amdStatus ,
"NOTSURE");
451 sprintf(amdCause ,
"TOOLONG-%d", iTotalTime);
491 ast_log(
LOG_ERROR,
"Config file amd.conf is in an invalid format. Aborting.\n");
498 if (!strcasecmp(cat,
"general") ) {
501 if (!strcasecmp(var->
name,
"initial_silence")) {
503 }
else if (!strcasecmp(var->
name,
"greeting")) {
505 }
else if (!strcasecmp(var->
name,
"after_greeting_silence")) {
507 }
else if (!strcasecmp(var->
name,
"silence_threshold")) {
509 }
else if (!strcasecmp(var->
name,
"total_analysis_time")) {
511 }
else if (!strcasecmp(var->
name,
"min_word_length")) {
513 }
else if (!strcasecmp(var->
name,
"between_words_silence")) {
515 }
else if (!strcasecmp(var->
name,
"maximum_number_of_words")) {
517 }
else if (!strcasecmp(var->
name,
"maximum_word_length")) {
532 ast_verb(3,
"AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] " 533 "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d]\n",
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
struct ast_variable * next
Main Channel structure associated with a channel.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
static int dfltTotalAnalysisTime
static int dfltSilenceThreshold
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
static int dfltMinimumWordLength
void ast_dsp_free(struct ast_dsp *dsp)
Convenient Signal Processing routines.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define CONFIG_STATUS_FILEINVALID
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
static int dfltMaximumWordLength
Structure for variables, used for configurations and for channel variables.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
static int dfltInitialSilence
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
int ast_unregister_application(const char *app)
Unregister an application.
#define ast_verb(level,...)
static int dfltBetweenWordsSilence
#define ast_strlen_zero(foo)
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
Configuration File Parser.
static int dfltMaximumNumberOfWords
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_config_load(filename, flags)
Load a config file.
General Asterisk PBX channel definitions.
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
#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 int dfltAfterGreetingSilence
void ast_config_destroy(struct ast_config *config)
Destroys a config.
#define ast_strdupa(s)
duplicate a string in memory from the stack
unsigned int ast_codec_samples_count(struct ast_frame *frame)
Get the number of samples contained within a frame.
Core PBX routines and definitions.
#define CONFIG_STATUS_FILEUNCHANGED
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set the minimum average magnitude threshold to determine talking by the DSP.
static int load_module(void)
Load the module.
static int dfltMaxWaitTimeForFrame
static int unload_module(void)
static void parse(struct mgcp_request *req)
Module has failed to load, may be in an inconsistent state.
static int amd_exec(struct ast_channel *chan, const char *data)
Structure used to handle boolean flags.
static void isAnsweringMachine(struct ast_channel *chan, const char *data)
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
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...
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
const char * ast_channel_name(const struct ast_channel *chan)
#define DEFAULT_SAMPLES_PER_MS
Data structure associated with a single frame of data.
enum ast_frame_type frametype
#define ASTERISK_GPL_KEY
The text the key() function should return.
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static int load_config(int reload)
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define AST_APP_ARG(name)
Define an application argument.