Asterisk - The Open Source Telephony Project  GIT-master-0190e70
app_amd.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2003 - 2006, Aheeva Technology.
5  *
6  * Claude Klimos (claude.klimos@aheeva.com)
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  *
18  * A license has been granted to Digium (via disclaimer) for the use of
19  * this code.
20  */
21 
22 /*! \file
23  *
24  * \brief Answering machine detection
25  *
26  * \author Claude Klimos (claude.klimos@aheeva.com)
27  *
28  * \ingroup applications
29  */
30 
31 /*! \li \ref app_amd.c uses the configuration file \ref amd.conf
32  * \addtogroup configuration_file Configuration Files
33  */
34 
35 /*!
36  * \page amd.conf amd.conf
37  * \verbinclude amd.conf.sample
38  */
39 
40 /*** MODULEINFO
41  <support_level>extended</support_level>
42  ***/
43 
44 #include "asterisk.h"
45 
46 #include "asterisk/module.h"
47 #include "asterisk/lock.h"
48 #include "asterisk/channel.h"
49 #include "asterisk/dsp.h"
50 #include "asterisk/pbx.h"
51 #include "asterisk/config.h"
52 #include "asterisk/app.h"
53 #include "asterisk/format_cache.h"
54 
55 /*** DOCUMENTATION
56  <application name="AMD" language="en_US">
57  <synopsis>
58  Attempt to detect answering machines.
59  </synopsis>
60  <syntax>
61  <parameter name="initialSilence" required="false">
62  <para>Is maximum initial silence duration before greeting.</para>
63  <para>If this is exceeded, the result is detection as a MACHINE</para>
64  </parameter>
65  <parameter name="greeting" required="false">
66  <para>is the maximum length of a greeting.</para>
67  <para>If this is exceeded, the result is detection as a MACHINE</para>
68  </parameter>
69  <parameter name="afterGreetingSilence" required="false">
70  <para>Is the silence after detecting a greeting.</para>
71  <para>If this is exceeded, the result is detection as a HUMAN</para>
72  </parameter>
73  <parameter name="totalAnalysis Time" required="false">
74  <para>Is the maximum time allowed for the algorithm</para>
75  <para>to decide on whether the audio represents a HUMAN, or a MACHINE</para>
76  </parameter>
77  <parameter name="miniumWordLength" required="false">
78  <para>Is the minimum duration of Voice considered to be a word</para>
79  </parameter>
80  <parameter name="betweenWordSilence" required="false">
81  <para>Is the minimum duration of silence after a word to
82  consider the audio that follows to be a new word</para>
83  </parameter>
84  <parameter name="maximumNumberOfWords" required="false">
85  <para>Is the maximum number of words in a greeting</para>
86  <para>If this is exceeded, then the result is detection as a MACHINE</para>
87  </parameter>
88  <parameter name="silenceThreshold" required="false">
89  <para>What is the average level of noise from 0 to 32767 which if not exceeded, should be considered silence?</para>
90  </parameter>
91  <parameter name="maximumWordLength" required="false">
92  <para>Is the maximum duration of a word to accept.</para>
93  <para>If exceeded, then the result is detection as a MACHINE</para>
94  </parameter>
95  </syntax>
96  <description>
97  <para>This application attempts to detect answering machines at the beginning
98  of outbound calls. Simply call this application after the call
99  has been answered (outbound only, of course).</para>
100  <para>When loaded, AMD reads amd.conf and uses the parameters specified as
101  default values. Those default values get overwritten when the calling AMD
102  with parameters.</para>
103  <para>This application sets the following channel variables:</para>
104  <variablelist>
105  <variable name="AMDSTATUS">
106  <para>This is the status of the answering machine detection</para>
107  <value name="MACHINE" />
108  <value name="HUMAN" />
109  <value name="NOTSURE" />
110  <value name="HANGUP" />
111  </variable>
112  <variable name="AMDCAUSE">
113  <para>Indicates the cause that led to the conclusion</para>
114  <value name="TOOLONG">
115  Total Time.
116  </value>
117  <value name="INITIALSILENCE">
118  Silence Duration - Initial Silence.
119  </value>
120  <value name="HUMAN">
121  Silence Duration - afterGreetingSilence.
122  </value>
123  <value name="LONGGREETING">
124  Voice Duration - Greeting.
125  </value>
126  <value name="MAXWORDLENGTH">
127  Word Length - max length of a single word.
128  </value>
129  <value name="MAXWORDS">
130  Word Count - maximum number of words.
131  </value>
132  </variable>
133  </variablelist>
134  </description>
135  <see-also>
136  <ref type="application">WaitForSilence</ref>
137  <ref type="application">WaitForNoise</ref>
138  </see-also>
139  </application>
140 
141  ***/
142 
143 static const char app[] = "AMD";
144 
145 #define STATE_IN_WORD 1
146 #define STATE_IN_SILENCE 2
147 
148 /* Some default values for the algorithm parameters. These defaults will be overwritten from amd.conf */
149 static int dfltInitialSilence = 2500;
150 static int dfltGreeting = 1500;
151 static int dfltAfterGreetingSilence = 800;
152 static int dfltTotalAnalysisTime = 5000;
153 static int dfltMinimumWordLength = 100;
154 static int dfltBetweenWordsSilence = 50;
156 static int dfltSilenceThreshold = 256;
157 static int dfltMaximumWordLength = 5000; /* Setting this to a large default so it is not used unless specify it in the configs or command line */
158 
159 /* Set to the lowest ms value provided in amd.conf or application parameters */
160 static int dfltMaxWaitTimeForFrame = 50;
161 
162 static void isAnsweringMachine(struct ast_channel *chan, const char *data)
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 }
467 
468 
469 static int amd_exec(struct ast_channel *chan, const char *data)
470 {
471  isAnsweringMachine(chan, data);
472 
473  return 0;
474 }
475 
476 static int load_config(int 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 }
539 
540 static int unload_module(void)
541 {
543 }
544 
545 /*!
546  * \brief Load the module
547  *
548  * Module loading including tests for configuration or dependencies.
549  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
550  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
551  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
552  * configuration file or other non-critical problem return
553  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
554  */
555 static int load_module(void)
556 {
559  }
560 
562 }
563 
564 static int reload(void)
565 {
566  if (load_config(1))
569 }
570 
571 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Answering Machine Detection Application",
572  .support_level = AST_MODULE_SUPPORT_EXTENDED,
573  .load = load_module,
574  .unload = unload_module,
575  .reload = reload,
576 );
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
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
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1744
Convenient Signal Processing routines.
#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
#define CONFIG_STATUS_FILEINVALID
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1719
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
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4271
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
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
const char * args
#define NULL
Definition: resample.c:96
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define ast_verb(level,...)
Definition: logger.h:455
static int dfltBetweenWordsSilence
Definition: app_amd.c:154
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
#define ao2_bump(obj)
Definition: astobj2.h:491
Configuration File Parser.
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:444
#define ast_log
Definition: astobj2.c:42
#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.
Definition: channel.c:5748
#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:851
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
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#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
static const char app[]
Definition: app_amd.c:143
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.
Definition: dsp.c:1749
static int reload(void)
Definition: app_amd.c:564
#define LOG_ERROR
Definition: logger.h:285
static int load_module(void)
Load the module.
Definition: app_amd.c:555
static int dfltMaxWaitTimeForFrame
Definition: app_amd.c:160
#define STATE_IN_SILENCE
Definition: app_amd.c:146
static int unload_module(void)
Definition: app_amd.c:540
#define ast_strlen_zero(a)
Definition: muted.c:73
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
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
Structure used to handle boolean flags.
Definition: utils.h:199
static void isAnsweringMachine(struct ast_channel *chan, const char *data)
Definition: app_amd.c:162
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.
Definition: dsp.c:1473
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3157
#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
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:1959
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
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
Media Format Cache API.
#define AST_APP_ARG(name)
Define an application argument.