Asterisk - The Open Source Telephony Project GIT-master-545c459
Loading...
Searching...
No Matches
Macros | Functions | Variables
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 "asterisk/format_cache.h"
Include dependency graph for app_amd.c:

Go to the source code of this file.

Macros

#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)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void isAnsweringMachine (struct ast_channel *chan, const char *data)
 
static int load_config (int reload)
 
static int load_module (void)
 Load the module.
 
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 = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, }
 
static const char app [] = "AMD"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static ast_mutex_t config_lock
 
static int dfltAfterGreetingSilence = 800
 
static char * dfltAudioFile = NULL
 
static int dfltBetweenWordsSilence = 50
 
static int dfltGreeting = 1500
 
static int dfltInitialSilence = 2500
 
static int dfltMaximumNumberOfWords = 2
 
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 (claud.nosp@m.e.kl.nosp@m.imos@.nosp@m.ahee.nosp@m.va.co.nosp@m.m)

Definition in file app_amd.c.

Macro Definition Documentation

◆ STATE_IN_SILENCE

#define STATE_IN_SILENCE   2

Definition at line 162 of file app_amd.c.

◆ STATE_IN_WORD

#define STATE_IN_WORD   1

Definition at line 161 of file app_amd.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 631 of file app_amd.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 631 of file app_amd.c.

◆ amd_exec()

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

Definition at line 508 of file app_amd.c.

509{
510 isAnsweringMachine(chan, data);
511
512 return 0;
513}
static void isAnsweringMachine(struct ast_channel *chan, const char *data)
Definition app_amd.c:181

References isAnsweringMachine().

Referenced by load_module().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 631 of file app_amd.c.

◆ isAnsweringMachine()

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

Definition at line 181 of file app_amd.c.

182{
183 int res = 0;
184 int audioFrameCount = 0;
185 struct ast_frame *f = NULL;
186 struct ast_dsp *silenceDetector = NULL;
187 struct timeval amd_tvstart;
188 int dspsilence = 0, framelength = 0;
189 RAII_VAR(struct ast_format *, readFormat, NULL, ao2_cleanup);
190 int inInitialSilence = 1;
191 int inGreeting = 0;
192 int voiceDuration = 0;
193 int silenceDuration = 0;
194 int iTotalTime = 0;
195 int iWordsCount = 0;
196 int currentState = STATE_IN_WORD;
197 int consecutiveVoiceDuration = 0;
198 char amdCause[256] = "", amdStatus[256] = "";
199 char *parse = ast_strdupa(data);
200
201 /* Let's set the initial values of the variables that will control the algorithm.
202 The initial values are the default ones. If they are passed as arguments
203 when invoking the application, then the default values will be overwritten
204 by the ones passed as parameters. */
205 int initialSilence = dfltInitialSilence;
206 int greeting = dfltGreeting;
207 int afterGreetingSilence = dfltAfterGreetingSilence;
208 int totalAnalysisTime = dfltTotalAnalysisTime;
209 int minimumWordLength = dfltMinimumWordLength;
210 int betweenWordsSilence = dfltBetweenWordsSilence;
211 int maximumNumberOfWords = dfltMaximumNumberOfWords;
212 int silenceThreshold = dfltSilenceThreshold;
213 int maximumWordLength = dfltMaximumWordLength;
214 int maxWaitTimeForFrame = dfltMaxWaitTimeForFrame;
215 const char *audioFile = NULL;
216
218 AST_APP_ARG(argInitialSilence);
219 AST_APP_ARG(argGreeting);
220 AST_APP_ARG(argAfterGreetingSilence);
221 AST_APP_ARG(argTotalAnalysisTime);
222 AST_APP_ARG(argMinimumWordLength);
223 AST_APP_ARG(argBetweenWordsSilence);
224 AST_APP_ARG(argMaximumNumberOfWords);
225 AST_APP_ARG(argSilenceThreshold);
226 AST_APP_ARG(argMaximumWordLength);
227 AST_APP_ARG(audioFile);
228 );
229
232 audioFile = ast_strdupa(dfltAudioFile);
233 }
235
236 ast_verb(3, "AMD: %s %s %s (Fmt: %s)\n", ast_channel_name(chan),
237 S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, "(N/A)"),
238 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "(N/A)"),
240
241 /* Lets parse the arguments. */
242 if (!ast_strlen_zero(parse)) {
243 /* Some arguments have been passed. Lets parse them and overwrite the defaults. */
245 if (!ast_strlen_zero(args.argInitialSilence))
246 initialSilence = atoi(args.argInitialSilence);
247 if (!ast_strlen_zero(args.argGreeting))
248 greeting = atoi(args.argGreeting);
249 if (!ast_strlen_zero(args.argAfterGreetingSilence))
250 afterGreetingSilence = atoi(args.argAfterGreetingSilence);
251 if (!ast_strlen_zero(args.argTotalAnalysisTime))
252 totalAnalysisTime = atoi(args.argTotalAnalysisTime);
253 if (!ast_strlen_zero(args.argMinimumWordLength))
254 minimumWordLength = atoi(args.argMinimumWordLength);
255 if (!ast_strlen_zero(args.argBetweenWordsSilence))
256 betweenWordsSilence = atoi(args.argBetweenWordsSilence);
257 if (!ast_strlen_zero(args.argMaximumNumberOfWords))
258 maximumNumberOfWords = atoi(args.argMaximumNumberOfWords);
259 if (!ast_strlen_zero(args.argSilenceThreshold))
260 silenceThreshold = atoi(args.argSilenceThreshold);
261 if (!ast_strlen_zero(args.argMaximumWordLength))
262 maximumWordLength = atoi(args.argMaximumWordLength);
263 if (!ast_strlen_zero(args.audioFile)) {
264 audioFile = args.audioFile;
265 }
266 } else {
267 ast_debug(1, "AMD using the default parameters.\n");
268 }
269
270 /* Find lowest ms value, that will be max wait time for a frame */
271 if (maxWaitTimeForFrame > initialSilence)
272 maxWaitTimeForFrame = initialSilence;
273 if (maxWaitTimeForFrame > greeting)
274 maxWaitTimeForFrame = greeting;
275 if (maxWaitTimeForFrame > afterGreetingSilence)
276 maxWaitTimeForFrame = afterGreetingSilence;
277 if (maxWaitTimeForFrame > totalAnalysisTime)
278 maxWaitTimeForFrame = totalAnalysisTime;
279 if (maxWaitTimeForFrame > minimumWordLength)
280 maxWaitTimeForFrame = minimumWordLength;
281 if (maxWaitTimeForFrame > betweenWordsSilence)
282 maxWaitTimeForFrame = betweenWordsSilence;
283
284 /* Now we're ready to roll! */
285 ast_verb(3, "AMD: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
286 "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d] \n",
287 initialSilence, greeting, afterGreetingSilence, totalAnalysisTime,
288 minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold, maximumWordLength);
289
290 /* Set read format to signed linear so we get signed linear frames in */
291 readFormat = ao2_bump(ast_channel_readformat(chan));
292 if (ast_set_read_format(chan, ast_format_slin) < 0 ) {
293 ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to set to linear mode, giving up\n", ast_channel_name(chan));
294 pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
295 pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
296 return;
297 }
298
299 /* Create a new DSP that will detect the silence */
300 if (!(silenceDetector = ast_dsp_new())) {
301 ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to create silence detector :(\n", ast_channel_name(chan));
302 pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
303 pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
304 return;
305 }
306
307 /* Set silence threshold to specified value */
308 ast_dsp_set_threshold(silenceDetector, silenceThreshold);
309
310 /* Set our start time so we can tie the loop to real world time and not RTP updates */
311 amd_tvstart = ast_tvnow();
312
313 /* Optional audio file to play to caller while AMD is doing its thing. */
314 if (!ast_strlen_zero(audioFile)) {
315 ast_streamfile(chan, audioFile, ast_channel_language(chan));
316 }
317
318 /* Now we go into a loop waiting for frames from the channel */
319 while ((res = ast_waitfor(chan, 2 * maxWaitTimeForFrame)) > -1) {
320 int ms = 0;
321
322 /* Figure out how long we waited */
323 if (res >= 0) {
324 ms = 2 * maxWaitTimeForFrame - res;
325 }
326
327 /* If we fail to read in a frame, that means they hung up */
328 if (!(f = ast_read(chan))) {
329 ast_verb(3, "AMD: Channel [%s]. HANGUP\n", ast_channel_name(chan));
330 ast_debug(1, "Got hangup\n");
331 strcpy(amdStatus, "HANGUP");
332 res = 1;
333 break;
334 }
335
336 /* Check to make sure we haven't gone over our real-world timeout in case frames get stalled for whatever reason */
337 if ( (ast_tvdiff_ms(ast_tvnow(), amd_tvstart)) > totalAnalysisTime ) {
338 ast_frfree(f);
339 strcpy(amdStatus , "NOTSURE");
340 if ( audioFrameCount == 0 ) {
341 ast_verb(3, "AMD: Channel [%s]. No audio data received in [%d] seconds.\n", ast_channel_name(chan), totalAnalysisTime);
342 sprintf(amdCause , "NOAUDIODATA-%d", iTotalTime);
343 break;
344 }
345 ast_verb(3, "AMD: Channel [%s]. Timeout...\n", ast_channel_name(chan));
346 sprintf(amdCause , "TOOLONG-%d", iTotalTime);
347 break;
348 }
349
351 /* keep track of the number of audio frames we get */
352 audioFrameCount++;
353
354 /* Figure out how long the frame is in milliseconds */
355 if (f->frametype == AST_FRAME_VOICE) {
357 } else {
358 framelength = ms;
359 }
360
361 iTotalTime += framelength;
362
363 ast_debug(1, "AMD: Channel [%s] frametype [%s] iTotalTime [%d] framelength [%d] totalAnalysisTime [%d]\n",
364 ast_channel_name(chan),
365 f->frametype == AST_FRAME_VOICE ? "AST_FRAME_VOICE" : "AST_FRAME_CNG",
366 iTotalTime, framelength, totalAnalysisTime);
367
368 /* If the total time exceeds the analysis time then give up as we are not too sure */
369 if (iTotalTime >= totalAnalysisTime) {
370 ast_verb(3, "AMD: Channel [%s]. Too long...\n", ast_channel_name(chan));
371 ast_frfree(f);
372 strcpy(amdStatus , "NOTSURE");
373 sprintf(amdCause , "TOOLONG-%d", iTotalTime);
374 break;
375 }
376
377 /* Feed the frame of audio into the silence detector and see if we get a result */
378 if (f->frametype != AST_FRAME_VOICE)
379 dspsilence += framelength;
380 else {
381 dspsilence = 0;
382 ast_dsp_silence(silenceDetector, f, &dspsilence);
383 }
384
385 if (dspsilence > 0) {
386 silenceDuration = dspsilence;
387
388 if (silenceDuration >= betweenWordsSilence) {
389 if (currentState != STATE_IN_SILENCE ) {
390 ast_verb(3, "AMD: Channel [%s]. Changed state to STATE_IN_SILENCE\n", ast_channel_name(chan));
391 }
392 /* Find words less than word duration */
393 if (consecutiveVoiceDuration < minimumWordLength && consecutiveVoiceDuration > 0){
394 ast_verb(3, "AMD: Channel [%s]. Short Word Duration: %d\n", ast_channel_name(chan), consecutiveVoiceDuration);
395 }
396 currentState = STATE_IN_SILENCE;
397 consecutiveVoiceDuration = 0;
398 }
399
400 if (inInitialSilence == 1 && silenceDuration >= initialSilence) {
401 ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n",
402 ast_channel_name(chan), silenceDuration, initialSilence);
403 ast_frfree(f);
404 strcpy(amdStatus , "MACHINE");
405 sprintf(amdCause , "INITIALSILENCE-%d-%d", silenceDuration, initialSilence);
406 res = 1;
407 break;
408 }
409
410 if (silenceDuration >= afterGreetingSilence && inGreeting == 1) {
411 ast_verb(3, "AMD: Channel [%s]. HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
412 ast_channel_name(chan), silenceDuration, afterGreetingSilence);
413 ast_frfree(f);
414 strcpy(amdStatus , "HUMAN");
415 sprintf(amdCause , "HUMAN-%d-%d", silenceDuration, afterGreetingSilence);
416 res = 1;
417 break;
418 }
419
420 } else {
421 consecutiveVoiceDuration += framelength;
422 voiceDuration += framelength;
423
424 /* If I have enough consecutive voice to say that I am in a Word, I can only increment the
425 number of words if my previous state was Silence, which means that I moved into a word. */
426 if (consecutiveVoiceDuration >= minimumWordLength && currentState == STATE_IN_SILENCE) {
427 iWordsCount++;
428 ast_verb(3, "AMD: Channel [%s]. Word detected. iWordsCount:%d\n", ast_channel_name(chan), iWordsCount);
429 currentState = STATE_IN_WORD;
430 }
431 if (consecutiveVoiceDuration >= maximumWordLength){
432 ast_verb(3, "AMD: Channel [%s]. Maximum Word Length detected. [%d]\n", ast_channel_name(chan), consecutiveVoiceDuration);
433 ast_frfree(f);
434 strcpy(amdStatus , "MACHINE");
435 sprintf(amdCause , "MAXWORDLENGTH-%d", consecutiveVoiceDuration);
436 break;
437 }
438 if (iWordsCount > maximumNumberOfWords) {
439 ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: iWordsCount:%d\n", ast_channel_name(chan), iWordsCount);
440 ast_frfree(f);
441 strcpy(amdStatus , "MACHINE");
442 sprintf(amdCause , "MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords);
443 res = 1;
444 break;
445 }
446
447 if (inGreeting == 1 && voiceDuration >= greeting) {
448 ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", ast_channel_name(chan), voiceDuration, greeting);
449 ast_frfree(f);
450 strcpy(amdStatus , "MACHINE");
451 sprintf(amdCause , "LONGGREETING-%d-%d", voiceDuration, greeting);
452 res = 1;
453 break;
454 }
455
456 if (voiceDuration >= minimumWordLength ) {
457 if (silenceDuration > 0)
458 ast_verb(3, "AMD: Channel [%s]. Detected Talk, previous silence duration: %d\n", ast_channel_name(chan), silenceDuration);
459 silenceDuration = 0;
460 }
461 if (consecutiveVoiceDuration >= minimumWordLength && inGreeting == 0) {
462 /* Only go in here once to change the greeting flag when we detect the 1st word */
463 if (silenceDuration > 0)
464 ast_verb(3, "AMD: Channel [%s]. Before Greeting Time: silenceDuration: %d voiceDuration: %d\n", ast_channel_name(chan), silenceDuration, voiceDuration);
465 inInitialSilence = 0;
466 inGreeting = 1;
467 }
468
469 }
470 } else {
471 iTotalTime += ms;
472 if (iTotalTime >= totalAnalysisTime) {
473 ast_frfree(f);
474 strcpy(amdStatus , "NOTSURE");
475 sprintf(amdCause , "TOOLONG-%d", iTotalTime);
476 break;
477 }
478 }
479 ast_frfree(f);
480 }
481
482 if (!res) {
483 /* It took too long to get a frame back. Giving up. */
484 ast_verb(3, "AMD: Channel [%s]. Too long...\n", ast_channel_name(chan));
485 strcpy(amdStatus , "NOTSURE");
486 sprintf(amdCause , "TOOLONG-%d", iTotalTime);
487 }
488
489 /* Set the status and cause on the channel */
490 pbx_builtin_setvar_helper(chan , "AMDSTATUS" , amdStatus);
491 pbx_builtin_setvar_helper(chan , "AMDCAUSE" , amdCause);
492
493 /* Restore channel read format */
494 if (readFormat && ast_set_read_format(chan, readFormat))
495 ast_log(LOG_WARNING, "AMD: Unable to restore read format on '%s'\n", ast_channel_name(chan));
496
497 /* Free the DSP used to detect silence */
498 ast_dsp_free(silenceDetector);
499
500 /* If we were playing something to pass the time, stop it now. */
501 if (!ast_strlen_zero(audioFile)) {
502 ast_stopstream(chan);
503 }
504
505 return;
506}
static int dfltBetweenWordsSilence
Definition app_amd.c:170
static int dfltInitialSilence
Definition app_amd.c:165
static int dfltMaximumNumberOfWords
Definition app_amd.c:171
#define STATE_IN_SILENCE
Definition app_amd.c:162
static int dfltGreeting
Definition app_amd.c:166
static ast_mutex_t config_lock
Definition app_amd.c:176
#define STATE_IN_WORD
Definition app_amd.c:161
static int dfltMinimumWordLength
Definition app_amd.c:169
static int dfltMaximumWordLength
Definition app_amd.c:173
static int dfltTotalAnalysisTime
Definition app_amd.c:168
static char * dfltAudioFile
Definition app_amd.c:174
static int dfltAfterGreetingSilence
Definition app_amd.c:167
static int dfltMaxWaitTimeForFrame
Definition app_amd.c:179
static int dfltSilenceThreshold
Definition app_amd.c:172
#define DEFAULT_SAMPLES_PER_MS
Definition asterisk.h:49
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_log
Definition astobj2.c:42
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
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.
Definition channel.c:3166
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4278
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition channel.c:5785
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.
Definition codec.c:379
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set the minimum average magnitude threshold to determine talking by the DSP.
Definition dsp.c:1973
void ast_dsp_free(struct ast_dsp *dsp)
Definition dsp.c:1968
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
Definition dsp.c:1672
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition dsp.c:1943
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition file.c:223
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition file.c:1320
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition format.c:334
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
#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.
#define ast_frfree(fr)
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_verb(level,...)
#define LOG_WARNING
#define ast_mutex_unlock(a)
Definition lock.h:197
#define ast_mutex_lock(a)
Definition lock.h:196
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.
static struct @523 args
#define NULL
Definition resample.c:96
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
Definition dsp.c:421
Definition of a media format.
Definition format.c:43
Data structure associated with a single frame of data.
enum ast_frame_type frametype
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981

References ao2_bump, ao2_cleanup, args, AST_APP_ARG, ast_channel_caller(), ast_channel_language(), ast_channel_name(), ast_channel_readformat(), ast_channel_redirecting(), ast_codec_samples_count(), ast_debug, AST_DECLARE_APP_ARGS, ast_dsp_free(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), ast_format_get_name(), ast_format_slin, AST_FRAME_CNG, AST_FRAME_VOICE, ast_frfree, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_read(), ast_set_read_format(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor(), config_lock, DEFAULT_SAMPLES_PER_MS, dfltAfterGreetingSilence, dfltAudioFile, dfltBetweenWordsSilence, dfltGreeting, dfltInitialSilence, dfltMaximumNumberOfWords, dfltMaximumWordLength, dfltMaxWaitTimeForFrame, dfltMinimumWordLength, dfltSilenceThreshold, dfltTotalAnalysisTime, ast_frame::frametype, LOG_WARNING, NULL, pbx_builtin_setvar_helper(), RAII_VAR, S_COR, STATE_IN_SILENCE, and STATE_IN_WORD.

Referenced by amd_exec().

◆ load_config()

static int load_config ( int  reload)
static

Definition at line 515 of file app_amd.c.

516{
517 struct ast_config *cfg = NULL;
518 char *cat = NULL;
519 struct ast_variable *var = NULL;
520 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
521
523
524 if (!(cfg = ast_config_load("amd.conf", config_flags))) {
525 ast_log(LOG_ERROR, "Configuration file amd.conf missing.\n");
526 return -1;
527 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
528 return 0;
529 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
530 ast_log(LOG_ERROR, "Config file amd.conf is in an invalid format. Aborting.\n");
531 return -1;
532 }
533
534 cat = ast_category_browse(cfg, NULL);
535
536 while (cat) {
537 if (!strcasecmp(cat, "general") ) {
538 var = ast_variable_browse(cfg, cat);
539 while (var) {
540 if (!strcasecmp(var->name, "initial_silence")) {
541 dfltInitialSilence = atoi(var->value);
542 } else if (!strcasecmp(var->name, "greeting")) {
543 dfltGreeting = atoi(var->value);
544 } else if (!strcasecmp(var->name, "after_greeting_silence")) {
545 dfltAfterGreetingSilence = atoi(var->value);
546 } else if (!strcasecmp(var->name, "silence_threshold")) {
547 dfltSilenceThreshold = atoi(var->value);
548 } else if (!strcasecmp(var->name, "total_analysis_time")) {
549 dfltTotalAnalysisTime = atoi(var->value);
550 } else if (!strcasecmp(var->name, "min_word_length")) {
551 dfltMinimumWordLength = atoi(var->value);
552 } else if (!strcasecmp(var->name, "between_words_silence")) {
553 dfltBetweenWordsSilence = atoi(var->value);
554 } else if (!strcasecmp(var->name, "maximum_number_of_words")) {
555 dfltMaximumNumberOfWords = atoi(var->value);
556 } else if (!strcasecmp(var->name, "maximum_word_length")) {
557 dfltMaximumWordLength = atoi(var->value);
558 } else if (!strcasecmp(var->name, "playback_file")) {
560 if (dfltAudioFile) {
563 }
564 if (!ast_strlen_zero(var->value)) {
565 dfltAudioFile = ast_strdup(var->value);
566 }
568 } else {
569 ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n",
570 app, cat, var->name, var->lineno);
571 }
572 var = var->next;
573 }
574 }
575 cat = ast_category_browse(cfg, cat);
576 }
577
579
580 ast_verb(5, "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
581 "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d]\n",
584
585 return 0;
586}
static const char app[]
Definition app_amd.c:159
static int reload(void)
Definition app_amd.c:619
#define var
Definition ast_expr2f.c:605
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
@ THRESHOLD_SILENCE
Definition dsp.h:75
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition dsp.c:2196
#define ast_config_load(filename, flags)
Load a config file.
@ CONFIG_FLAG_FILEUNCHANGED
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition extconf.c:3324
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition extconf.c:1287
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition extconf.c:1213
#define LOG_ERROR
Structure used to handle boolean flags.
Definition utils.h:220
Structure for variables, used for configurations and for channel variables.

References app, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_dsp_get_threshold_from_settings(), ast_free, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_strdup, ast_strlen_zero(), ast_variable_browse(), ast_verb, CONFIG_FLAG_FILEUNCHANGED, config_lock, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, dfltAfterGreetingSilence, dfltAudioFile, dfltBetweenWordsSilence, dfltGreeting, dfltInitialSilence, dfltMaximumNumberOfWords, dfltMaximumWordLength, dfltMinimumWordLength, dfltSilenceThreshold, dfltTotalAnalysisTime, LOG_ERROR, LOG_WARNING, NULL, reload(), THRESHOLD_SILENCE, and var.

◆ load_module()

static int load_module ( void  )
static

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails tests return AST_MODULE_LOAD_FAILURE. If the module can not load the configuration file or other non-critical problem return AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 609 of file app_amd.c.

610{
614 }
615
617}
static int load_config(void)
static int amd_exec(struct ast_channel *chan, const char *data)
Definition app_amd.c:508
#define ast_mutex_init(pmutex)
Definition lock.h:193
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640

References amd_exec(), app, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_mutex_init, ast_register_application_xml, config_lock, and load_config().

◆ reload()

static int reload ( void  )
static

Definition at line 619 of file app_amd.c.

620{
621 if (load_config(1))
624}

References AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and load_config().

Referenced by load_config().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 588 of file app_amd.c.

589{
591 if (dfltAudioFile) {
593 }
597}
#define ast_mutex_destroy(a)
Definition lock.h:195
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:404

References app, ast_free, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, ast_unregister_application(), config_lock, and dfltAudioFile.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Answering Machine Detection Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, }
static

Definition at line 631 of file app_amd.c.

◆ app

const char app[] = "AMD"
static

Definition at line 159 of file app_amd.c.

Referenced by load_config(), load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 631 of file app_amd.c.

◆ config_lock

ast_mutex_t config_lock
static

Definition at line 176 of file app_amd.c.

Referenced by isAnsweringMachine(), load_config(), load_module(), and unload_module().

◆ dfltAfterGreetingSilence

int dfltAfterGreetingSilence = 800
static

Definition at line 167 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltAudioFile

char* dfltAudioFile = NULL
static

Definition at line 174 of file app_amd.c.

Referenced by isAnsweringMachine(), load_config(), and unload_module().

◆ dfltBetweenWordsSilence

int dfltBetweenWordsSilence = 50
static

Definition at line 170 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltGreeting

int dfltGreeting = 1500
static

Definition at line 166 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltInitialSilence

int dfltInitialSilence = 2500
static

Definition at line 165 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltMaximumNumberOfWords

int dfltMaximumNumberOfWords = 2
static

Definition at line 171 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltMaximumWordLength

int dfltMaximumWordLength = 5000
static

Definition at line 173 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltMaxWaitTimeForFrame

int dfltMaxWaitTimeForFrame = 50
static

Definition at line 179 of file app_amd.c.

Referenced by isAnsweringMachine().

◆ dfltMinimumWordLength

int dfltMinimumWordLength = 100
static

Definition at line 169 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltSilenceThreshold

int dfltSilenceThreshold = 256
static

Definition at line 172 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltTotalAnalysisTime

int dfltTotalAnalysisTime = 5000
static

Definition at line 168 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().