<p>George Joseph <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/9210">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Kevin Harwell: Looks good to me, but someone else must approve
  Joshua Colp: Looks good to me, but someone else must approve
  Sean Bright: Looks good to me, approved
  George Joseph: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">ARI POST DTMF: Make not compete with channel's media thread.<br><br>There can be one and only one thread handling a channel's media at a time.<br>Otherwise, we don't know which thread is going to handle the media frames.<br><br>ASTERISK-27625<br><br>Change-Id: I4d6a2fe7386ea447ee199003bf8ad681cb30454e<br>---<br>M include/asterisk/app.h<br>M main/app.c<br>M res/stasis/control.c<br>3 files changed, 115 insertions(+), 34 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/include/asterisk/app.h b/include/asterisk/app.h<br>index 5b10b1c..0865121 100644<br>--- a/include/asterisk/app.h<br>+++ b/include/asterisk/app.h<br>@@ -923,24 +923,51 @@<br> void ast_unreplace_sigchld(void);<br> <br> /*!<br>-  \brief Send DTMF to a channel<br>-<br>-  \param chan    The channel that will receive the DTMF frames<br>-  \param peer    (optional) Peer channel that will be autoserviced while the<br>-                 primary channel is receiving DTMF<br>-  \param digits  This is a string of characters representing the DTMF digits<br>-                 to be sent to the channel.  Valid characters are<br>-                 "0123456789*#abcdABCD".  Note: You can pass arguments 'f' or<br>-                 'F', if you want to Flash the channel (if supported by the<br>-                 channel), or 'w' to add a 500 millisecond pause to the DTMF<br>-                 sequence.<br>-  \param between This is the number of milliseconds to wait in between each<br>-                 DTMF digit.  If zero milliseconds is specified, then the<br>-                 default value of 100 will be used.<br>-  \param duration This is the duration that each DTMF digit should have.<br>-*/<br>+ * \brief Send a string of DTMF digits to a channel<br>+ *<br>+ * \param chan    The channel that will receive the DTMF frames<br>+ * \param peer    (optional) Peer channel that will be autoserviced while the<br>+ *                primary channel is receiving DTMF<br>+ * \param digits  This is a string of characters representing the DTMF digits<br>+ *                to be sent to the channel.  Valid characters are<br>+ *                "0123456789*#abcdABCD".  Note: You can pass arguments 'f' or<br>+ *                'F', if you want to Flash the channel (if supported by the<br>+ *                channel), or 'w' to add a 500 millisecond pause to the DTMF<br>+ *                sequence.<br>+ * \param between This is the number of milliseconds to wait in between each<br>+ *                DTMF digit.  If zero milliseconds is specified, then the<br>+ *                default value of 100 will be used.<br>+ * \param duration This is the duration that each DTMF digit should have.<br>+ *<br>+ * \pre This must only be called by the channel's media handler thread.<br>+ *<br>+ * \retval 0 on success.<br>+ * \retval -1 on failure or a channel hung up.<br>+ */<br> int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration);<br> <br>+/*!<br>+ * \brief Send a string of DTMF digits to a channel from an external thread.<br>+ *<br>+ * \param chan    The channel that will receive the DTMF frames<br>+ * \param digits  This is a string of characters representing the DTMF digits<br>+ *                to be sent to the channel.  Valid characters are<br>+ *                "0123456789*#abcdABCD".  Note: You can pass arguments 'f' or<br>+ *                'F', if you want to Flash the channel (if supported by the<br>+ *                channel), or 'w' to add a 500 millisecond pause to the DTMF<br>+ *                sequence.<br>+ * \param between This is the number of milliseconds to wait in between each<br>+ *                DTMF digit.  If zero milliseconds is specified, then the<br>+ *                default value of 100 will be used.<br>+ * \param duration This is the duration that each DTMF digit should have.<br>+ *<br>+ * \pre This must only be called by threads that are not the channel's<br>+ * media handler thread.<br>+ *<br>+ * \return Nothing<br>+ */<br>+void ast_dtmf_stream_external(struct ast_channel *chan, const char *digits, int between, unsigned int duration);<br>+<br> /*! \brief Stream a filename (or file descriptor) as a generator. */<br> int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride);<br> <br>diff --git a/main/app.c b/main/app.c<br>index 331c827..e7aab10 100644<br>--- a/main/app.c<br>+++ b/main/app.c<br>@@ -875,25 +875,37 @@<br> }<br> #endif<br> <br>-int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)<br>+static int external_sleep(struct ast_channel *chan, int ms)<br>+{<br>+       usleep(ms * 1000);<br>+   return 0;<br>+}<br>+<br>+static int dtmf_stream(struct ast_channel *chan, const char *digits, int between, unsigned int duration, int is_external)<br> {<br>      const char *ptr;<br>      int res;<br>      struct ast_silence_generator *silgen = NULL;<br>+ int (*my_sleep)(struct ast_channel *chan, int ms);<br>+   int (*my_senddigit)(struct ast_channel *chan, char digit, unsigned int duration);<br>+<br>+ if (is_external) {<br>+           my_sleep = external_sleep;<br>+           my_senddigit = ast_senddigit_external;<br>+       } else {<br>+             my_sleep = ast_safe_sleep;<br>+           my_senddigit = ast_senddigit;<br>+        }<br> <br>  if (!between) {<br>               between = 100;<br>-       }<br>-<br>- if (peer && ast_autoservice_start(peer)) {<br>-           return -1;<br>    }<br> <br>  /* Need a quiet time before sending digits. */<br>        if (ast_opt_transmit_silence) {<br>               silgen = ast_channel_start_silence_generator(chan);<br>   }<br>-    res = ast_safe_sleep(chan, 100);<br>+     res = my_sleep(chan, 100);<br>    if (res) {<br>            goto dtmf_stream_cleanup;<br>     }<br>@@ -901,12 +913,14 @@<br>      for (ptr = digits; *ptr; ptr++) {<br>             if (*ptr == 'w') {<br>                    /* 'w' -- wait half a second */<br>-                      if ((res = ast_safe_sleep(chan, 500))) {<br>+                     res = my_sleep(chan, 500);<br>+                   if (res) {<br>                            break;<br>                        }<br>             } else if (*ptr == 'W') {<br>                     /* 'W' -- wait a second */<br>-                   if ((res = ast_safe_sleep(chan, 1000))) {<br>+                    res = my_sleep(chan, 1000);<br>+                  if (res) {<br>                            break;<br>                        }<br>             } else if (strchr("0123456789*#abcdfABCDF", *ptr)) {<br>@@ -915,10 +929,11 @@<br>                                 ast_indicate(chan, AST_CONTROL_FLASH);<br>                        } else {<br>                              /* Character represents valid DTMF */<br>-                                ast_senddigit(chan, *ptr, duration);<br>+                         my_senddigit(chan, *ptr, duration);<br>                   }<br>                     /* pause between digits */<br>-                   if ((res = ast_safe_sleep(chan, between))) {<br>+                 res = my_sleep(chan, between);<br>+                       if (res) {<br>                            break;<br>                        }<br>             } else {<br>@@ -930,6 +945,18 @@<br>        if (silgen) {<br>                 ast_channel_stop_silence_generator(chan, silgen);<br>     }<br>+<br>+ return res;<br>+}<br>+<br>+int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)<br>+{<br>+     int res;<br>+<br>+  if (peer && ast_autoservice_start(peer)) {<br>+           return -1;<br>+   }<br>+    res = dtmf_stream(chan, digits, between, duration, 0);<br>        if (peer && ast_autoservice_stop(peer)) {<br>             res = -1;<br>     }<br>@@ -937,6 +964,11 @@<br>       return res;<br> }<br> <br>+void ast_dtmf_stream_external(struct ast_channel *chan, const char *digits, int between, unsigned int duration)<br>+{<br>+     dtmf_stream(chan, digits, between, duration, 1);<br>+}<br>+<br> struct linear_state {<br>       int fd;<br>       int autoclose;<br>diff --git a/res/stasis/control.c b/res/stasis/control.c<br>index df97931..1821f20 100644<br>--- a/res/stasis/control.c<br>+++ b/res/stasis/control.c<br>@@ -503,6 +503,32 @@<br>         char dtmf[];<br> };<br> <br>+static void dtmf_in_bridge(struct ast_channel *chan, struct stasis_app_control_dtmf_data *dtmf_data)<br>+{<br>+      if (dtmf_data->before) {<br>+          usleep(dtmf_data->before * 1000);<br>+ }<br>+<br>+ ast_dtmf_stream_external(chan, dtmf_data->dtmf, dtmf_data->between, dtmf_data->duration);<br>+<br>+        if (dtmf_data->after) {<br>+           usleep(dtmf_data->after * 1000);<br>+  }<br>+}<br>+<br>+static void dtmf_no_bridge(struct ast_channel *chan, struct stasis_app_control_dtmf_data *dtmf_data)<br>+{<br>+  if (dtmf_data->before) {<br>+          ast_safe_sleep(chan, dtmf_data->before);<br>+  }<br>+<br>+ ast_dtmf_stream(chan, NULL, dtmf_data->dtmf, dtmf_data->between, dtmf_data->duration);<br>+<br>+   if (dtmf_data->after) {<br>+           ast_safe_sleep(chan, dtmf_data->after);<br>+   }<br>+}<br>+<br> static int app_control_dtmf(struct stasis_app_control *control,<br>    struct ast_channel *chan, void *data)<br> {<br>@@ -512,14 +538,10 @@<br>              ast_indicate(chan, AST_CONTROL_PROGRESS);<br>     }<br> <br>- if (dtmf_data->before) {<br>-          ast_safe_sleep(chan, dtmf_data->before);<br>-  }<br>-<br>- ast_dtmf_stream(chan, NULL, dtmf_data->dtmf, dtmf_data->between, dtmf_data->duration);<br>-<br>-   if (dtmf_data->after) {<br>-           ast_safe_sleep(chan, dtmf_data->after);<br>+   if (stasis_app_get_bridge(control)) {<br>+                dtmf_in_bridge(chan, dtmf_data);<br>+     } else {<br>+             dtmf_no_bridge(chan, dtmf_data);<br>      }<br> <br>  return 0;<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/9210">change 9210</a>. To unsubscribe, 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/9210"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 13 </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I4d6a2fe7386ea447ee199003bf8ad681cb30454e </div>
<div style="display:none"> Gerrit-Change-Number: 9210 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Richard Mudgett <rmudgett@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Richard Mudgett <rmudgett@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Sean Bright <sean.bright@gmail.com> </div>