<p>N A has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/16080">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">app_sendmf: New SendMF application<br><br>Adds a SendMF application to send arbitrary<br>R1 MF tones on a channel.<br><br>ASTERISK-29496<br><br>Change-Id: I5d89afdbccee3f86cc702ed96d882f3d351327a4<br>---<br>A apps/app_sendmf.c<br>A doc/CHANGES-staging/app_sendmf.txt<br>2 files changed, 321 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/80/16080/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/apps/app_sendmf.c b/apps/app_sendmf.c</span><br><span>new file mode 100644</span><br><span>index 0000000..4b3f070</span><br><span>--- /dev/null</span><br><span>+++ b/apps/app_sendmf.c</span><br><span>@@ -0,0 +1,315 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2021, Naveen Albert</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Naveen Albert <asterisk@phreaknet.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief App to send MF digits</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \author Naveen Albert <asterisk@phreaknet.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \ingroup applications</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*** MODULEINFO</span><br><span style="color: hsl(120, 100%, 40%);">+    <support_level>extended</support_level></span><br><span style="color: hsl(120, 100%, 40%);">+ ***/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/pbx.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/module.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/app.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/channel.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/indications.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*** DOCUMENTATION</span><br><span style="color: hsl(120, 100%, 40%);">+ <application name="SendMF" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+                <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                      Sends arbitrary MF digits</span><br><span style="color: hsl(120, 100%, 40%);">+             </synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+             <syntax></span><br><span style="color: hsl(120, 100%, 40%);">+                        <parameter name="digits" required="true"></span><br><span style="color: hsl(120, 100%, 40%);">+                           <para>List of digits 0-9,KSTUV to send; also f or F for a flash-hook</span><br><span style="color: hsl(120, 100%, 40%);">+                            if the channel supports flash-hook, and w or W for a wink if the channel</span><br><span style="color: hsl(120, 100%, 40%);">+                              supports wink.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                           <para>Key pulse and start digits are not included automatically.</span><br><span style="color: hsl(120, 100%, 40%);">+                                K is used for KP, S for ST, T for STP, U for ST2P, and V for ST3P.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                       </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="timeout_ms" required="false"></span><br><span style="color: hsl(120, 100%, 40%);">+                              <para>Amount of time to wait in ms between tones. (defaults to 50ms).</para></span><br><span style="color: hsl(120, 100%, 40%);">+                      </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="duration_ms" required="false"></span><br><span style="color: hsl(120, 100%, 40%);">+                             <para>Duration of each numeric digit (defaults to 55ms).</para></span><br><span style="color: hsl(120, 100%, 40%);">+                   </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="duration_ms_kp" required="false"></span><br><span style="color: hsl(120, 100%, 40%);">+                          <para>Duration of KP digits (defaults to 120ms).</para></span><br><span style="color: hsl(120, 100%, 40%);">+                   </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="duration_ms_st" required="false"></span><br><span style="color: hsl(120, 100%, 40%);">+                          <para>Duration of ST, STP, ST2P, and ST3P digits (defaults to 55ms).</para></span><br><span style="color: hsl(120, 100%, 40%);">+                       </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="channel" required="false"></span><br><span style="color: hsl(120, 100%, 40%);">+                         <para>Channel where digits will be played</para></span><br><span style="color: hsl(120, 100%, 40%);">+                  </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+            </syntax></span><br><span style="color: hsl(120, 100%, 40%);">+               <description></span><br><span style="color: hsl(120, 100%, 40%);">+                   <para>It will send all digits or terminate if it encounters an error.</para></span><br><span style="color: hsl(120, 100%, 40%);">+              </description></span><br><span style="color: hsl(120, 100%, 40%);">+          <see-also></span><br><span style="color: hsl(120, 100%, 40%);">+                      <ref type="application">SendDTMF</ref></span><br><span style="color: hsl(120, 100%, 40%);">+          </see-also></span><br><span style="color: hsl(120, 100%, 40%);">+     </application></span><br><span style="color: hsl(120, 100%, 40%);">+ ***/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const char sendmf_name[] = "SendMF";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_DEFAULT_EMULATE_MF_DURATION 100</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ast_senddigit_mf_begin(struct ast_channel *chan, char digit)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     static const char * const mf_tones[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              "1300+1500", /* 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+                "700+900",   /* 1 */</span><br><span style="color: hsl(120, 100%, 40%);">+                "700+1100",  /* 2 */</span><br><span style="color: hsl(120, 100%, 40%);">+                "900+1100",  /* 3 */</span><br><span style="color: hsl(120, 100%, 40%);">+                "700+1300",  /* 4 */</span><br><span style="color: hsl(120, 100%, 40%);">+                "900+1300",  /* 5 */</span><br><span style="color: hsl(120, 100%, 40%);">+                "1100+1300", /* 6 */</span><br><span style="color: hsl(120, 100%, 40%);">+                "700+1500",  /* 7 */</span><br><span style="color: hsl(120, 100%, 40%);">+                "900+1500",  /* 8 */</span><br><span style="color: hsl(120, 100%, 40%);">+                "1100+1500", /* 9 */</span><br><span style="color: hsl(120, 100%, 40%);">+                "1100+1700", /* K (KP) */</span><br><span style="color: hsl(120, 100%, 40%);">+           "1500+1700", /* S (ST) */</span><br><span style="color: hsl(120, 100%, 40%);">+           "900+1700",  /* T (STP) */</span><br><span style="color: hsl(120, 100%, 40%);">+          "1300+1700", /* U (ST2P) */</span><br><span style="color: hsl(120, 100%, 40%);">+         "700+1700"   /* V (ST3P) */</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (digit >= '0' && digit <='9')</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_playtones_start(chan, 0, mf_tones[digit-'0'], 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ else if (digit == 'K')</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_playtones_start(chan, 0, mf_tones[10], 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        else if (digit == 'S')</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_playtones_start(chan, 0, mf_tones[11], 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        else if (digit == 'T')</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_playtones_start(chan, 0, mf_tones[12], 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        else if (digit == 'U')</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_playtones_start(chan, 0, mf_tones[13], 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        else if (digit == 'V')</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_playtones_start(chan, 0, mf_tones[14], 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        else {</span><br><span style="color: hsl(120, 100%, 40%);">+                /* not handled */</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_debug(1, "Unable to generate MF tone '%c' for '%s'\n", digit, ast_channel_name(chan));</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ast_senddigit_mf_end(struct ast_channel *chan, char digit, unsigned int duration)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ast_channel_generator(chan)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_playtones_stop(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ast_senddigit_mf(struct ast_channel *chan, char digit, unsigned int duration, unsigned int durationkp, unsigned int durationst)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (duration < AST_DEFAULT_EMULATE_MF_DURATION) {</span><br><span style="color: hsl(120, 100%, 40%);">+          duration = AST_DEFAULT_EMULATE_MF_DURATION;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_channel_tech(chan)->send_digit_begin) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (digit == 'K')</span><br><span style="color: hsl(120, 100%, 40%);">+                     duration = durationkp;</span><br><span style="color: hsl(120, 100%, 40%);">+                else if (digit == 'S' || digit == 'T' || digit == 'U' || digit == 'V')</span><br><span style="color: hsl(120, 100%, 40%);">+                        duration = durationst;</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_senddigit_mf_begin(chan, digit);</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_safe_sleep(chan, duration);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     return ast_senddigit_mf_end(chan, digit, duration);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ast_senddigit_external_mf(struct ast_channel *chan, char digit, unsigned int duration, unsigned int durationkp, unsigned int durationst)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (duration < AST_DEFAULT_EMULATE_MF_DURATION) {</span><br><span style="color: hsl(120, 100%, 40%);">+          duration = AST_DEFAULT_EMULATE_MF_DURATION;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_channel_tech(chan)->send_digit_begin) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_senddigit_mf_begin(chan, digit);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (digit == 'K')</span><br><span style="color: hsl(120, 100%, 40%);">+                     duration = durationkp;</span><br><span style="color: hsl(120, 100%, 40%);">+                else if (digit == 'S' || digit == 'T' || digit == 'U' || digit == 'V')</span><br><span style="color: hsl(120, 100%, 40%);">+                        duration = durationst;</span><br><span style="color: hsl(120, 100%, 40%);">+                usleep(duration * 1000);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     return ast_senddigit_mf_end(chan, digit, duration);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int external_sleep(struct ast_channel *chan, int ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      usleep(ms * 1000);</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int mf_stream(struct ast_channel *chan, const char *digits, int between, unsigned int duration, unsigned int durationkp, unsigned int durationst, int is_external)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+      int res;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_silence_generator *silgen = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  int (*my_sleep)(struct ast_channel *chan, int ms);</span><br><span style="color: hsl(120, 100%, 40%);">+    int (*my_senddigit)(struct ast_channel *chan, char digit, unsigned int duration, unsigned int durationkp, unsigned int durationst);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (is_external) {</span><br><span style="color: hsl(120, 100%, 40%);">+            my_sleep = external_sleep;</span><br><span style="color: hsl(120, 100%, 40%);">+            my_senddigit = ast_senddigit_external_mf;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              my_sleep = ast_safe_sleep;</span><br><span style="color: hsl(120, 100%, 40%);">+            my_senddigit = ast_senddigit_mf;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!between) {</span><br><span style="color: hsl(120, 100%, 40%);">+               between = 100;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Need a quiet time before sending digits. */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ast_opt_transmit_silence) {</span><br><span style="color: hsl(120, 100%, 40%);">+               silgen = ast_channel_start_silence_generator(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     res = my_sleep(chan, 100);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            goto mf_stream_cleanup;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (ptr = digits; *ptr; ptr++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (strchr("0123456789KSTUVwWfF", *ptr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (*ptr == 'f' || *ptr == 'F') {</span><br><span style="color: hsl(120, 100%, 40%);">+                             /* ignore return values if not supported by channel */</span><br><span style="color: hsl(120, 100%, 40%);">+                                ast_indicate(chan, AST_CONTROL_FLASH);</span><br><span style="color: hsl(120, 100%, 40%);">+                        } else if (*ptr == 'w' || *ptr == 'W') {</span><br><span style="color: hsl(120, 100%, 40%);">+                              /* ignore return values if not supported by channel */</span><br><span style="color: hsl(120, 100%, 40%);">+                                ast_indicate(chan, AST_CONTROL_WINK);</span><br><span style="color: hsl(120, 100%, 40%);">+                 } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              /* Character represents valid DTMF */</span><br><span style="color: hsl(120, 100%, 40%);">+                         my_senddigit(chan, *ptr, duration, durationkp, durationst);</span><br><span style="color: hsl(120, 100%, 40%);">+                   }</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* pause between digits */</span><br><span style="color: hsl(120, 100%, 40%);">+                    res = my_sleep(chan, between);</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_log(LOG_WARNING, "Illegal MF character '%c' in string. (0-9KSTUVwWfF allowed)\n", *ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+mf_stream_cleanup:</span><br><span style="color: hsl(120, 100%, 40%);">+       if (silgen) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_channel_stop_silence_generator(chan, silgen);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static 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)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int res;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (peer && ast_autoservice_start(peer)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     res = mf_stream(chan, digits, between, duration, durationkp, durationst, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (peer && ast_autoservice_stop(peer)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             res = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int sendmf_exec(struct ast_channel *chan, const char *vdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int res;</span><br><span style="color: hsl(120, 100%, 40%);">+      char *data;</span><br><span style="color: hsl(120, 100%, 40%);">+   int dinterval = 0, duration = 0, durationkp = 0, durationst = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_channel *chan_found = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_channel *chan_dest = chan;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel *chan_autoservice = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_DECLARE_APP_ARGS(args,</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_APP_ARG(digits);</span><br><span style="color: hsl(120, 100%, 40%);">+          AST_APP_ARG(dinterval);</span><br><span style="color: hsl(120, 100%, 40%);">+               AST_APP_ARG(duration);</span><br><span style="color: hsl(120, 100%, 40%);">+                AST_APP_ARG(durationkp);</span><br><span style="color: hsl(120, 100%, 40%);">+              AST_APP_ARG(durationst);</span><br><span style="color: hsl(120, 100%, 40%);">+              AST_APP_ARG(channel);</span><br><span style="color: hsl(120, 100%, 40%);">+ );</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ast_strlen_zero(vdata)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_WARNING, "SendMF requires an argument\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   data = ast_strdupa(vdata);</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_STANDARD_APP_ARGS(args, data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ast_strlen_zero(args.digits)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_WARNING, "The digits argument is required (0-9,KSTUV,wf)\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ast_strlen_zero(args.dinterval)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_app_parse_timelen(args.dinterval, &dinterval, TIMELEN_MILLISECONDS);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ast_strlen_zero(args.duration)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_app_parse_timelen(args.duration, &duration, TIMELEN_MILLISECONDS);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ast_strlen_zero(args.durationkp)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_app_parse_timelen(args.durationkp, &durationkp, TIMELEN_MILLISECONDS);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ast_strlen_zero(args.duration)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_app_parse_timelen(args.durationst, &durationst, TIMELEN_MILLISECONDS);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ast_strlen_zero(args.channel)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         chan_found = ast_channel_get_by_name(args.channel);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!chan_found) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_log(LOG_WARNING, "No such channel: %s\n", args.channel);</span><br><span style="color: hsl(120, 100%, 40%);">+                        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             chan_dest = chan_found;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (chan_found != chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     chan_autoservice = chan;</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     res = ast_mf_stream(chan_dest, chan_autoservice, args.digits,</span><br><span style="color: hsl(120, 100%, 40%);">+         dinterval <= 0 ? 50 : dinterval, duration <= 0 ? 55 : duration,</span><br><span style="color: hsl(120, 100%, 40%);">+         durationkp <= 0 ? 120 : durationkp, durationst <= 0 ? 55 : durationst);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_found) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_channel_unref(chan_found);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return chan_autoservice ? 0 : res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int unload_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return ast_unregister_application(sendmf_name);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int load_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_register_application_xml(sendmf_name, sendmf_exec);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Send MF digits Application");</span><br><span>diff --git a/doc/CHANGES-staging/app_sendmf.txt b/doc/CHANGES-staging/app_sendmf.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..4344276</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/app_sendmf.txt</span><br><span>@@ -0,0 +1,6 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: send_mf application</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+A SendMF application is now included</span><br><span style="color: hsl(120, 100%, 40%);">+to send arbitrary standard R1 MF</span><br><span style="color: hsl(120, 100%, 40%);">+tones on a channel.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/16080">change 16080</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/16080"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I5d89afdbccee3f86cc702ed96d882f3d351327a4 </div>
<div style="display:none"> Gerrit-Change-Number: 16080 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: N A <mail@interlinked.x10host.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>