Asterisk - The Open Source Telephony Project  21.4.1
app_mf.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2021, Naveen Albert
5  *
6  * Naveen Albert <asterisk@phreaknet.org>
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 
19 /*! \file
20  *
21  * \brief MF sender and receiver applications
22  *
23  * \author Naveen Albert <asterisk@phreaknet.org>
24  *
25  * \ingroup applications
26  */
27 
28 /*** MODULEINFO
29  <support_level>extended</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 #include "asterisk/file.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/dsp.h"
38 #include "asterisk/app.h"
39 #include "asterisk/module.h"
40 #include "asterisk/indications.h"
41 #include "asterisk/conversions.h"
42 
43 /*** DOCUMENTATION
44  <application name="ReceiveMF" language="en_US">
45  <since>
46  <version>16.21.0</version>
47  <version>18.7.0</version>
48  <version>19.0.0</version>
49  </since>
50  <synopsis>
51  Detects MF digits on a channel and saves them to a variable.
52  </synopsis>
53  <syntax>
54  <parameter name="variable" required="true">
55  <para>The input digits will be stored in the given
56  <replaceable>variable</replaceable> name.</para>
57  </parameter>
58  <parameter name="timeout">
59  <para>The number of seconds to wait for all digits, if greater
60  than <literal>0</literal>. Can be floating point. Default
61  is no timeout.</para>
62  </parameter>
63  <parameter name="options">
64  <optionlist>
65  <option name="d">
66  <para>Delay audio by a frame to try to extra quelch.</para>
67  </option>
68  <option name="l">
69  <para>Receive digits even if a key pulse (KP) has not yet
70  been received. By default, this application will ignore
71  all other digits until a KP has been received.</para>
72  </option>
73  <option name="k">
74  <para>Do not return a character for the KP digit.</para>
75  </option>
76  <option name="m">
77  <para>Mute conference.</para>
78  </option>
79  <option name="n">
80  <para>Maximum number of digits, regardless of the sequence.</para>
81  </option>
82  <option name="o">
83  <para>Enable override. Repeated KPs will clear all previous digits.</para>
84  </option>
85  <option name="q">
86  <para>Quelch MF from in-band.</para>
87  </option>
88  <option name="r">
89  <para>"Radio" mode (relaxed MF).</para>
90  </option>
91  <option name="s">
92  <para>Do not return a character for ST digits.</para>
93  </option>
94  </optionlist>
95  </parameter>
96  </syntax>
97  <description>
98  <para>Reads a ST, STP, ST2P, or ST3P-terminated string of MF digits from
99  the user in to the given <replaceable>variable</replaceable>.</para>
100  <para>This application does not automatically answer the channel and
101  should be preceded with <literal>Answer</literal> or
102  <literal>Progress</literal> as needed.</para>
103  <variablelist>
104  <variable name="RECEIVEMFSTATUS">
105  <para>This is the status of the read operation.</para>
106  <value name="START" />
107  <value name="ERROR" />
108  <value name="HANGUP" />
109  <value name="MAXDIGITS" />
110  <value name="TIMEOUT" />
111  </variable>
112  </variablelist>
113  </description>
114  <see-also>
115  <ref type="application">Read</ref>
116  <ref type="application">SendMF</ref>
117  <ref type="application">ReceiveSF</ref>
118  </see-also>
119  </application>
120  <application name="SendMF" language="en_US">
121  <since>
122  <version>16.21.0</version>
123  <version>18.7.0</version>
124  <version>19.0.0</version>
125  </since>
126  <synopsis>
127  Sends arbitrary MF digits on the current or specified channel.
128  </synopsis>
129  <syntax>
130  <parameter name="digits" required="true">
131  <para>List of digits 0-9,*#ABC to send; w for a half-second pause,
132  also f or F for a flash-hook if the channel supports flash-hook,
133  h or H for 250 ms of 2600 Hz,
134  and W for a wink if the channel supports wink.</para>
135  <para>Key pulse and start digits are not included automatically.
136  * is used for KP, # for ST, A for STP, B for ST2P, and C for ST3P.</para>
137  </parameter>
138  <parameter name="timeout_ms" required="false">
139  <para>Amount of time to wait in ms between tones. (defaults to 50ms).</para>
140  </parameter>
141  <parameter name="duration_ms" required="false">
142  <para>Duration of each numeric digit (defaults to 55ms).</para>
143  </parameter>
144  <parameter name="duration_ms_kp" required="false">
145  <para>Duration of KP digits (defaults to 120ms).</para>
146  </parameter>
147  <parameter name="duration_ms_st" required="false">
148  <para>Duration of ST, STP, ST2P, and ST3P digits (defaults to 65ms).</para>
149  </parameter>
150  <parameter name="channel" required="false">
151  <para>Channel where digits will be played</para>
152  </parameter>
153  </syntax>
154  <description>
155  <para>It will send all digits or terminate if it encounters an error.</para>
156  </description>
157  <see-also>
158  <ref type="application">ReceiveMF</ref>
159  <ref type="application">SendSF</ref>
160  <ref type="application">SendDTMF</ref>
161  </see-also>
162  </application>
163  <manager name="PlayMF" language="en_US">
164  <since>
165  <version>16.21.0</version>
166  <version>18.7.0</version>
167  <version>19.0.0</version>
168  </since>
169  <synopsis>
170  Play MF digit on a specific channel.
171  </synopsis>
172  <syntax>
173  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
174  <parameter name="Channel" required="true">
175  <para>Channel name to send digit to.</para>
176  </parameter>
177  <parameter name="Digit" required="true">
178  <para>The MF digit to play.</para>
179  </parameter>
180  <parameter name="Duration" required="false">
181  <para>The duration, in milliseconds, of the digit to be played.</para>
182  </parameter>
183  </syntax>
184  <description>
185  <para>Plays an MF digit on the specified channel.</para>
186  </description>
187  </manager>
188  ***/
189 
190 enum read_option_flags {
191  OPT_DELAY = (1 << 0),
192  OPT_MUTE = (1 << 1),
193  OPT_QUELCH = (1 << 2),
194  OPT_RELAXED = (1 << 3),
195  OPT_LAX_KP = (1 << 4),
196  OPT_PROCESS = (1 << 5),
197  OPT_NO_KP = (1 << 6),
198  OPT_NO_ST = (1 << 7),
199  OPT_KP_OVERRIDE = (1 << 8),
200  OPT_MAXDIGITS = (1 << 9),
201 };
202 
203 enum {
204  OPT_ARG_MAXDIGITS,
205  /* Must be the last element */
206  OPT_ARG_ARRAY_SIZE,
207 };
208 
209 AST_APP_OPTIONS(read_app_options, {
210  AST_APP_OPTION('d', OPT_DELAY),
211  AST_APP_OPTION('l', OPT_LAX_KP),
212  AST_APP_OPTION('k', OPT_NO_KP),
213  AST_APP_OPTION('m', OPT_MUTE),
214  AST_APP_OPTION_ARG('n', OPT_MAXDIGITS, OPT_ARG_MAXDIGITS),
215  AST_APP_OPTION('o', OPT_KP_OVERRIDE),
216  AST_APP_OPTION('p', OPT_PROCESS),
217  AST_APP_OPTION('q', OPT_QUELCH),
218  AST_APP_OPTION('r', OPT_RELAXED),
219  AST_APP_OPTION('s', OPT_NO_ST),
220 });
221 
222 static const char *readmf_name = "ReceiveMF";
223 static const char sendmf_name[] = "SendMF";
224 
225 #define MF_BETWEEN_MS 50
226 #define MF_DURATION 55
227 #define MF_KP_DURATION 120
228 #define MF_ST_DURATION 65
229 
230 /*!
231  * \brief Detects MF digits on channel using DSP, terminated by ST, STP, ST2P, or ST3P
232  *
233  * \param chan channel on which to read digits
234  * \param buf Buffer in which to store digits
235  * \param buflen Size of buffer
236  * \param timeout ms to wait for all digits before giving up
237  * \param features Any additional DSP features to use
238  * \param laxkp Receive digits even if KP not received
239  * \param override Start over if we receive additional KPs
240  * \param no_kp Don't include KP in the output
241  * \param no_st Don't include start digits in the output
242  * \param maxdigits If greater than 0, only read this many digits no matter what
243  *
244  * \retval 0 if successful
245  * \retval -1 if unsuccessful (including hangup).
246  */
247 static int read_mf_digits(struct ast_channel *chan, char *buf, int buflen, int timeout, int features, int laxkp, int override, int no_kp, int no_st, int maxdigits) {
248  struct ast_dsp *dsp;
249  struct ast_frame *frame = NULL;
250  struct timeval start;
251  int remaining_time = timeout;
252  int digits_read = 0;
253  int is_start_digit = 0;
254  char *str = buf;
255  int res = 0;
256 
257  if (!(dsp = ast_dsp_new())) {
258  ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
259  pbx_builtin_setvar_helper(chan, "RECEIVEMFSTATUS", "ERROR");
260  return -1;
261  }
262  ast_dsp_set_features(dsp, DSP_FEATURE_DIGIT_DETECT);
263  ast_dsp_set_digitmode(dsp, DSP_DIGITMODE_MF | features);
264 
265  start = ast_tvnow();
266  *str = 0; /* start with empty output buffer */
267 
268  /* based on app_read and generic_fax_exec from res_fax */
269  while (timeout == 0 || remaining_time > 0) {
270  if (timeout > 0) {
271  remaining_time = ast_remaining_ms(start, timeout);
272  if (remaining_time <= 0) {
273  pbx_builtin_setvar_helper(chan, "RECEIVEMFSTATUS", "TIMEOUT");
274  break;
275  }
276  }
277  if ((maxdigits && digits_read >= maxdigits) || digits_read >= (buflen - 1)) { /* we don't have room to store any more digits (very unlikely to happen for a legitimate reason) */
278  /* This result will probably not be usable, so status should not be START */
279  pbx_builtin_setvar_helper(chan, "RECEIVEMFSTATUS", "MAXDIGITS");
280  break;
281  }
282  /* ast_waitfordigit only waits for DTMF frames, we need to do DSP on voice frames */
283  if (ast_waitfor(chan, 1000) > 0) {
284  frame = ast_read(chan);
285  if (!frame) {
286  ast_debug(1, "Channel '%s' did not return a frame; probably hung up.\n", ast_channel_name(chan));
287  pbx_builtin_setvar_helper(chan, "RECEIVEMFSTATUS", "HANGUP");
288  break;
289  } else if (frame->frametype == AST_FRAME_VOICE) {
290  frame = ast_dsp_process(chan, dsp, frame);
291  /* AST_FRAME_DTMF is used all over the DSP code for DTMF, MF, fax, etc.
292  It's used because we can use the frame to store the digit detected.
293  All this means is that we received something we care about. */
294  if (frame->frametype == AST_FRAME_DTMF) {
295  char result = frame->subclass.integer;
296  if (digits_read == 0 && !laxkp && result != '*') {
297  ast_debug(1, "Received MF digit, but no KP yet, ignoring: %c\n", result);
298  ast_frfree(frame);
299  continue;
300  }
301  ast_debug(1, "Received MF digit: %c\n", result);
302  if (result == '*') {
303  /* We received an additional KP, start over? */
304  if (override && digits_read > 0) {
305  ast_debug(1, "Received another KP, starting over\n");
306  str = buf;
307  *str = 0;
308  digits_read = 1; /* we just detected a KP */
309  } else {
310  digits_read++;
311  }
312  /* if we were told not to include the KP digit in the output string, then skip it */
313  if (no_kp) {
314  ast_frfree(frame);
315  continue;
316  }
317  } else {
318  digits_read++;
319  }
320  is_start_digit = (strchr("#", result) || strchr("A", result) || strchr("B", result) || strchr("C", result));
321  /* if we were told not to include the ST digit in the output string, then skip it */
322  if (!no_st || !is_start_digit) {
323  *str++ = result; /* won't write past allotted memory, because of buffer check at top of loop */
324  *str = 0;
325  }
326  /* we received a ST digit (ST, STP, ST2P, or ST3P), so we're done */
327  if (is_start_digit) {
328  pbx_builtin_setvar_helper(chan, "RECEIVEMFSTATUS", "START");
329  ast_frfree(frame);
330  break;
331  }
332  /* only free frame if it was a DSP match. The MF itself should not be muted. */
333  ast_frfree(frame);
334  }
335  }
336  } else {
337  pbx_builtin_setvar_helper(chan, "RECEIVEMFSTATUS", "HANGUP");
338  res = -1;
339  }
340  }
341  ast_dsp_free(dsp);
342  ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, remaining_time: %d }\n", ast_channel_name(chan), timeout, remaining_time);
343  return res;
344 }
345 
346 static int read_mf_exec(struct ast_channel *chan, const char *data)
347 {
348 #define BUFFER_SIZE 256
349  char tmp[BUFFER_SIZE] = "";
350  int to = 0;
351  double tosec;
352  struct ast_flags flags = {0};
353  char *optargs[OPT_ARG_ARRAY_SIZE];
354  char *argcopy = NULL;
355  int res, features = 0, maxdigits = 0;
356 
357  AST_DECLARE_APP_ARGS(arglist,
358  AST_APP_ARG(variable);
359  AST_APP_ARG(timeout);
360  AST_APP_ARG(options);
361  );
362 
363  if (ast_strlen_zero(data)) {
364  ast_log(LOG_WARNING, "ReceiveMF requires an argument (variable)\n");
365  return -1;
366  }
367 
368  argcopy = ast_strdupa(data);
369 
370  AST_STANDARD_APP_ARGS(arglist, argcopy);
371 
372  if (!ast_strlen_zero(arglist.options)) {
373  ast_app_parse_options(read_app_options, &flags, optargs, arglist.options);
374  }
375 
376  if (!ast_strlen_zero(arglist.timeout)) {
377  tosec = atof(arglist.timeout);
378  if (tosec <= 0) {
379  to = 0;
380  } else {
381  to = tosec * 1000.0;
382  }
383  }
384 
385  if (ast_strlen_zero(arglist.variable)) {
386  ast_log(LOG_WARNING, "Invalid! Usage: ReceiveMF(variable[,timeout][,option])\n");
387  return -1;
388  }
389  if (ast_test_flag(&flags, OPT_MAXDIGITS) && !ast_strlen_zero(optargs[OPT_ARG_MAXDIGITS])) {
390  maxdigits = atoi(optargs[OPT_ARG_MAXDIGITS]);
391  if (maxdigits <= 0) {
392  ast_log(LOG_WARNING, "Invalid maximum number of digits, ignoring: '%s'\n", optargs[OPT_ARG_MAXDIGITS]);
393  maxdigits = 0;
394  }
395  }
396 
397  if (ast_test_flag(&flags, OPT_DELAY)) {
398  features |= DSP_DIGITMODE_MUTEMAX;
399  }
400 
401  if (ast_test_flag(&flags, OPT_MUTE)) {
402  features |= DSP_DIGITMODE_MUTECONF;
403  }
404 
405  if (!ast_test_flag(&flags, OPT_QUELCH)) {
406  features |= DSP_DIGITMODE_NOQUELCH;
407  }
408 
409  if (ast_test_flag(&flags, OPT_RELAXED)) {
410  features |= DSP_DIGITMODE_RELAXDTMF;
411  }
412 
413  res = read_mf_digits(chan, tmp, BUFFER_SIZE, to, features, (ast_test_flag(&flags, OPT_LAX_KP)),
414  (ast_test_flag(&flags, OPT_KP_OVERRIDE)), (ast_test_flag(&flags, OPT_NO_KP)), (ast_test_flag(&flags, OPT_NO_ST)), maxdigits);
415  pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
416  if (!ast_strlen_zero(tmp)) {
417  ast_verb(3, "MF digits received: '%s'\n", tmp);
418  } else if (!res) { /* if channel hung up, don't print anything out */
419  ast_verb(3, "No MF digits received.\n");
420  }
421  return res;
422 }
423 
424 static int sendmf_exec(struct ast_channel *chan, const char *vdata)
425 {
426  int res;
427  char *data;
428  int dinterval = 0, duration = 0, durationkp = 0, durationst = 0;
429  struct ast_channel *chan_found = NULL;
430  struct ast_channel *chan_dest = chan;
431  struct ast_channel *chan_autoservice = NULL;
433  AST_APP_ARG(digits);
434  AST_APP_ARG(dinterval);
435  AST_APP_ARG(duration);
436  AST_APP_ARG(durationkp);
437  AST_APP_ARG(durationst);
438  AST_APP_ARG(channel);
439  );
440 
441  if (ast_strlen_zero(vdata)) {
442  ast_log(LOG_WARNING, "SendMF requires an argument\n");
443  return 0;
444  }
445 
446  data = ast_strdupa(vdata);
447  AST_STANDARD_APP_ARGS(args, data);
448 
449  if (ast_strlen_zero(args.digits)) {
450  ast_log(LOG_WARNING, "The digits argument is required (0-9,*#ABC,wf)\n");
451  return 0;
452  }
453  if (!ast_strlen_zero(args.dinterval)) {
454  ast_app_parse_timelen(args.dinterval, &dinterval, TIMELEN_MILLISECONDS);
455  }
456  if (!ast_strlen_zero(args.duration)) {
457  ast_app_parse_timelen(args.duration, &duration, TIMELEN_MILLISECONDS);
458  }
459  if (!ast_strlen_zero(args.durationkp)) {
460  ast_app_parse_timelen(args.durationkp, &durationkp, TIMELEN_MILLISECONDS);
461  }
462  if (!ast_strlen_zero(args.durationst)) {
463  ast_app_parse_timelen(args.durationst, &durationst, TIMELEN_MILLISECONDS);
464  }
465  if (!ast_strlen_zero(args.channel)) {
466  chan_found = ast_channel_get_by_name(args.channel);
467  if (!chan_found) {
468  ast_log(LOG_WARNING, "No such channel: %s\n", args.channel);
469  return 0;
470  }
471  chan_dest = chan_found;
472  if (chan_found != chan) {
473  chan_autoservice = chan;
474  }
475  }
476  res = ast_mf_stream(chan_dest, chan_autoservice, NULL, args.digits, dinterval <= 0 ? MF_BETWEEN_MS : dinterval,
477  duration <= 0 ? MF_DURATION : duration, durationkp <= 0 ? MF_KP_DURATION : durationkp,
478  durationst <= 0 ? MF_ST_DURATION : durationst, 0);
479  ast_channel_cleanup(chan_found);
480 
481  return chan_autoservice ? 0 : res;
482 }
483 
484 static int manager_play_mf(struct mansession *s, const struct message *m)
485 {
486  const char *channel = astman_get_header(m, "Channel");
487  const char *digit = astman_get_header(m, "Digit");
488  const char *duration = astman_get_header(m, "Duration");
489  struct ast_channel *chan;
490  unsigned int duration_ms = MF_DURATION;
491 
492  if (!(chan = ast_channel_get_by_name(channel))) {
493  astman_send_error(s, m, "Channel not found");
494  return 0;
495  }
496 
497  if (ast_strlen_zero(digit)) {
498  astman_send_error(s, m, "No digit specified");
499  chan = ast_channel_unref(chan);
500  return 0;
501  }
502 
503  /* Override default duration with KP or ST-specific default durations */
504  if (!strcmp(digit, "*"))
505  duration_ms = MF_KP_DURATION;
506 
507  if (!strcmp(digit, "#") || !strcmp(digit, "A") || !strcmp(digit, "B") || !strcmp(digit, "C"))
508  duration_ms = MF_ST_DURATION;
509 
510  if (!ast_strlen_zero(duration) && (sscanf(duration, "%30u", &duration_ms) != 1)) {
511  astman_send_error(s, m, "Could not convert Duration parameter");
512  chan = ast_channel_unref(chan);
513  return 0;
514  }
515 
516  ast_mf_stream(chan, NULL, NULL, digit, 0, duration_ms, duration_ms, duration_ms, 1);
517 
518  chan = ast_channel_unref(chan);
519 
520  astman_send_ack(s, m, "MF successfully queued");
521 
522  return 0;
523 }
524 
525 static int unload_module(void)
526 {
527  int res;
528 
529  res = ast_unregister_application(readmf_name);
530  res |= ast_unregister_application(sendmf_name);
531  res |= ast_manager_unregister("PlayMF");
532 
533  return res;
534 }
535 
536 static int load_module(void)
537 {
538  int res;
539 
540  res = ast_register_application_xml(readmf_name, read_mf_exec);
541  res |= ast_register_application_xml(sendmf_name, sendmf_exec);
542  res |= ast_manager_register_xml("PlayMF", EVENT_FLAG_CALL, manager_play_mf);
543 
544  return res;
545 }
546 
547 AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "MF Sender and Receiver Applications");
Tone Indication Support.
struct ast_frame * ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, struct ast_frame *inf)
Return AST_FRAME_NULL frames when there is silence, AST_FRAME_BUSY on busies, and call progress...
Definition: dsp.c:1499
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
Convenient Signal Processing routines.
#define DSP_DIGITMODE_MF
Definition: dsp.h:32
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define DSP_DIGITMODE_MUTECONF
Definition: dsp.h:35
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
static int read_mf_digits(struct ast_channel *chan, char *buf, int buflen, int timeout, int features, int laxkp, int override, int no_kp, int no_st, int maxdigits)
Detects MF digits on channel using DSP, terminated by ST, STP, ST2P, or ST3P.
Definition: app_mf.c:247
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3421
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
struct ast_frame_subclass subclass
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3050
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define DSP_DIGITMODE_RELAXDTMF
Definition: dsp.h:37
General Asterisk PBX channel definitions.
Definition: dsp.c:407
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2969
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1785
Conversion utility functions.
#define ast_debug(level,...)
Log a DEBUG message.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3066
Core PBX routines and definitions.
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8057
#define DSP_DIGITMODE_MUTEMAX
Definition: dsp.h:36
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2281
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1768
Structure used to handle boolean flags.
Definition: utils.h:199
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_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3162
Data structure associated with a single frame of data.
enum ast_frame_type frametype
#define DSP_DIGITMODE_NOQUELCH
Definition: dsp.h:34
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen defunit)
Common routine to parse time lengths, with optional time unit specifier.
Definition: main/app.c:3273
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
int ast_mf_stream(struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *chan2, const char *digits, int between, unsigned int duration, unsigned int durationkp, unsigned int durationst, int is_external)
Send a string of MF digits to a channel.
Definition: main/app.c:1113
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3389
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode)
Set digit mode.
Definition: dsp.c:1857
#define AST_APP_ARG(name)
Define an application argument.