37 #include "asterisk/module.h"
130 static const char app[] =
"AMD";
132 #define STATE_IN_WORD 1
133 #define STATE_IN_SILENCE 2
153 struct ast_dsp *silenceDetector = NULL;
154 int dspsilence = 0, readFormat, framelength = 0;
155 int inInitialSilence = 1;
157 int voiceDuration = 0;
158 int silenceDuration = 0;
162 int consecutiveVoiceDuration = 0;
163 char amdCause[256] =
"", amdStatus[256] =
"";
203 initialSilence = atoi(
args.argInitialSilence);
205 greeting = atoi(
args.argGreeting);
207 afterGreetingSilence = atoi(
args.argAfterGreetingSilence);
209 totalAnalysisTime = atoi(
args.argTotalAnalysisTime);
211 minimumWordLength = atoi(
args.argMinimumWordLength);
213 betweenWordsSilence = atoi(
args.argBetweenWordsSilence);
215 maximumNumberOfWords = atoi(
args.argMaximumNumberOfWords);
217 silenceThreshold = atoi(
args.argSilenceThreshold);
219 maximumWordLength = atoi(
args.argMaximumWordLength);
221 ast_debug(1,
"AMD using the default parameters.\n");
225 if (maxWaitTimeForFrame > initialSilence)
226 maxWaitTimeForFrame = initialSilence;
227 if (maxWaitTimeForFrame > greeting)
228 maxWaitTimeForFrame = greeting;
229 if (maxWaitTimeForFrame > afterGreetingSilence)
230 maxWaitTimeForFrame = afterGreetingSilence;
231 if (maxWaitTimeForFrame > totalAnalysisTime)
232 maxWaitTimeForFrame = totalAnalysisTime;
233 if (maxWaitTimeForFrame > minimumWordLength)
234 maxWaitTimeForFrame = minimumWordLength;
235 if (maxWaitTimeForFrame > betweenWordsSilence)
236 maxWaitTimeForFrame = betweenWordsSilence;
239 ast_verb(3,
"AMD: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
240 "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d] \n",
241 initialSilence, greeting, afterGreetingSilence, totalAnalysisTime,
242 minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold, maximumWordLength);
265 while ((res =
ast_waitfor(chan, 2 * maxWaitTimeForFrame)) > -1) {
271 strcpy(amdStatus,
"HANGUP");
281 framelength = 2 * maxWaitTimeForFrame;
284 iTotalTime += framelength;
285 if (iTotalTime >= totalAnalysisTime) {
286 ast_verb(3,
"AMD: Channel [%s]. Too long...\n", chan->
name );
288 strcpy(amdStatus ,
"NOTSURE");
289 sprintf(amdCause ,
"TOOLONG-%d", iTotalTime);
295 dspsilence += 2 * maxWaitTimeForFrame;
301 if (dspsilence > 0) {
302 silenceDuration = dspsilence;
304 if (silenceDuration >= betweenWordsSilence) {
306 ast_verb(3,
"AMD: Channel [%s]. Changed state to STATE_IN_SILENCE\n", chan->
name);
309 if (consecutiveVoiceDuration < minimumWordLength && consecutiveVoiceDuration > 0){
310 ast_verb(3,
"AMD: Channel [%s]. Short Word Duration: %d\n", chan->
name, consecutiveVoiceDuration);
313 consecutiveVoiceDuration = 0;
316 if (inInitialSilence == 1 && silenceDuration >= initialSilence) {
317 ast_verb(3,
"AMD: Channel [%s]. ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n",
318 chan->
name, silenceDuration, initialSilence);
320 strcpy(amdStatus ,
"MACHINE");
321 sprintf(amdCause ,
"INITIALSILENCE-%d-%d", silenceDuration, initialSilence);
326 if (silenceDuration >= afterGreetingSilence && inGreeting == 1) {
327 ast_verb(3,
"AMD: Channel [%s]. HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
328 chan->
name, silenceDuration, afterGreetingSilence);
330 strcpy(amdStatus ,
"HUMAN");
331 sprintf(amdCause ,
"HUMAN-%d-%d", silenceDuration, afterGreetingSilence);
337 consecutiveVoiceDuration += framelength;
338 voiceDuration += framelength;
342 if (consecutiveVoiceDuration >= minimumWordLength && currentState ==
STATE_IN_SILENCE) {
344 ast_verb(3,
"AMD: Channel [%s]. Word detected. iWordsCount:%d\n", chan->
name, iWordsCount);
347 if (consecutiveVoiceDuration >= maximumWordLength){
348 ast_verb(3,
"AMD: Channel [%s]. Maximum Word Length detected. [%d]\n", chan->
name, consecutiveVoiceDuration);
350 strcpy(amdStatus ,
"MACHINE");
351 sprintf(amdCause ,
"MAXWORDLENGTH-%d", consecutiveVoiceDuration);
354 if (iWordsCount >= maximumNumberOfWords) {
355 ast_verb(3,
"AMD: Channel [%s]. ANSWERING MACHINE: iWordsCount:%d\n", chan->
name, iWordsCount);
357 strcpy(amdStatus ,
"MACHINE");
358 sprintf(amdCause ,
"MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords);
363 if (inGreeting == 1 && voiceDuration >= greeting) {
364 ast_verb(3,
"AMD: Channel [%s]. ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", chan->
name, voiceDuration, greeting);
366 strcpy(amdStatus ,
"MACHINE");
367 sprintf(amdCause ,
"LONGGREETING-%d-%d", voiceDuration, greeting);
372 if (voiceDuration >= minimumWordLength ) {
373 if (silenceDuration > 0)
374 ast_verb(3,
"AMD: Channel [%s]. Detected Talk, previous silence duration: %d\n", chan->
name, silenceDuration);
377 if (consecutiveVoiceDuration >= minimumWordLength && inGreeting == 0) {
379 if (silenceDuration > 0)
380 ast_verb(3,
"AMD: Channel [%s]. Before Greeting Time: silenceDuration: %d voiceDuration: %d\n", chan->
name, silenceDuration, voiceDuration);
381 inInitialSilence = 0;
392 ast_verb(3,
"AMD: Channel [%s]. Too long...\n", chan->
name);
393 strcpy(amdStatus ,
"NOTSURE");
394 sprintf(amdCause ,
"TOOLONG-%d", iTotalTime);
434 ast_log(
LOG_ERROR,
"Config file amd.conf is in an invalid format. Aborting.\n");
441 if (!strcasecmp(cat,
"general") ) {
444 if (!strcasecmp(var->
name,
"initial_silence")) {
445 dfltInitialSilence = atoi(var->
value);
446 }
else if (!strcasecmp(var->
name,
"greeting")) {
447 dfltGreeting = atoi(var->
value);
448 }
else if (!strcasecmp(var->
name,
"after_greeting_silence")) {
449 dfltAfterGreetingSilence = atoi(var->
value);
450 }
else if (!strcasecmp(var->
name,
"silence_threshold")) {
451 dfltSilenceThreshold = atoi(var->
value);
452 }
else if (!strcasecmp(var->
name,
"total_analysis_time")) {
453 dfltTotalAnalysisTime = atoi(var->
value);
454 }
else if (!strcasecmp(var->
name,
"min_word_length")) {
455 dfltMinimumWordLength = atoi(var->
value);
456 }
else if (!strcasecmp(var->
name,
"between_words_silence")) {
457 dfltBetweenWordsSilence = atoi(var->
value);
458 }
else if (!strcasecmp(var->
name,
"maximum_number_of_words")) {
459 dfltMaximumNumberOfWords = atoi(var->
value);
460 }
else if (!strcasecmp(var->
name,
"maximum_word_length")) {
461 dfltMaximumWordLength = atoi(var->
value);
475 ast_verb(3,
"AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
476 "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d]\n",
477 dfltInitialSilence, dfltGreeting, dfltAfterGreetingSilence, dfltTotalAnalysisTime,
478 dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold, dfltMaximumWordLength);
Main Channel structure associated with a channel.
char * str
Subscriber phone number (Malloced)
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
struct ast_party_caller caller
Channel Caller ID information.
static int dfltTotalAnalysisTime
static int dfltSilenceThreshold
static int dfltMinimumWordLength
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
void ast_dsp_free(struct ast_dsp *dsp)
Convenient Signal Processing routines.
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
struct ast_dsp * ast_dsp_new(void)
static int dfltMaximumWordLength
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Structure for variables, used for configurations and for channel variables.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
struct ast_party_redirecting redirecting
Redirecting/Diversion information.
Configuration File Parser.
static int dfltInitialSilence
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
int ast_unregister_application(const char *app)
Unregister an application.
#define ast_verb(level,...)
void ast_config_destroy(struct ast_config *config)
Destroys a config.
static int dfltBetweenWordsSilence
static int dfltMaximumNumberOfWords
int ast_set_read_format(struct ast_channel *chan, format_t format)
Sets read format on channel chan Set read format for channel to whichever component of "format" is be...
#define ast_debug(level,...)
Log a DEBUG message.
struct ast_party_id ani
Automatic Number Identification (ANI)
General Asterisk PBX channel definitions.
#define ast_config_load(filename, flags)
Load a config file.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
#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
Core PBX routines and definitions.
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set threshold value for silence.
#define ast_strdupa(s)
duplicate a string in memory from the stack
char * ast_getformatname(format_t format)
Get the name of a format.
static int load_module(void)
static int dfltMaxWaitTimeForFrame
const ast_string_field name
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
static int unload_module(void)
static void parse(struct mgcp_request *req)
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)
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)
Return non-zero if this is silence. Updates "totalsilence" with the total number of seconds of silenc...
#define AST_FORMAT_SLINEAR
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
int ast_codec_get_samples(struct ast_frame *f)
Returns the number of samples contained in the frame.
#define DEFAULT_SAMPLES_PER_MS
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
Data structure associated with a single frame of data.
#define AST_APP_ARG(name)
Define an application argument.
enum ast_frame_type frametype
struct ast_variable * next
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define CONFIG_STATUS_FILEINVALID
#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.
static int load_config(int reload)
unsigned char valid
TRUE if the number information is valid/present.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
#define CONFIG_STATUS_FILEUNCHANGED
struct ast_party_number number
Subscriber phone number.