Asterisk - The Open Source Telephony Project  18.5.0
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. More...
 
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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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 int dfltAfterGreetingSilence = 800
 
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 146 of file app_amd.c.

Referenced by isAnsweringMachine().

◆ STATE_IN_WORD

#define STATE_IN_WORD   1

Definition at line 145 of file app_amd.c.

Referenced by isAnsweringMachine().

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 576 of file app_amd.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 576 of file app_amd.c.

◆ amd_exec()

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

Definition at line 469 of file app_amd.c.

References isAnsweringMachine().

Referenced by load_module().

470 {
471  isAnsweringMachine(chan, data);
472 
473  return 0;
474 }
static void isAnsweringMachine(struct ast_channel *chan, const char *data)
Definition: app_amd.c:162

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 576 of file app_amd.c.

◆ isAnsweringMachine()

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

Definition at line 162 of file app_amd.c.

References ao2_bump, ao2_cleanup, args, AST_APP_ARG, ast_channel_caller(), 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_read(), ast_set_read_format(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor(), DEFAULT_SAMPLES_PER_MS, dfltAfterGreetingSilence, dfltBetweenWordsSilence, dfltGreeting, dfltInitialSilence, dfltMaximumNumberOfWords, dfltMaximumWordLength, dfltMaxWaitTimeForFrame, dfltMinimumWordLength, dfltSilenceThreshold, dfltTotalAnalysisTime, ast_frame::frametype, LOG_WARNING, NULL, parse(), pbx_builtin_setvar_helper(), RAII_VAR, S_COR, STATE_IN_SILENCE, and STATE_IN_WORD.

Referenced by amd_exec().

163 {
164  int res = 0;
165  int audioFrameCount = 0;
166  struct ast_frame *f = NULL;
167  struct ast_dsp *silenceDetector = NULL;
168  struct timeval amd_tvstart;
169  int dspsilence = 0, framelength = 0;
170  RAII_VAR(struct ast_format *, readFormat, NULL, ao2_cleanup);
171  int inInitialSilence = 1;
172  int inGreeting = 0;
173  int voiceDuration = 0;
174  int silenceDuration = 0;
175  int iTotalTime = 0;
176  int iWordsCount = 0;
177  int currentState = STATE_IN_WORD;
178  int consecutiveVoiceDuration = 0;
179  char amdCause[256] = "", amdStatus[256] = "";
180  char *parse = ast_strdupa(data);
181 
182  /* Lets set the initial values of the variables that will control the algorithm.
183  The initial values are the default ones. If they are passed as arguments
184  when invoking the application, then the default values will be overwritten
185  by the ones passed as parameters. */
186  int initialSilence = dfltInitialSilence;
187  int greeting = dfltGreeting;
188  int afterGreetingSilence = dfltAfterGreetingSilence;
189  int totalAnalysisTime = dfltTotalAnalysisTime;
190  int minimumWordLength = dfltMinimumWordLength;
191  int betweenWordsSilence = dfltBetweenWordsSilence;
192  int maximumNumberOfWords = dfltMaximumNumberOfWords;
193  int silenceThreshold = dfltSilenceThreshold;
194  int maximumWordLength = dfltMaximumWordLength;
195  int maxWaitTimeForFrame = dfltMaxWaitTimeForFrame;
196 
198  AST_APP_ARG(argInitialSilence);
199  AST_APP_ARG(argGreeting);
200  AST_APP_ARG(argAfterGreetingSilence);
201  AST_APP_ARG(argTotalAnalysisTime);
202  AST_APP_ARG(argMinimumWordLength);
203  AST_APP_ARG(argBetweenWordsSilence);
204  AST_APP_ARG(argMaximumNumberOfWords);
205  AST_APP_ARG(argSilenceThreshold);
206  AST_APP_ARG(argMaximumWordLength);
207  );
208 
209  ast_verb(3, "AMD: %s %s %s (Fmt: %s)\n", ast_channel_name(chan),
210  S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, "(N/A)"),
211  S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "(N/A)"),
213 
214  /* Lets parse the arguments. */
215  if (!ast_strlen_zero(parse)) {
216  /* Some arguments have been passed. Lets parse them and overwrite the defaults. */
217  AST_STANDARD_APP_ARGS(args, parse);
218  if (!ast_strlen_zero(args.argInitialSilence))
219  initialSilence = atoi(args.argInitialSilence);
220  if (!ast_strlen_zero(args.argGreeting))
221  greeting = atoi(args.argGreeting);
222  if (!ast_strlen_zero(args.argAfterGreetingSilence))
223  afterGreetingSilence = atoi(args.argAfterGreetingSilence);
224  if (!ast_strlen_zero(args.argTotalAnalysisTime))
225  totalAnalysisTime = atoi(args.argTotalAnalysisTime);
226  if (!ast_strlen_zero(args.argMinimumWordLength))
227  minimumWordLength = atoi(args.argMinimumWordLength);
228  if (!ast_strlen_zero(args.argBetweenWordsSilence))
229  betweenWordsSilence = atoi(args.argBetweenWordsSilence);
230  if (!ast_strlen_zero(args.argMaximumNumberOfWords))
231  maximumNumberOfWords = atoi(args.argMaximumNumberOfWords);
232  if (!ast_strlen_zero(args.argSilenceThreshold))
233  silenceThreshold = atoi(args.argSilenceThreshold);
234  if (!ast_strlen_zero(args.argMaximumWordLength))
235  maximumWordLength = atoi(args.argMaximumWordLength);
236  } else {
237  ast_debug(1, "AMD using the default parameters.\n");
238  }
239 
240  /* Find lowest ms value, that will be max wait time for a frame */
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;
253 
254  /* Now we're ready to roll! */
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);
259 
260  /* Set read format to signed linear so we get signed linear frames in */
261  readFormat = ao2_bump(ast_channel_readformat(chan));
262  if (ast_set_read_format(chan, ast_format_slin) < 0 ) {
263  ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to set to linear mode, giving up\n", ast_channel_name(chan));
264  pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
265  pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
266  return;
267  }
268 
269  /* Create a new DSP that will detect the silence */
270  if (!(silenceDetector = ast_dsp_new())) {
271  ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to create silence detector :(\n", ast_channel_name(chan));
272  pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
273  pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
274  return;
275  }
276 
277  /* Set silence threshold to specified value */
278  ast_dsp_set_threshold(silenceDetector, silenceThreshold);
279 
280  /* Set our start time so we can tie the loop to real world time and not RTP updates */
281  amd_tvstart = ast_tvnow();
282 
283  /* Now we go into a loop waiting for frames from the channel */
284  while ((res = ast_waitfor(chan, 2 * maxWaitTimeForFrame)) > -1) {
285  int ms = 0;
286 
287  /* Figure out how long we waited */
288  if (res >= 0) {
289  ms = 2 * maxWaitTimeForFrame - res;
290  }
291 
292  /* If we fail to read in a frame, that means they hung up */
293  if (!(f = ast_read(chan))) {
294  ast_verb(3, "AMD: Channel [%s]. HANGUP\n", ast_channel_name(chan));
295  ast_debug(1, "Got hangup\n");
296  strcpy(amdStatus, "HANGUP");
297  res = 1;
298  break;
299  }
300 
301  /* Check to make sure we haven't gone over our real-world timeout in case frames get stalled for whatever reason */
302  if ( (ast_tvdiff_ms(ast_tvnow(), amd_tvstart)) > totalAnalysisTime ) {
303  ast_frfree(f);
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);
308  break;
309  }
310  ast_verb(3, "AMD: Channel [%s]. Timeout...\n", ast_channel_name(chan));
311  sprintf(amdCause , "TOOLONG-%d", iTotalTime);
312  break;
313  }
314 
315  if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_CNG) {
316  /* keep track of the number of audio frames we get */
317  audioFrameCount++;
318 
319  /* Figure out how long the frame is in milliseconds */
320  if (f->frametype == AST_FRAME_VOICE) {
321  framelength = (ast_codec_samples_count(f) / DEFAULT_SAMPLES_PER_MS);
322  } else {
323  framelength = ms;
324  }
325 
326  iTotalTime += framelength;
327 
328  ast_debug(1, "AMD: Channel [%s] frametype [%s] iTotalTime [%d] framelength [%d] totalAnalysisTime [%d]\n",
329  ast_channel_name(chan),
330  f->frametype == AST_FRAME_VOICE ? "AST_FRAME_VOICE" : "AST_FRAME_CNG",
331  iTotalTime, framelength, totalAnalysisTime);
332 
333  /* If the total time exceeds the analysis time then give up as we are not too sure */
334  if (iTotalTime >= totalAnalysisTime) {
335  ast_verb(3, "AMD: Channel [%s]. Too long...\n", ast_channel_name(chan));
336  ast_frfree(f);
337  strcpy(amdStatus , "NOTSURE");
338  sprintf(amdCause , "TOOLONG-%d", iTotalTime);
339  break;
340  }
341 
342  /* Feed the frame of audio into the silence detector and see if we get a result */
343  if (f->frametype != AST_FRAME_VOICE)
344  dspsilence += framelength;
345  else {
346  dspsilence = 0;
347  ast_dsp_silence(silenceDetector, f, &dspsilence);
348  }
349 
350  if (dspsilence > 0) {
351  silenceDuration = dspsilence;
352 
353  if (silenceDuration >= betweenWordsSilence) {
354  if (currentState != STATE_IN_SILENCE ) {
355  ast_verb(3, "AMD: Channel [%s]. Changed state to STATE_IN_SILENCE\n", ast_channel_name(chan));
356  }
357  /* Find words less than word duration */
358  if (consecutiveVoiceDuration < minimumWordLength && consecutiveVoiceDuration > 0){
359  ast_verb(3, "AMD: Channel [%s]. Short Word Duration: %d\n", ast_channel_name(chan), consecutiveVoiceDuration);
360  }
361  currentState = STATE_IN_SILENCE;
362  consecutiveVoiceDuration = 0;
363  }
364 
365  if (inInitialSilence == 1 && silenceDuration >= initialSilence) {
366  ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n",
367  ast_channel_name(chan), silenceDuration, initialSilence);
368  ast_frfree(f);
369  strcpy(amdStatus , "MACHINE");
370  sprintf(amdCause , "INITIALSILENCE-%d-%d", silenceDuration, initialSilence);
371  res = 1;
372  break;
373  }
374 
375  if (silenceDuration >= afterGreetingSilence && inGreeting == 1) {
376  ast_verb(3, "AMD: Channel [%s]. HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
377  ast_channel_name(chan), silenceDuration, afterGreetingSilence);
378  ast_frfree(f);
379  strcpy(amdStatus , "HUMAN");
380  sprintf(amdCause , "HUMAN-%d-%d", silenceDuration, afterGreetingSilence);
381  res = 1;
382  break;
383  }
384 
385  } else {
386  consecutiveVoiceDuration += framelength;
387  voiceDuration += framelength;
388 
389  /* If I have enough consecutive voice to say that I am in a Word, I can only increment the
390  number of words if my previous state was Silence, which means that I moved into a word. */
391  if (consecutiveVoiceDuration >= minimumWordLength && currentState == STATE_IN_SILENCE) {
392  iWordsCount++;
393  ast_verb(3, "AMD: Channel [%s]. Word detected. iWordsCount:%d\n", ast_channel_name(chan), iWordsCount);
394  currentState = STATE_IN_WORD;
395  }
396  if (consecutiveVoiceDuration >= maximumWordLength){
397  ast_verb(3, "AMD: Channel [%s]. Maximum Word Length detected. [%d]\n", ast_channel_name(chan), consecutiveVoiceDuration);
398  ast_frfree(f);
399  strcpy(amdStatus , "MACHINE");
400  sprintf(amdCause , "MAXWORDLENGTH-%d", consecutiveVoiceDuration);
401  break;
402  }
403  if (iWordsCount > maximumNumberOfWords) {
404  ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: iWordsCount:%d\n", ast_channel_name(chan), iWordsCount);
405  ast_frfree(f);
406  strcpy(amdStatus , "MACHINE");
407  sprintf(amdCause , "MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords);
408  res = 1;
409  break;
410  }
411 
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);
414  ast_frfree(f);
415  strcpy(amdStatus , "MACHINE");
416  sprintf(amdCause , "LONGGREETING-%d-%d", voiceDuration, greeting);
417  res = 1;
418  break;
419  }
420 
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);
424  silenceDuration = 0;
425  }
426  if (consecutiveVoiceDuration >= minimumWordLength && inGreeting == 0) {
427  /* Only go in here once to change the greeting flag when we detect the 1st word */
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;
431  inGreeting = 1;
432  }
433 
434  }
435  } else {
436  iTotalTime += ms;
437  if (iTotalTime >= totalAnalysisTime) {
438  ast_frfree(f);
439  strcpy(amdStatus , "NOTSURE");
440  sprintf(amdCause , "TOOLONG-%d", iTotalTime);
441  break;
442  }
443  }
444  ast_frfree(f);
445  }
446 
447  if (!res) {
448  /* It took too long to get a frame back. Giving up. */
449  ast_verb(3, "AMD: Channel [%s]. Too long...\n", ast_channel_name(chan));
450  strcpy(amdStatus , "NOTSURE");
451  sprintf(amdCause , "TOOLONG-%d", iTotalTime);
452  }
453 
454  /* Set the status and cause on the channel */
455  pbx_builtin_setvar_helper(chan , "AMDSTATUS" , amdStatus);
456  pbx_builtin_setvar_helper(chan , "AMDCAUSE" , amdCause);
457 
458  /* Restore channel read format */
459  if (readFormat && ast_set_read_format(chan, readFormat))
460  ast_log(LOG_WARNING, "AMD: Unable to restore read format on '%s'\n", ast_channel_name(chan));
461 
462  /* Free the DSP used to detect silence */
463  ast_dsp_free(silenceDetector);
464 
465  return;
466 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
static int dfltTotalAnalysisTime
Definition: app_amd.c:152
static int dfltSilenceThreshold
Definition: app_amd.c:156
static int dfltMinimumWordLength
Definition: app_amd.c:153
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1770
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1745
static int dfltMaximumWordLength
Definition: app_amd.c:157
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
Definition of a media format.
Definition: format.c:43
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
static int dfltInitialSilence
Definition: app_amd.c:149
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
const char * args
#define NULL
Definition: resample.c:96
#define ast_verb(level,...)
Definition: logger.h:463
static int dfltBetweenWordsSilence
Definition: app_amd.c:154
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
#define ao2_bump(obj)
Definition: astobj2.h:491
static int dfltMaximumNumberOfWords
Definition: app_amd.c:155
#define STATE_IN_WORD
Definition: app_amd.c:145
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5849
#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:911
Definition: dsp.c:405
#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:85
static int dfltAfterGreetingSilence
Definition: app_amd.c:151
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
unsigned int ast_codec_samples_count(struct ast_frame *frame)
Get the number of samples contained within a frame.
Definition: codec.c:378
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:1775
static int dfltMaxWaitTimeForFrame
Definition: app_amd.c:160
#define STATE_IN_SILENCE
Definition: app_amd.c:146
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
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.
Definition: dsp.c:1483
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3171
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
const char * ast_channel_name(const struct ast_channel *chan)
#define DEFAULT_SAMPLES_PER_MS
Definition: asterisk.h:47
#define ast_frfree(fr)
Data structure associated with a single frame of data.
enum ast_frame_type frametype
static int dfltGreeting
Definition: app_amd.c:150
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ load_config()

static int load_config ( int  reload)
static

Definition at line 476 of file app_amd.c.

References app, 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, dfltAfterGreetingSilence, dfltBetweenWordsSilence, dfltGreeting, dfltInitialSilence, dfltMaximumNumberOfWords, dfltMaximumWordLength, dfltMinimumWordLength, dfltSilenceThreshold, dfltTotalAnalysisTime, ast_variable::lineno, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, NULL, THRESHOLD_SILENCE, ast_variable::value, and var.

Referenced by load_module(), and reload().

477 {
478  struct ast_config *cfg = NULL;
479  char *cat = NULL;
480  struct ast_variable *var = NULL;
481  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
482 
484 
485  if (!(cfg = ast_config_load("amd.conf", config_flags))) {
486  ast_log(LOG_ERROR, "Configuration file amd.conf missing.\n");
487  return -1;
488  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
489  return 0;
490  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
491  ast_log(LOG_ERROR, "Config file amd.conf is in an invalid format. Aborting.\n");
492  return -1;
493  }
494 
495  cat = ast_category_browse(cfg, NULL);
496 
497  while (cat) {
498  if (!strcasecmp(cat, "general") ) {
499  var = ast_variable_browse(cfg, cat);
500  while (var) {
501  if (!strcasecmp(var->name, "initial_silence")) {
502  dfltInitialSilence = atoi(var->value);
503  } else if (!strcasecmp(var->name, "greeting")) {
504  dfltGreeting = atoi(var->value);
505  } else if (!strcasecmp(var->name, "after_greeting_silence")) {
506  dfltAfterGreetingSilence = atoi(var->value);
507  } else if (!strcasecmp(var->name, "silence_threshold")) {
508  dfltSilenceThreshold = atoi(var->value);
509  } else if (!strcasecmp(var->name, "total_analysis_time")) {
510  dfltTotalAnalysisTime = atoi(var->value);
511  } else if (!strcasecmp(var->name, "min_word_length")) {
512  dfltMinimumWordLength = atoi(var->value);
513  } else if (!strcasecmp(var->name, "between_words_silence")) {
514  dfltBetweenWordsSilence = atoi(var->value);
515  } else if (!strcasecmp(var->name, "maximum_number_of_words")) {
516  dfltMaximumNumberOfWords = atoi(var->value);
517  } else if (!strcasecmp(var->name, "maximum_word_length")) {
518  dfltMaximumWordLength = atoi(var->value);
519 
520  } else {
521  ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n",
522  app, cat, var->name, var->lineno);
523  }
524  var = var->next;
525  }
526  }
527  cat = ast_category_browse(cfg, cat);
528  }
529 
530  ast_config_destroy(cfg);
531 
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",
536 
537  return 0;
538 }
struct ast_variable * next
static int dfltTotalAnalysisTime
Definition: app_amd.c:152
static int dfltSilenceThreshold
Definition: app_amd.c:156
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
static int dfltMinimumWordLength
Definition: app_amd.c:153
#define LOG_WARNING
Definition: logger.h:274
#define CONFIG_STATUS_FILEINVALID
static int dfltMaximumWordLength
Definition: app_amd.c:157
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
static int dfltInitialSilence
Definition: app_amd.c:149
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
#define ast_verb(level,...)
Definition: logger.h:463
static int dfltBetweenWordsSilence
Definition: app_amd.c:154
static int dfltMaximumNumberOfWords
Definition: app_amd.c:155
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
static int dfltAfterGreetingSilence
Definition: app_amd.c:151
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
static const char app[]
Definition: app_amd.c:143
#define CONFIG_STATUS_FILEUNCHANGED
static int reload(void)
Definition: app_amd.c:564
#define LOG_ERROR
Definition: logger.h:285
Structure used to handle boolean flags.
Definition: utils.h:199
static int dfltGreeting
Definition: app_amd.c:150
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:1996

◆ 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 555 of file app_amd.c.

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

Referenced by reload().

556 {
559  }
560 
562 }
static const char app[]
Definition: app_amd.c:143
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static int amd_exec(struct ast_channel *chan, const char *data)
Definition: app_amd.c:469
static int load_config(int reload)
Definition: app_amd.c:476
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

◆ reload()

static int reload ( void  )
static

Definition at line 564 of file app_amd.c.

References AST_MODFLAG_DEFAULT, AST_MODULE_INFO(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, AST_MODULE_SUPPORT_EXTENDED, ASTERISK_GPL_KEY, load_config(), load_module(), and unload_module().

565 {
566  if (load_config(1))
569 }
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static int load_config(int reload)
Definition: app_amd.c:476

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 540 of file app_amd.c.

References app, and ast_unregister_application().

Referenced by reload().

541 {
543 }
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
static const char app[]
Definition: app_amd.c:143

Variable Documentation

◆ __mod_info

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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, }
static

Definition at line 576 of file app_amd.c.

◆ app

const char app[] = "AMD"
static

Definition at line 143 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 576 of file app_amd.c.

◆ dfltAfterGreetingSilence

int dfltAfterGreetingSilence = 800
static

Definition at line 151 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltBetweenWordsSilence

int dfltBetweenWordsSilence = 50
static

Definition at line 154 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltGreeting

int dfltGreeting = 1500
static

Definition at line 150 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltInitialSilence

int dfltInitialSilence = 2500
static

Definition at line 149 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltMaximumNumberOfWords

int dfltMaximumNumberOfWords = 2
static

Definition at line 155 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltMaximumWordLength

int dfltMaximumWordLength = 5000
static

Definition at line 157 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltMaxWaitTimeForFrame

int dfltMaxWaitTimeForFrame = 50
static

Definition at line 160 of file app_amd.c.

Referenced by isAnsweringMachine().

◆ dfltMinimumWordLength

int dfltMinimumWordLength = 100
static

Definition at line 153 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltSilenceThreshold

int dfltSilenceThreshold = 256
static

Definition at line 156 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().

◆ dfltTotalAnalysisTime

int dfltTotalAnalysisTime = 5000
static

Definition at line 152 of file app_amd.c.

Referenced by isAnsweringMachine(), and load_config().