<p>Kevin Harwell <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/16272">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  George Joseph: Looks good to me, approved
  Kevin Harwell: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">app_mf: Add channel agnostic MF sender<br><br>Adds a SendMF application and PlayMF manager<br>event to send arbitrary R1 MF tones on the<br>current or specified channel.<br><br>ASTERISK-29496<br><br>Change-Id: I5d89afdbccee3f86cc702ed96d882f3d351327a4<br>---<br>A apps/app_mf.c<br>A doc/CHANGES-staging/mf.txt<br>2 files changed, 367 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/apps/app_mf.c b/apps/app_mf.c</span><br><span>new file mode 100644</span><br><span>index 0000000..671fc1c</span><br><span>--- /dev/null</span><br><span>+++ b/apps/app_mf.c</span><br><span>@@ -0,0 +1,361 @@</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,*#ABC 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%);">+                                * is used for KP, # for ST, A for STP, B for ST2P, and C 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 65ms).</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%);">+  <manager name="PlayMF" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+            <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                      Play MF signal on a specific channel.</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%);">+                        <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" /></span><br><span style="color: hsl(120, 100%, 40%);">+                   <parameter name="Channel" required="true"></span><br><span style="color: hsl(120, 100%, 40%);">+                          <para>Channel name to send digit to.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                       </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="Digit" required="true"></span><br><span style="color: hsl(120, 100%, 40%);">+                            <para>The MF digit to play.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                        </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="Duration" required="false"></span><br><span style="color: hsl(120, 100%, 40%);">+                                <para>The duration, in milliseconds, of the digit to 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>Plays an MF digit on the specified channel.</para></span><br><span style="color: hsl(120, 100%, 40%);">+          </description></span><br><span style="color: hsl(120, 100%, 40%);">+  </manager></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 DEFAULT_EMULATE_MF_DURATION 35</span><br><span style="color: hsl(120, 100%, 40%);">+#define MF_BETWEEN_MS 50</span><br><span style="color: hsl(120, 100%, 40%);">+#define MF_DURATION 55</span><br><span style="color: hsl(120, 100%, 40%);">+#define MF_KP_DURATION 120</span><br><span style="color: hsl(120, 100%, 40%);">+#define MF_ST_DURATION 65</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int 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", /* * (KP) */</span><br><span style="color: hsl(120, 100%, 40%);">+           "1500+1700", /* # (ST) */</span><br><span style="color: hsl(120, 100%, 40%);">+           "900+1700",  /* A (STP) */</span><br><span style="color: hsl(120, 100%, 40%);">+          "1300+1700", /* B (ST2P) */</span><br><span style="color: hsl(120, 100%, 40%);">+         "700+1700"   /* C (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 == '*') {</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 == '#') {</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 == 'A') {</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 == 'B') {</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 == 'C') {</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_log(LOG_WARNING, "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 senddigit_mf_end(struct ast_channel *chan)</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 mysleep(struct ast_channel *chan, int ms, int is_external)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return is_external ? usleep(ms * 1000) : ast_safe_sleep(chan, ms);</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 senddigit_mf(struct ast_channel *chan, char digit, unsigned int duration,</span><br><span style="color: hsl(120, 100%, 40%);">+ 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%);">+ if (duration < DEFAULT_EMULATE_MF_DURATION) {</span><br><span style="color: hsl(120, 100%, 40%);">+              duration = 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 == '*') {</span><br><span style="color: hsl(120, 100%, 40%);">+                   duration = durationkp;</span><br><span style="color: hsl(120, 100%, 40%);">+                } else if (digit == '#' || digit == 'A' || digit == 'B' || digit == 'C') {</span><br><span style="color: hsl(120, 100%, 40%);">+                    duration = durationst;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             senddigit_mf_begin(chan, digit);</span><br><span style="color: hsl(120, 100%, 40%);">+              mysleep(chan, duration, is_external);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     return senddigit_mf_end(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%);">+static int mf_stream(struct ast_channel *chan, const char *digits, int between, unsigned int duration,</span><br><span style="color: hsl(120, 100%, 40%);">+   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%);">+</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 = mysleep(chan, 100, is_external);</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("0123456789*#ABCwWfF", *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 MF */</span><br><span style="color: hsl(120, 100%, 40%);">+                           senddigit_mf(chan, *ptr, duration, durationkp, durationst, is_external);</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%);">+                    /* The DSP code in Asterisk does not currently properly receive repeated tones</span><br><span style="color: hsl(120, 100%, 40%);">+                                if no audio is sent in the middle. Simply sending audio (even 0 Hz)</span><br><span style="color: hsl(120, 100%, 40%);">+                           works around this limitation and guarantees the correct behavior.</span><br><span style="color: hsl(120, 100%, 40%);">+                             */</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_playtones_start(chan, 0, "0", 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                       res = mysleep(chan, between, is_external);</span><br><span style="color: hsl(120, 100%, 40%);">+                    senddigit_mf_end(chan);</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-9*#ABCwWfF 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 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,*#ABC,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.durationst)) {</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%);">+     if (chan_autoservice && ast_autoservice_start(chan_autoservice)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_channel_cleanup(chan_found);</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_dest, args.digits, dinterval <= 0 ? MF_BETWEEN_MS : dinterval,</span><br><span style="color: hsl(120, 100%, 40%);">+                duration <= 0 ? MF_DURATION : duration, durationkp <= 0 ? MF_KP_DURATION : durationkp,</span><br><span style="color: hsl(120, 100%, 40%);">+          durationst <= 0 ? MF_ST_DURATION : durationst, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_autoservice && ast_autoservice_stop(chan_autoservice)) {</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%);">+     ast_channel_cleanup(chan_found);</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 manager_play_mf(struct mansession *s, const struct message *m)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *channel = astman_get_header(m, "Channel");</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *digit = astman_get_header(m, "Digit");</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *duration = astman_get_header(m, "Duration");</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_channel *chan;</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned int duration_ms = MF_DURATION;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!(chan = ast_channel_get_by_name(channel))) {</span><br><span style="color: hsl(120, 100%, 40%);">+             astman_send_error(s, m, "Channel not found");</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%);">+   if (ast_strlen_zero(digit)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         astman_send_error(s, m, "No digit specified");</span><br><span style="color: hsl(120, 100%, 40%);">+              chan = ast_channel_unref(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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Override default duration with KP or ST-specific default durations */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!strcmp(digit, "*"))</span><br><span style="color: hsl(120, 100%, 40%);">+            duration_ms = MF_KP_DURATION;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!strcmp(digit, "#") || !strcmp(digit, "A") || !strcmp(digit, "B") || !strcmp(digit, "C"))</span><br><span style="color: hsl(120, 100%, 40%);">+         duration_ms = MF_ST_DURATION;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ast_strlen_zero(duration) && (sscanf(duration, "%30u", &duration_ms) != 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              astman_send_error(s, m, "Could not convert Duration parameter");</span><br><span style="color: hsl(120, 100%, 40%);">+            chan = ast_channel_unref(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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   senddigit_mf(chan, *digit, duration_ms, duration_ms, duration_ms, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ chan = ast_channel_unref(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     astman_send_ack(s, m, "MF successfully queued");</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 unload_module(void)</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%);">+    res = ast_unregister_application(sendmf_name);</span><br><span style="color: hsl(120, 100%, 40%);">+        res |= ast_manager_unregister("PlayMF");</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 load_module(void)</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%);">+    res = ast_manager_register_xml("PlayMF", EVENT_FLAG_CALL, manager_play_mf);</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= 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%);">+      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%);">+AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Send MF digits Application");</span><br><span>diff --git a/doc/CHANGES-staging/mf.txt b/doc/CHANGES-staging/mf.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..644f62a</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/mf.txt</span><br><span>@@ -0,0 +1,6 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: Channel-agnostic MF support</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+A SendMF application and PlayMF manager</span><br><span style="color: hsl(120, 100%, 40%);">+application are now included to send</span><br><span style="color: hsl(120, 100%, 40%);">+arbitrary standard R1 MF tones on the</span><br><span style="color: hsl(120, 100%, 40%);">+current channel or another specified channel.</span><br><span></span><br></pre><div style="white-space:pre-wrap"></div><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/16272">change 16272</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/+/16272"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 19 </div>
<div style="display:none"> Gerrit-Change-Id: I5d89afdbccee3f86cc702ed96d882f3d351327a4 </div>
<div style="display:none"> Gerrit-Change-Number: 16272 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: N A <mail@interlinked.x10host.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>