Wed Jan 8 2020 09:49:39

Asterisk developer's documentation


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 
29 /*** MODULEINFO
30  <support_level>extended</support_level>
31  ***/
32 
33 #include "asterisk.h"
34 
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
36 
37 #include "asterisk/module.h"
38 #include "asterisk/lock.h"
39 #include "asterisk/channel.h"
40 #include "asterisk/dsp.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/config.h"
43 #include "asterisk/app.h"
44 
45 /*** DOCUMENTATION
46  <application name="AMD" language="en_US">
47  <synopsis>
48  Attempt to detect answering machines.
49  </synopsis>
50  <syntax>
51  <parameter name="initialSilence" required="false">
52  <para>Is maximum initial silence duration before greeting.</para>
53  <para>If this is exceeded set as MACHINE</para>
54  </parameter>
55  <parameter name="greeting" required="false">
56  <para>is the maximum length of a greeting.</para>
57  <para>If this is exceeded set as MACHINE</para>
58  </parameter>
59  <parameter name="afterGreetingSilence" required="false">
60  <para>Is the silence after detecting a greeting.</para>
61  <para>If this is exceeded set as HUMAN</para>
62  </parameter>
63  <parameter name="totalAnalysis Time" required="false">
64  <para>Is the maximum time allowed for the algorithm</para>
65  <para>to decide HUMAN or MACHINE</para>
66  </parameter>
67  <parameter name="miniumWordLength" required="false">
68  <para>Is the minimum duration of Voice considered to be a word</para>
69  </parameter>
70  <parameter name="betweenWordSilence" required="false">
71  <para>Is the minimum duration of silence after a word to
72  consider the audio that follows to be a new word</para>
73  </parameter>
74  <parameter name="maximumNumberOfWords" required="false">
75  <para>Is the maximum number of words in a greeting</para>
76  <para>If this is exceeded set as MACHINE</para>
77  </parameter>
78  <parameter name="silenceThreshold" required="false">
79  <para>How long do we consider silence</para>
80  </parameter>
81  <parameter name="maximumWordLength" required="false">
82  <para>Is the maximum duration of a word to accept.</para>
83  <para>If exceeded set as MACHINE</para>
84  </parameter>
85  </syntax>
86  <description>
87  <para>This application attempts to detect answering machines at the beginning
88  of outbound calls. Simply call this application after the call
89  has been answered (outbound only, of course).</para>
90  <para>When loaded, AMD reads amd.conf and uses the parameters specified as
91  default values. Those default values get overwritten when the calling AMD
92  with parameters.</para>
93  <para>This application sets the following channel variables:</para>
94  <variablelist>
95  <variable name="AMDSTATUS">
96  <para>This is the status of the answering machine detection</para>
97  <value name="MACHINE" />
98  <value name="HUMAN" />
99  <value name="NOTSURE" />
100  <value name="HANGUP" />
101  </variable>
102  <variable name="AMDCAUSE">
103  <para>Indicates the cause that led to the conclusion</para>
104  <value name="TOOLONG">
105  Total Time.
106  </value>
107  <value name="INITIALSILENCE">
108  Silence Duration - Initial Silence.
109  </value>
110  <value name="HUMAN">
111  Silence Duration - afterGreetingSilence.
112  </value>
113  <value name="LONGGREETING">
114  Voice Duration - Greeting.
115  </value>
116  <value name="MAXWORDLENGTH">
117  Word Count - maximum number of words.
118  </value>
119  </variable>
120  </variablelist>
121  </description>
122  <see-also>
123  <ref type="application">WaitForSilence</ref>
124  <ref type="application">WaitForNoise</ref>
125  </see-also>
126  </application>
127 
128  ***/
129 
130 static const char app[] = "AMD";
131 
132 #define STATE_IN_WORD 1
133 #define STATE_IN_SILENCE 2
134 
135 /* Some default values for the algorithm parameters. These defaults will be overwritten from amd.conf */
136 static int dfltInitialSilence = 2500;
137 static int dfltGreeting = 1500;
138 static int dfltAfterGreetingSilence = 800;
139 static int dfltTotalAnalysisTime = 5000;
140 static int dfltMinimumWordLength = 100;
141 static int dfltBetweenWordsSilence = 50;
143 static int dfltSilenceThreshold = 256;
144 static int dfltMaximumWordLength = 5000; /* Setting this to a large default so it is not used unless specify it in the configs or command line */
145 
146 /* Set to the lowest ms value provided in amd.conf or application parameters */
147 static int dfltMaxWaitTimeForFrame = 50;
148 
149 static void isAnsweringMachine(struct ast_channel *chan, const char *data)
150 {
151  int res = 0;
152  struct ast_frame *f = NULL;
153  struct ast_dsp *silenceDetector = NULL;
154  int dspsilence = 0, readFormat, framelength = 0;
155  int inInitialSilence = 1;
156  int inGreeting = 0;
157  int voiceDuration = 0;
158  int silenceDuration = 0;
159  int iTotalTime = 0;
160  int iWordsCount = 0;
161  int currentState = STATE_IN_WORD;
162  int consecutiveVoiceDuration = 0;
163  char amdCause[256] = "", amdStatus[256] = "";
164  char *parse = ast_strdupa(data);
165 
166  /* Lets set the initial values of the variables that will control the algorithm.
167  The initial values are the default ones. If they are passed as arguments
168  when invoking the application, then the default values will be overwritten
169  by the ones passed as parameters. */
170  int initialSilence = dfltInitialSilence;
171  int greeting = dfltGreeting;
172  int afterGreetingSilence = dfltAfterGreetingSilence;
173  int totalAnalysisTime = dfltTotalAnalysisTime;
174  int minimumWordLength = dfltMinimumWordLength;
175  int betweenWordsSilence = dfltBetweenWordsSilence;
176  int maximumNumberOfWords = dfltMaximumNumberOfWords;
177  int silenceThreshold = dfltSilenceThreshold;
178  int maximumWordLength = dfltMaximumWordLength;
179  int maxWaitTimeForFrame = dfltMaxWaitTimeForFrame;
180 
182  AST_APP_ARG(argInitialSilence);
183  AST_APP_ARG(argGreeting);
184  AST_APP_ARG(argAfterGreetingSilence);
185  AST_APP_ARG(argTotalAnalysisTime);
186  AST_APP_ARG(argMinimumWordLength);
187  AST_APP_ARG(argBetweenWordsSilence);
188  AST_APP_ARG(argMaximumNumberOfWords);
189  AST_APP_ARG(argSilenceThreshold);
190  AST_APP_ARG(argMaximumWordLength);
191  );
192 
193  ast_verb(3, "AMD: %s %s %s (Fmt: %s)\n", chan->name,
194  S_COR(chan->caller.ani.number.valid, chan->caller.ani.number.str, "(N/A)"),
195  S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, "(N/A)"),
197 
198  /* Lets parse the arguments. */
199  if (!ast_strlen_zero(parse)) {
200  /* Some arguments have been passed. Lets parse them and overwrite the defaults. */
201  AST_STANDARD_APP_ARGS(args, parse);
202  if (!ast_strlen_zero(args.argInitialSilence))
203  initialSilence = atoi(args.argInitialSilence);
204  if (!ast_strlen_zero(args.argGreeting))
205  greeting = atoi(args.argGreeting);
206  if (!ast_strlen_zero(args.argAfterGreetingSilence))
207  afterGreetingSilence = atoi(args.argAfterGreetingSilence);
208  if (!ast_strlen_zero(args.argTotalAnalysisTime))
209  totalAnalysisTime = atoi(args.argTotalAnalysisTime);
210  if (!ast_strlen_zero(args.argMinimumWordLength))
211  minimumWordLength = atoi(args.argMinimumWordLength);
212  if (!ast_strlen_zero(args.argBetweenWordsSilence))
213  betweenWordsSilence = atoi(args.argBetweenWordsSilence);
214  if (!ast_strlen_zero(args.argMaximumNumberOfWords))
215  maximumNumberOfWords = atoi(args.argMaximumNumberOfWords);
216  if (!ast_strlen_zero(args.argSilenceThreshold))
217  silenceThreshold = atoi(args.argSilenceThreshold);
218  if (!ast_strlen_zero(args.argMaximumWordLength))
219  maximumWordLength = atoi(args.argMaximumWordLength);
220  } else {
221  ast_debug(1, "AMD using the default parameters.\n");
222  }
223 
224  /* Find lowest ms value, that will be max wait time for a frame */
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;
237 
238  /* Now we're ready to roll! */
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);
243 
244  /* Set read format to signed linear so we get signed linear frames in */
245  readFormat = chan->readformat;
246  if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0 ) {
247  ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to set to linear mode, giving up\n", chan->name );
248  pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
249  pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
250  return;
251  }
252 
253  /* Create a new DSP that will detect the silence */
254  if (!(silenceDetector = ast_dsp_new())) {
255  ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to create silence detector :(\n", chan->name );
256  pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
257  pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
258  return;
259  }
260 
261  /* Set silence threshold to specified value */
262  ast_dsp_set_threshold(silenceDetector, silenceThreshold);
263 
264  /* Now we go into a loop waiting for frames from the channel */
265  while ((res = ast_waitfor(chan, 2 * maxWaitTimeForFrame)) > -1) {
266 
267  /* If we fail to read in a frame, that means they hung up */
268  if (!(f = ast_read(chan))) {
269  ast_verb(3, "AMD: Channel [%s]. HANGUP\n", chan->name);
270  ast_debug(1, "Got hangup\n");
271  strcpy(amdStatus, "HANGUP");
272  res = 1;
273  break;
274  }
275 
277  /* If the total time exceeds the analysis time then give up as we are not too sure */
278  if (f->frametype == AST_FRAME_VOICE) {
279  framelength = (ast_codec_get_samples(f) / DEFAULT_SAMPLES_PER_MS);
280  } else {
281  framelength = 2 * maxWaitTimeForFrame;
282  }
283 
284  iTotalTime += framelength;
285  if (iTotalTime >= totalAnalysisTime) {
286  ast_verb(3, "AMD: Channel [%s]. Too long...\n", chan->name );
287  ast_frfree(f);
288  strcpy(amdStatus , "NOTSURE");
289  sprintf(amdCause , "TOOLONG-%d", iTotalTime);
290  break;
291  }
292 
293  /* Feed the frame of audio into the silence detector and see if we get a result */
294  if (f->frametype != AST_FRAME_VOICE)
295  dspsilence += 2 * maxWaitTimeForFrame;
296  else {
297  dspsilence = 0;
298  ast_dsp_silence(silenceDetector, f, &dspsilence);
299  }
300 
301  if (dspsilence > 0) {
302  silenceDuration = dspsilence;
303 
304  if (silenceDuration >= betweenWordsSilence) {
305  if (currentState != STATE_IN_SILENCE ) {
306  ast_verb(3, "AMD: Channel [%s]. Changed state to STATE_IN_SILENCE\n", chan->name);
307  }
308  /* Find words less than word duration */
309  if (consecutiveVoiceDuration < minimumWordLength && consecutiveVoiceDuration > 0){
310  ast_verb(3, "AMD: Channel [%s]. Short Word Duration: %d\n", chan->name, consecutiveVoiceDuration);
311  }
312  currentState = STATE_IN_SILENCE;
313  consecutiveVoiceDuration = 0;
314  }
315 
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);
319  ast_frfree(f);
320  strcpy(amdStatus , "MACHINE");
321  sprintf(amdCause , "INITIALSILENCE-%d-%d", silenceDuration, initialSilence);
322  res = 1;
323  break;
324  }
325 
326  if (silenceDuration >= afterGreetingSilence && inGreeting == 1) {
327  ast_verb(3, "AMD: Channel [%s]. HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
328  chan->name, silenceDuration, afterGreetingSilence);
329  ast_frfree(f);
330  strcpy(amdStatus , "HUMAN");
331  sprintf(amdCause , "HUMAN-%d-%d", silenceDuration, afterGreetingSilence);
332  res = 1;
333  break;
334  }
335 
336  } else {
337  consecutiveVoiceDuration += framelength;
338  voiceDuration += framelength;
339 
340  /* If I have enough consecutive voice to say that I am in a Word, I can only increment the
341  number of words if my previous state was Silence, which means that I moved into a word. */
342  if (consecutiveVoiceDuration >= minimumWordLength && currentState == STATE_IN_SILENCE) {
343  iWordsCount++;
344  ast_verb(3, "AMD: Channel [%s]. Word detected. iWordsCount:%d\n", chan->name, iWordsCount);
345  currentState = STATE_IN_WORD;
346  }
347  if (consecutiveVoiceDuration >= maximumWordLength){
348  ast_verb(3, "AMD: Channel [%s]. Maximum Word Length detected. [%d]\n", chan->name, consecutiveVoiceDuration);
349  ast_frfree(f);
350  strcpy(amdStatus , "MACHINE");
351  sprintf(amdCause , "MAXWORDLENGTH-%d", consecutiveVoiceDuration);
352  break;
353  }
354  if (iWordsCount >= maximumNumberOfWords) {
355  ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: iWordsCount:%d\n", chan->name, iWordsCount);
356  ast_frfree(f);
357  strcpy(amdStatus , "MACHINE");
358  sprintf(amdCause , "MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords);
359  res = 1;
360  break;
361  }
362 
363  if (inGreeting == 1 && voiceDuration >= greeting) {
364  ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", chan->name, voiceDuration, greeting);
365  ast_frfree(f);
366  strcpy(amdStatus , "MACHINE");
367  sprintf(amdCause , "LONGGREETING-%d-%d", voiceDuration, greeting);
368  res = 1;
369  break;
370  }
371 
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);
375  silenceDuration = 0;
376  }
377  if (consecutiveVoiceDuration >= minimumWordLength && inGreeting == 0) {
378  /* Only go in here once to change the greeting flag when we detect the 1st word */
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;
382  inGreeting = 1;
383  }
384 
385  }
386  }
387  ast_frfree(f);
388  }
389 
390  if (!res) {
391  /* It took too long to get a frame back. Giving up. */
392  ast_verb(3, "AMD: Channel [%s]. Too long...\n", chan->name);
393  strcpy(amdStatus , "NOTSURE");
394  sprintf(amdCause , "TOOLONG-%d", iTotalTime);
395  }
396 
397  /* Set the status and cause on the channel */
398  pbx_builtin_setvar_helper(chan , "AMDSTATUS" , amdStatus);
399  pbx_builtin_setvar_helper(chan , "AMDCAUSE" , amdCause);
400 
401  /* Restore channel read format */
402  if (readFormat && ast_set_read_format(chan, readFormat))
403  ast_log(LOG_WARNING, "AMD: Unable to restore read format on '%s'\n", chan->name);
404 
405  /* Free the DSP used to detect silence */
406  ast_dsp_free(silenceDetector);
407 
408  return;
409 }
410 
411 
412 static int amd_exec(struct ast_channel *chan, const char *data)
413 {
414  isAnsweringMachine(chan, data);
415 
416  return 0;
417 }
418 
419 static int load_config(int reload)
420 {
421  struct ast_config *cfg = NULL;
422  char *cat = NULL;
423  struct ast_variable *var = NULL;
424  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
425 
427 
428  if (!(cfg = ast_config_load("amd.conf", config_flags))) {
429  ast_log(LOG_ERROR, "Configuration file amd.conf missing.\n");
430  return -1;
431  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
432  return 0;
433  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
434  ast_log(LOG_ERROR, "Config file amd.conf is in an invalid format. Aborting.\n");
435  return -1;
436  }
437 
438  cat = ast_category_browse(cfg, NULL);
439 
440  while (cat) {
441  if (!strcasecmp(cat, "general") ) {
442  var = ast_variable_browse(cfg, cat);
443  while (var) {
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);
462 
463  } else {
464  ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n",
465  app, cat, var->name, var->lineno);
466  }
467  var = var->next;
468  }
469  }
470  cat = ast_category_browse(cfg, cat);
471  }
472 
473  ast_config_destroy(cfg);
474 
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);
479 
480  return 0;
481 }
482 
483 static int unload_module(void)
484 {
485  return ast_unregister_application(app);
486 }
487 
488 static int load_module(void)
489 {
490  if (load_config(0))
495 }
496 
497 static int reload(void)
498 {
499  if (load_config(1))
502 }
503 
504 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Answering Machine Detection Application",
505  .load = load_module,
506  .unload = unload_module,
507  .reload = reload,
508 );
Main Channel structure associated with a channel.
Definition: channel.h:742
char * str
Subscriber phone number (Malloced)
Definition: channel.h:241
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
static int dfltTotalAnalysisTime
Definition: app_amd.c:139
static int dfltSilenceThreshold
Definition: app_amd.c:143
static int dfltMinimumWordLength
Definition: app_amd.c:140
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:449
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1650
Convenient Signal Processing routines.
#define LOG_WARNING
Definition: logger.h:144
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
int lineno
Definition: config.h:87
struct ast_dsp * ast_dsp_new(void)
Definition: dsp.c:1607
static int dfltMaximumWordLength
Definition: app_amd.c:144
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define var
Definition: ast_expr2f.c:606
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
struct ast_party_redirecting redirecting
Redirecting/Diversion information.
Definition: channel.h:814
Configuration File Parser.
static int dfltInitialSilence
Definition: app_amd.c:136
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:374
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
#define ast_verb(level,...)
Definition: logger.h:243
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
static int dfltBetweenWordsSilence
Definition: app_amd.c:141
static int dfltMaximumNumberOfWords
Definition: app_amd.c:142
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 &quot;format&quot; is be...
Definition: channel.c:5301
#define STATE_IN_WORD
Definition: app_amd.c:132
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
const char * value
Definition: config.h:79
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:377
General Asterisk PBX channel definitions.
Definition: dsp.c:390
#define ast_config_load(filename, flags)
Load a config file.
Definition: config.h:170
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
#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:83
static int dfltAfterGreetingSilence
Definition: app_amd.c:138
const char * name
Definition: config.h:77
static const char app[]
Definition: app_amd.c:130
Core PBX routines and definitions.
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set threshold value for silence.
Definition: dsp.c:1655
static int reload(void)
Definition: app_amd.c:497
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
char * ast_getformatname(format_t format)
Get the name of a format.
Definition: frame.c:578
#define LOG_ERROR
Definition: logger.h:155
static struct @350 args
static int load_module(void)
Definition: app_amd.c:488
static int dfltMaxWaitTimeForFrame
Definition: app_amd.c:147
#define STATE_IN_SILENCE
Definition: app_amd.c:133
const ast_string_field name
Definition: channel.h:787
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...
Definition: logger.c:1207
static int unload_module(void)
Definition: app_amd.c:483
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
static struct ast_format f[]
Definition: format_g726.c:181
static int amd_exec(struct ast_channel *chan, const char *data)
Definition: app_amd.c:412
Structure used to handle boolean flags.
Definition: utils.h:200
static void isAnsweringMachine(struct ast_channel *chan, const char *data)
Definition: app_amd.c:149
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...
Definition: pbx.c:10546
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Return non-zero if this is silence. Updates &quot;totalsilence&quot; with the total number of seconds of silenc...
Definition: dsp.c:1355
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3539
format_t readformat
Definition: channel.h:853
int ast_codec_get_samples(struct ast_frame *f)
Returns the number of samples contained in the frame.
Definition: frame.c:1470
#define DEFAULT_SAMPLES_PER_MS
Definition: asterisk.h:42
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
Data structure associated with a single frame of data.
Definition: frame.h:142
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
enum ast_frame_type frametype
Definition: frame.h:144
struct ast_variable * next
Definition: config.h:82
#define ast_frfree(fr)
Definition: frame.h:583
static int dfltGreeting
Definition: app_amd.c:137
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:1880
static int load_config(int reload)
Definition: app_amd.c:419
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:247
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
#define CONFIG_STATUS_FILEUNCHANGED
Definition: config.h:51
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:292