Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
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="ReceiveSF" language="en_US">
45  <synopsis>
46  Detects SF digits on a channel and saves them to a variable.
47  </synopsis>
48  <syntax>
49  <parameter name="variable" required="true">
50  <para>The input digits will be stored in the given
51  <replaceable>variable</replaceable> name.</para>
52  </parameter>
53  <parameter name="digits" required="false">
54  <para>Maximum number of digits to read. Default is unlimited.</para>
55  </parameter>
56  <parameter name="timeout">
57  <para>The number of seconds to wait for all digits, if greater
58  than <literal>0</literal>. Can be floating point. Default
59  is no timeout.</para>
60  </parameter>
61  <parameter name="frequency">
62  <para>The frequency for which to detect pulsed digits.
63  Default is 2600 Hz.</para>
64  </parameter>
65  <parameter name="options">
66  <optionlist>
67  <option name="d">
68  <para>Delay audio by a frame to try to extra quelch.</para>
69  </option>
70  <option name="e">
71  <para>Allow receiving extra pulses 11 through 16.</para>
72  </option>
73  <option name="m">
74  <para>Mute conference.</para>
75  </option>
76  <option name="q">
77  <para>Quelch SF from in-band.</para>
78  </option>
79  <option name="r">
80  <para>"Radio" mode (relaxed SF).</para>
81  </option>
82  </optionlist>
83  </parameter>
84  </syntax>
85  <description>
86  <para>Reads SF digits from the user in to the given
87  <replaceable>variable</replaceable>.</para>
88  <para>This application does not automatically answer the channel and
89  should be preceded with <literal>Answer</literal> or
90  <literal>Progress</literal> as needed.</para>
91  <variablelist>
92  <variable name="RECEIVESFSTATUS">
93  <para>This is the status of the read operation.</para>
94  <value name="START" />
95  <value name="ERROR" />
96  <value name="HANGUP" />
97  <value name="TIMEOUT" />
98  </variable>
99  </variablelist>
100  </description>
101  <see-also>
102  <ref type="application">ReceiveMF</ref>
103  <ref type="application">SendMF</ref>
104  <ref type="application">Read</ref>
105  </see-also>
106  </application>
107  <application name="ReceiveMF" language="en_US">
108  <synopsis>
109  Detects MF digits on a channel and saves them to a variable.
110  </synopsis>
111  <syntax>
112  <parameter name="variable" required="true">
113  <para>The input digits will be stored in the given
114  <replaceable>variable</replaceable> name.</para>
115  </parameter>
116  <parameter name="timeout">
117  <para>The number of seconds to wait for all digits, if greater
118  than <literal>0</literal>. Can be floating point. Default
119  is no timeout.</para>
120  </parameter>
121  <parameter name="options">
122  <optionlist>
123  <option name="d">
124  <para>Delay audio by a frame to try to extra quelch.</para>
125  </option>
126  <option name="l">
127  <para>Receive digits even if a key pulse (KP) has not yet
128  been received. By default, this application will ignore
129  all other digits until a KP has been received.</para>
130  </option>
131  <option name="k">
132  <para>Do not return a character for the KP digit.</para>
133  </option>
134  <option name="m">
135  <para>Mute conference.</para>
136  </option>
137  <option name="o">
138  <para>Enable override. Repeated KPs will clear all previous digits.</para>
139  </option>
140  <option name="q">
141  <para>Quelch MF from in-band.</para>
142  </option>
143  <option name="r">
144  <para>"Radio" mode (relaxed MF).</para>
145  </option>
146  <option name="s">
147  <para>Do not return a character for ST digits.</para>
148  </option>
149  </optionlist>
150  </parameter>
151  </syntax>
152  <description>
153  <para>Reads a ST, STP, ST2P, or ST3P-terminated string of MF digits from
154  the user in to the given <replaceable>variable</replaceable>.</para>
155  <para>This application does not automatically answer the channel and
156  should be preceded with <literal>Answer</literal> or
157  <literal>Progress</literal> as needed.</para>
158  <variablelist>
159  <variable name="RECEIVEMFSTATUS">
160  <para>This is the status of the read operation.</para>
161  <value name="START" />
162  <value name="ERROR" />
163  <value name="HANGUP" />
164  <value name="TIMEOUT" />
165  </variable>
166  </variablelist>
167  </description>
168  <see-also>
169  <ref type="application">ReceiveSF</ref>
170  <ref type="application">SendMF</ref>
171  <ref type="application">Read</ref>
172  </see-also>
173  </application>
174  <application name="SendMF" language="en_US">
175  <synopsis>
176  Sends arbitrary MF digits on the current or specified channel.
177  </synopsis>
178  <syntax>
179  <parameter name="digits" required="true">
180  <para>List of digits 0-9,*#ABC to send; also f or F for a flash-hook
181  if the channel supports flash-hook, and w or W for a wink if the channel
182  supports wink.</para>
183  <para>Key pulse and start digits are not included automatically.
184  * is used for KP, # for ST, A for STP, B for ST2P, and C for ST3P.</para>
185  </parameter>
186  <parameter name="timeout_ms" required="false">
187  <para>Amount of time to wait in ms between tones. (defaults to 50ms).</para>
188  </parameter>
189  <parameter name="duration_ms" required="false">
190  <para>Duration of each numeric digit (defaults to 55ms).</para>
191  </parameter>
192  <parameter name="duration_ms_kp" required="false">
193  <para>Duration of KP digits (defaults to 120ms).</para>
194  </parameter>
195  <parameter name="duration_ms_st" required="false">
196  <para>Duration of ST, STP, ST2P, and ST3P digits (defaults to 65ms).</para>
197  </parameter>
198  <parameter name="channel" required="false">
199  <para>Channel where digits will be played</para>
200  </parameter>
201  </syntax>
202  <description>
203  <para>It will send all digits or terminate if it encounters an error.</para>
204  </description>
205  <see-also>
206  <ref type="application">ReceiveMF</ref>
207  <ref type="application">SendDTMF</ref>
208  </see-also>
209  </application>
210  <manager name="PlayMF" language="en_US">
211  <synopsis>
212  Play MF digit on a specific channel.
213  </synopsis>
214  <syntax>
215  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
216  <parameter name="Channel" required="true">
217  <para>Channel name to send digit to.</para>
218  </parameter>
219  <parameter name="Digit" required="true">
220  <para>The MF digit to play.</para>
221  </parameter>
222  <parameter name="Duration" required="false">
223  <para>The duration, in milliseconds, of the digit to be played.</para>
224  </parameter>
225  </syntax>
226  <description>
227  <para>Plays an MF digit on the specified channel.</para>
228  </description>
229  </manager>
230  ***/
231 
233  OPT_DELAY = (1 << 0),
234  OPT_MUTE = (1 << 1),
235  OPT_QUELCH = (1 << 2),
236  OPT_RELAXED = (1 << 3),
237  OPT_LAX_KP = (1 << 4),
238  OPT_PROCESS = (1 << 5),
239  OPT_NO_KP = (1 << 6),
240  OPT_NO_ST = (1 << 7),
241  OPT_KP_OVERRIDE = (1 << 8),
242  OPT_EXTRAPULSES = (1 << 9),
243 };
244 
247  AST_APP_OPTION('e', OPT_EXTRAPULSES), /* SF only */
248  AST_APP_OPTION('l', OPT_LAX_KP), /* MF only */
249  AST_APP_OPTION('k', OPT_NO_KP), /* MF only */
250  AST_APP_OPTION('m', OPT_MUTE),
251  AST_APP_OPTION('o', OPT_KP_OVERRIDE), /* MF only */
252  AST_APP_OPTION('p', OPT_PROCESS), /* MF only */
255  AST_APP_OPTION('s', OPT_NO_ST), /* MF only */
256 });
257 
258 static char *readmf_name = "ReceiveMF";
259 static char *readsf_name = "ReceiveSF";
260 static const char sendmf_name[] = "SendMF";
261 
262 #define MF_BETWEEN_MS 50
263 #define MF_DURATION 55
264 #define MF_KP_DURATION 120
265 #define MF_ST_DURATION 65
266 
267 /*!
268  * \brief Detects MF digits on channel using DSP, terminated by ST, STP, ST2P, or ST3P
269  * \return 0 if successful, -1 if unsuccessful.
270  * \param chan channel on which to read digits
271  * \param str buffer in which to store digits
272  * \param timeout ms to wait for all digits before giving up
273  */
274 static int read_mf_digits(struct ast_channel *chan, char *buf, int timeout, int features, int laxkp, int override, int no_kp, int no_st) {
275  struct ast_dsp *dsp;
276  struct ast_frame *frame = NULL;
277  struct timeval start;
278  int remaining_time = timeout;
279  int digits_read = 0;
280  int is_start_digit = 0;
281  char *str = buf;
282 
283  if (!(dsp = ast_dsp_new())) {
284  ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
285  pbx_builtin_setvar_helper(chan, "RECEIVEMFSTATUS", "ERROR");
286  return -1;
287  }
289  ast_dsp_set_digitmode(dsp, DSP_DIGITMODE_MF | features);
290 
291  start = ast_tvnow();
292  *str = 0; /* start with empty output buffer */
293 
294  /* based on app_read and generic_fax_exec from res_fax */
295  while (timeout == 0 || remaining_time > 0) {
296  if (timeout > 0) {
297  remaining_time = ast_remaining_ms(start, timeout);
298  if (remaining_time <= 0) {
299  pbx_builtin_setvar_helper(chan, "RECEIVEMFSTATUS", "TIMEOUT");
300  break;
301  }
302  }
303  /* ast_waitfordigit only waits for DTMF frames, we need to do DSP on voice frames */
304  if (ast_waitfor(chan, 1000) > 0) {
305  frame = ast_read(chan);
306  if (!frame) {
307  ast_debug(1, "Channel '%s' did not return a frame; probably hung up.\n", ast_channel_name(chan));
308  pbx_builtin_setvar_helper(chan, "RECEIVEMFSTATUS", "HANGUP");
309  break;
310  } else if (frame->frametype == AST_FRAME_VOICE) {
311  frame = ast_dsp_process(chan, dsp, frame);
312  /* AST_FRAME_DTMF is used all over the DSP code for DTMF, MF, fax, etc.
313  It's used because we can use the frame to store the digit detected.
314  All this means is that we received something we care about. */
315  if (frame->frametype == AST_FRAME_DTMF) {
316  char result = frame->subclass.integer;
317  if (digits_read == 0 && !laxkp && result != '*') {
318  ast_debug(1, "Received MF digit, but no KP yet, ignoring: %c\n", result);
319  continue;
320  }
321  ast_debug(1, "Received MF digit: %c\n", result);
322  digits_read++;
323  if (result == '*') {
324  /* We received an additional KP, start over? */
325  if (override && digits_read > 0) {
326  ast_debug(1, "Received another KP, starting over\n");
327  str = buf;
328  *str = 0;
329  digits_read = 1; /* we just detected a KP */
330  }
331  /* if we were told not to include the ST digit in the output string, then skip it */
332  if (no_kp) {
333  continue;
334  }
335  }
336  is_start_digit = (strchr("#", result) || strchr("A", result) || strchr("B", result) || strchr("C", result));
337  /* if we were told not to include the ST digit in the output string, then skip it */
338  if (!no_st || !is_start_digit) {
339  *str++ = result;
340  *str = 0;
341  }
342  /* we received a ST digit (ST, STP, ST2P, or ST3P), so we're done */
343  if (is_start_digit) {
344  pbx_builtin_setvar_helper(chan, "RECEIVEMFSTATUS", "START");
345  break;
346  }
347  }
348  }
349  } else {
350  pbx_builtin_setvar_helper(chan, "RECEIVEMFSTATUS", "HANGUP");
351  }
352  }
353  ast_dsp_free(dsp);
354  ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, remaining_time: %d }\n", ast_channel_name(chan), timeout, remaining_time);
355  return 0;
356 }
357 
358 static int read_sf_digits(struct ast_channel *chan, char *buf, int timeout, int maxdigits, int freq, int features, int extrapulses) {
359  struct ast_dsp *dsp;
360  struct ast_frame *frame = NULL;
361  struct timeval start, pulsetimer, digittimer;
362  int remaining_time = timeout;
363  char *str = buf;
364  int hits = 0, digits_read = 0;
365  unsigned short int sf_on = 0;
366 
367  if (!(dsp = ast_dsp_new())) {
368  ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
369  pbx_builtin_setvar_helper(chan, "RECEIVEMFSTATUS", "ERROR");
370  return -1;
371  }
373  ast_dsp_set_freqmode(dsp, freq, 60, 16, 0);
374 
375  start = ast_tvnow();
376  *str = 0; /* start with empty output buffer */
377 
378  while (timeout == 0 || remaining_time > 0) {
379  if (timeout > 0) {
380  remaining_time = ast_remaining_ms(start, timeout);
381  if (remaining_time <= 0) {
382  pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "TIMEOUT");
383  break;
384  }
385  }
386  if (ast_waitfor(chan, 1000) > 0) {
387  frame = ast_read(chan);
388  if (!frame) {
389  ast_debug(1, "Channel '%s' did not return a frame; probably hung up.\n", ast_channel_name(chan));
390  pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "HANGUP");
391  break;
392  } else if (frame->frametype == AST_FRAME_VOICE) {
393  frame = ast_dsp_process(chan, dsp, frame);
394  if (frame->frametype == AST_FRAME_DTMF) {
395  char result = frame->subclass.integer;
396  if (result == 'q') {
397  sf_on = 1;
398  pulsetimer = ast_tvnow(); /* reset the pulse timer */
399  /* now, we need at least a 40ms pause to register the pulse */
400  }
401  } else {
402  if (sf_on) {
403  int timeleft = ast_remaining_ms(pulsetimer, 40);
404  if (timeleft <= 0) {
405  sf_on = 0;
406  /* The pulse needs to end no more than 75ms after we detected it */
407  if (timeleft > -75) {
408  hits++;
409  digittimer = ast_tvnow(); /* reset the digit timer */
410  ast_debug(5, "Detected SF pulse (pulse #%d)\n", hits);
411  } else {
412  ast_debug(5, "SF noise, ignoring, time elapsed was %d ms\n", timeleft);
413  }
414  }
415  } else if (hits > 0 && ast_remaining_ms(digittimer, 100) <= 0) {
416  /* has the digit finished? */
417  ast_debug(2, "Received SF digit: %d\n", hits);
418  digits_read++;
419  if (hits > 10) {
420  if (extrapulses) {
421  /* dahdi-base.c translates 11 to * and 12 to # */
422  if (hits == 11)
423  hits = '*';
424  else if (hits == 12)
425  hits = '#';
426  else if (hits == 13)
427  hits = 'D';
428  else if (hits == 14)
429  hits = 'C';
430  else if (hits == 15)
431  hits = 'B';
432  else if (hits == 16)
433  hits = 'A';
434  else {
435  ast_debug(3, "Got SF pulse digit %d, is someone playing with the phone?\n", hits);
436  hits = 'A';
437  }
438  *str++ = hits;
439  } else {
440  ast_debug(2, "Got more than 10 pulses, truncating to 10\n");
441  hits = 0; /* 10 dial pulses = digit 0 */
442  *str++ = hits + '0';
443  }
444  } else {
445  if (hits == 10) {
446  hits = 0; /* 10 dial pulses = digit 0 */
447  }
448  *str++ = hits + '0';
449  }
450  *str = 0;
451  hits = 0;
452  if (maxdigits > 0 && digits_read >= maxdigits) {
453  pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "START");
454  break;
455  }
456  }
457  }
458  }
459  } else {
460  pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "HANGUP");
461  }
462  }
463  ast_dsp_free(dsp);
464  ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, remaining_time: %d }\n", ast_channel_name(chan), timeout, remaining_time);
465  return 0;
466 }
467 
468 /*
469 add SendSF application here
470 */
471 
472 static int read_sf_exec(struct ast_channel *chan, const char *data)
473 {
474  char tmp[256] = "";
475  double tosec;
476  struct ast_flags flags = {0};
477  char *argcopy = NULL;
478  int features = 0, digits = 0, to = 0, freq = 2600;
479 
480  AST_DECLARE_APP_ARGS(arglist,
481  AST_APP_ARG(variable);
482  AST_APP_ARG(digits);
484  AST_APP_ARG(freq);
486  );
487 
488  if (ast_strlen_zero(data)) {
489  ast_log(LOG_WARNING, "ReceiveSF requires an argument (variable)\n");
490  return -1;
491  }
492 
493  argcopy = ast_strdupa(data);
494 
495  AST_STANDARD_APP_ARGS(arglist, argcopy);
496 
497  if (!ast_strlen_zero(arglist.options)) {
498  ast_app_parse_options(read_app_options, &flags, NULL, arglist.options);
499  }
500 
501  if (!ast_strlen_zero(arglist.timeout)) {
502  tosec = atof(arglist.timeout);
503  if (tosec <= 0) {
504  to = 0;
505  } else {
506  to = tosec * 1000.0;
507  }
508  }
509 
510  if (!ast_strlen_zero(arglist.digits) && (ast_str_to_int(arglist.digits, &digits) || digits <= 0)) {
511  ast_log(LOG_WARNING, "Invalid number of digits: %s\n", arglist.digits);
512  return -1;
513  }
514 
515  if (!ast_strlen_zero(arglist.freq) && (ast_str_to_int(arglist.freq, &freq) || freq <= 0)) {
516  ast_log(LOG_WARNING, "Invalid freq: %s\n", arglist.freq);
517  return -1;
518  }
519 
520  if (ast_strlen_zero(arglist.variable)) {
521  ast_log(LOG_WARNING, "Invalid! Usage: ReceiveSF(variable[,timeout][,option])\n");
522  return -1;
523  }
524 
525  if (ast_test_flag(&flags, OPT_DELAY)) {
526  features |= DSP_DIGITMODE_MUTEMAX;
527  }
528 
529  if (ast_test_flag(&flags, OPT_MUTE)) {
530  features |= DSP_DIGITMODE_MUTECONF;
531  }
532 
533  if (!ast_test_flag(&flags, OPT_QUELCH)) {
534  features |= DSP_DIGITMODE_NOQUELCH;
535  }
536 
537  if (ast_test_flag(&flags, OPT_RELAXED)) {
538  features |= DSP_DIGITMODE_RELAXDTMF;
539  }
540 
541  read_sf_digits(chan, tmp, to, digits, freq, features, ast_test_flag(&flags, OPT_EXTRAPULSES));
542  pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
543  if (!ast_strlen_zero(tmp)) {
544  ast_verb(3, "MF digits received: '%s'\n", tmp);
545  } else {
546  ast_verb(3, "No MF digits received.\n");
547  }
548  return 0;
549 }
550 
551 static int read_mf_exec(struct ast_channel *chan, const char *data)
552 {
553  char tmp[256] = "";
554  int to = 0;
555  double tosec;
556  struct ast_flags flags = {0};
557  char *argcopy = NULL;
558  int features = 0;
559 
560  AST_DECLARE_APP_ARGS(arglist,
561  AST_APP_ARG(variable);
564  );
565 
566  if (ast_strlen_zero(data)) {
567  ast_log(LOG_WARNING, "ReceiveMF requires an argument (variable)\n");
568  return -1;
569  }
570 
571  argcopy = ast_strdupa(data);
572 
573  AST_STANDARD_APP_ARGS(arglist, argcopy);
574 
575  if (!ast_strlen_zero(arglist.options)) {
576  ast_app_parse_options(read_app_options, &flags, NULL, arglist.options);
577  }
578 
579  if (!ast_strlen_zero(arglist.timeout)) {
580  tosec = atof(arglist.timeout);
581  if (tosec <= 0) {
582  to = 0;
583  } else {
584  to = tosec * 1000.0;
585  }
586  }
587 
588  if (ast_strlen_zero(arglist.variable)) {
589  ast_log(LOG_WARNING, "Invalid! Usage: ReceiveMF(variable[,timeout][,option])\n");
590  return -1;
591  }
592 
593  if (ast_test_flag(&flags, OPT_DELAY)) {
594  features |= DSP_DIGITMODE_MUTEMAX;
595  }
596 
597  if (ast_test_flag(&flags, OPT_MUTE)) {
598  features |= DSP_DIGITMODE_MUTECONF;
599  }
600 
601  if (!ast_test_flag(&flags, OPT_QUELCH)) {
602  features |= DSP_DIGITMODE_NOQUELCH;
603  }
604 
605  if (ast_test_flag(&flags, OPT_RELAXED)) {
606  features |= DSP_DIGITMODE_RELAXDTMF;
607  }
608 
609  read_mf_digits(chan, tmp, to, features, (ast_test_flag(&flags, OPT_LAX_KP)),
610  (ast_test_flag(&flags, OPT_KP_OVERRIDE)), (ast_test_flag(&flags, OPT_NO_KP)), (ast_test_flag(&flags, OPT_NO_ST)));
611  pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
612  if (!ast_strlen_zero(tmp)) {
613  ast_verb(3, "MF digits received: '%s'\n", tmp);
614  } else {
615  ast_verb(3, "No MF digits received.\n");
616  }
617  return 0;
618 }
619 
620 static int sendmf_exec(struct ast_channel *chan, const char *vdata)
621 {
622  int res;
623  char *data;
624  int dinterval = 0, duration = 0, durationkp = 0, durationst = 0;
625  struct ast_channel *chan_found = NULL;
626  struct ast_channel *chan_dest = chan;
627  struct ast_channel *chan_autoservice = NULL;
629  AST_APP_ARG(digits);
630  AST_APP_ARG(dinterval);
631  AST_APP_ARG(duration);
632  AST_APP_ARG(durationkp);
633  AST_APP_ARG(durationst);
635  );
636 
637  if (ast_strlen_zero(vdata)) {
638  ast_log(LOG_WARNING, "SendMF requires an argument\n");
639  return 0;
640  }
641 
642  data = ast_strdupa(vdata);
644 
645  if (ast_strlen_zero(args.digits)) {
646  ast_log(LOG_WARNING, "The digits argument is required (0-9,*#ABC,wf)\n");
647  return 0;
648  }
649  if (!ast_strlen_zero(args.dinterval)) {
650  ast_app_parse_timelen(args.dinterval, &dinterval, TIMELEN_MILLISECONDS);
651  }
652  if (!ast_strlen_zero(args.duration)) {
653  ast_app_parse_timelen(args.duration, &duration, TIMELEN_MILLISECONDS);
654  }
655  if (!ast_strlen_zero(args.durationkp)) {
656  ast_app_parse_timelen(args.durationkp, &durationkp, TIMELEN_MILLISECONDS);
657  }
658  if (!ast_strlen_zero(args.durationst)) {
659  ast_app_parse_timelen(args.durationst, &durationst, TIMELEN_MILLISECONDS);
660  }
661  if (!ast_strlen_zero(args.channel)) {
662  chan_found = ast_channel_get_by_name(args.channel);
663  if (!chan_found) {
664  ast_log(LOG_WARNING, "No such channel: %s\n", args.channel);
665  return 0;
666  }
667  chan_dest = chan_found;
668  if (chan_found != chan) {
669  chan_autoservice = chan;
670  }
671  }
672  res = ast_mf_stream(chan_dest, chan_autoservice, args.digits, dinterval <= 0 ? MF_BETWEEN_MS : dinterval,
673  duration <= 0 ? MF_DURATION : duration, durationkp <= 0 ? MF_KP_DURATION : durationkp,
674  durationst <= 0 ? MF_ST_DURATION : durationst, 0);
675  if (chan_found) {
676  ast_channel_unref(chan_found);
677  }
678 
679  return chan_autoservice ? 0 : res;
680 }
681 
682 static int manager_play_mf(struct mansession *s, const struct message *m)
683 {
684  const char *channel = astman_get_header(m, "Channel");
685  const char *digit = astman_get_header(m, "Digit");
686  const char *duration = astman_get_header(m, "Duration");
687  struct ast_channel *chan;
688  unsigned int duration_ms = MF_DURATION;
689 
690  if (!(chan = ast_channel_get_by_name(channel))) {
691  astman_send_error(s, m, "Channel not found");
692  return 0;
693  }
694 
695  if (ast_strlen_zero(digit)) {
696  astman_send_error(s, m, "No digit specified");
697  chan = ast_channel_unref(chan);
698  return 0;
699  }
700 
701  /* Override default duration with KP or ST-specific default durations */
702  if (!strcmp(digit, "*"))
703  duration_ms = MF_KP_DURATION;
704 
705  if (!strcmp(digit, "#") || !strcmp(digit, "A") || !strcmp(digit, "B") || !strcmp(digit, "C"))
706  duration_ms = MF_ST_DURATION;
707 
708  if (!ast_strlen_zero(duration) && (sscanf(duration, "%30u", &duration_ms) != 1)) {
709  astman_send_error(s, m, "Could not convert Duration parameter");
710  chan = ast_channel_unref(chan);
711  return 0;
712  }
713 
714  ast_mf_stream(chan, NULL, digit, 0, duration_ms, duration_ms, duration_ms, 1);
715 
716  chan = ast_channel_unref(chan);
717 
718  astman_send_ack(s, m, "MF successfully queued");
719 
720  return 0;
721 }
722 
723 static int unload_module(void)
724 {
725  int res;
726 
727  res = ast_unregister_application(readsf_name);
728  res |= ast_unregister_application(readmf_name);
729  res |= ast_unregister_application(sendmf_name);
730  res |= ast_manager_unregister("PlayMF");
731 
732  return res;
733 }
734 
735 static int load_module(void)
736 {
737  int res;
738 
739  res = ast_register_application_xml(readsf_name, read_sf_exec);
740  res |= ast_register_application_xml(readmf_name, read_mf_exec);
741  res |= ast_register_application_xml(sendmf_name, sendmf_exec);
743 
744  return res;
745 }
746 
747 AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "MF Sender and Receiver Applications");
Tone Indication Support.
char digit
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:1494
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
static int unload_module(void)
Definition: app_mf.c:723
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
#define ast_test_flag(p, flag)
Definition: utils.h:63
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1770
#define DSP_FEATURE_DIGIT_DETECT
Definition: dsp.h:28
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Convenient Signal Processing routines.
#define DSP_DIGITMODE_MF
Definition: dsp.h:32
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define DSP_DIGITMODE_MUTECONF
Definition: dsp.h:35
#define MF_BETWEEN_MS
Definition: app_mf.c:262
#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 timeout
Definition: cdr_mysql.c:86
static int tmp()
Definition: bt_open.c:389
static int load_module(void)
Definition: app_mf.c:735
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
#define EVENT_FLAG_CALL
Definition: manager.h:72
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
Definition: muted.c:95
const char * str
Definition: app_jack.c:147
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
const char * args
#define MF_DURATION
Definition: app_mf.c:263
#define MF_KP_DURATION
Definition: app_mf.c:264
#define NULL
Definition: resample.c:96
#define AST_FRAME_DTMF
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define ast_verb(level,...)
Definition: logger.h:463
struct ast_frame_subclass subclass
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
static const struct ast_app_option read_app_options[128]
Definition: app_mf.c:256
#define DSP_DIGITMODE_RELAXDTMF
Definition: dsp.h:37
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "MF Sender and Receiver Applications")
static char * readmf_name
Definition: app_mf.c:258
General Asterisk PBX channel definitions.
Definition: dsp.c:405
static int read_mf_digits(struct ast_channel *chan, char *buf, int timeout, int features, int laxkp, int override, int no_kp, int no_st)
Detects MF digits on channel using DSP, terminated by ST, STP, ST2P, or ST3P.
Definition: app_mf.c:274
In case you didn&#39;t read that giant block of text above the mansession_session struct, the struct 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:1625
Conversion utility functions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
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:2906
Core PBX routines and definitions.
#define MF_ST_DURATION
Definition: app_mf.c:265
int ast_str_to_int(const char *str, int *res)
Convert the given string to a signed integer.
Definition: conversions.c:44
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7258
#define DSP_DIGITMODE_MUTEMAX
Definition: dsp.h:36
static char * readsf_name
Definition: app_mf.c:259
static int read_mf_exec(struct ast_channel *chan, const char *data)
Definition: app_mf.c:551
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: main/utils.c:2033
int ast_mf_stream(struct ast_channel *chan, struct ast_channel *peer, 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:967
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1755
static int read_sf_digits(struct ast_channel *chan, char *buf, int timeout, int maxdigits, int freq, int features, int extrapulses)
Definition: app_mf.c:358
static int sendmf_exec(struct ast_channel *chan, const char *vdata)
Definition: app_mf.c:620
static int read_sf_exec(struct ast_channel *chan, const char *data)
Definition: app_mf.c:472
Structure used to handle boolean flags.
Definition: utils.h:199
static int manager_play_mf(struct mansession *s, const struct message *m)
Definition: app_mf.c:682
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:3171
const char * ast_channel_name(const struct ast_channel *chan)
static PGresult * result
Definition: cel_pgsql.c:88
Data structure associated with a single frame of data.
read_option_flags
Definition: app_mf.c:232
int ast_dsp_set_freqmode(struct ast_dsp *dsp, int freq1, int dur, int db, int squelch)
Set arbitrary frequency detection mode.
Definition: dsp.c:1859
static const char sendmf_name[]
Definition: app_mf.c:260
enum ast_frame_type frametype
#define DSP_DIGITMODE_NOQUELCH
Definition: dsp.h:34
static struct test_options options
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
#define DSP_FEATURE_FREQ_DETECT
Definition: dsp.h:45
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:3113
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:186
#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
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
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...
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode)
Set digit mode.
Definition: dsp.c:1844
#define AST_APP_ARG(name)
Define an application argument.