]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
ARI POST DTMF: Make not compete with channel's media thread.
authorRichard Mudgett <rmudgett@digium.com>
Wed, 13 Jun 2018 21:41:43 +0000 (16:41 -0500)
committerRichard Mudgett <rmudgett@digium.com>
Tue, 19 Jun 2018 19:13:07 +0000 (14:13 -0500)
There can be one and only one thread handling a channel's media at a time.
Otherwise, we don't know which thread is going to handle the media frames.

ASTERISK-27625

Change-Id: I4d6a2fe7386ea447ee199003bf8ad681cb30454e

include/asterisk/app.h
main/app.c
res/stasis/control.c

index 5b10b1c1c7c9ccdfa3773069aab4b191bc20a1ae..0865121e2372a5ac60da0fb755e2c2e11bfd2a34 100644 (file)
@@ -923,24 +923,51 @@ void ast_replace_sigchld(void);
 void ast_unreplace_sigchld(void);
 
 /*!
-  \brief Send DTMF to a channel
-
-  \param chan    The channel that will receive the DTMF frames
-  \param peer    (optional) Peer channel that will be autoserviced while the
-                 primary channel is receiving DTMF
-  \param digits  This is a string of characters representing the DTMF digits
-                 to be sent to the channel.  Valid characters are
-                 "0123456789*#abcdABCD".  Note: You can pass arguments 'f' or
-                 'F', if you want to Flash the channel (if supported by the
-                 channel), or 'w' to add a 500 millisecond pause to the DTMF
-                 sequence.
-  \param between This is the number of milliseconds to wait in between each
-                 DTMF digit.  If zero milliseconds is specified, then the
-                 default value of 100 will be used.
-  \param duration This is the duration that each DTMF digit should have.
-*/
+ * \brief Send a string of DTMF digits to a channel
+ *
+ * \param chan    The channel that will receive the DTMF frames
+ * \param peer    (optional) Peer channel that will be autoserviced while the
+ *                primary channel is receiving DTMF
+ * \param digits  This is a string of characters representing the DTMF digits
+ *                to be sent to the channel.  Valid characters are
+ *                "0123456789*#abcdABCD".  Note: You can pass arguments 'f' or
+ *                'F', if you want to Flash the channel (if supported by the
+ *                channel), or 'w' to add a 500 millisecond pause to the DTMF
+ *                sequence.
+ * \param between This is the number of milliseconds to wait in between each
+ *                DTMF digit.  If zero milliseconds is specified, then the
+ *                default value of 100 will be used.
+ * \param duration This is the duration that each DTMF digit should have.
+ *
+ * \pre This must only be called by the channel's media handler thread.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure or a channel hung up.
+ */
 int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration);
 
+/*!
+ * \brief Send a string of DTMF digits to a channel from an external thread.
+ *
+ * \param chan    The channel that will receive the DTMF frames
+ * \param digits  This is a string of characters representing the DTMF digits
+ *                to be sent to the channel.  Valid characters are
+ *                "0123456789*#abcdABCD".  Note: You can pass arguments 'f' or
+ *                'F', if you want to Flash the channel (if supported by the
+ *                channel), or 'w' to add a 500 millisecond pause to the DTMF
+ *                sequence.
+ * \param between This is the number of milliseconds to wait in between each
+ *                DTMF digit.  If zero milliseconds is specified, then the
+ *                default value of 100 will be used.
+ * \param duration This is the duration that each DTMF digit should have.
+ *
+ * \pre This must only be called by threads that are not the channel's
+ * media handler thread.
+ *
+ * \return Nothing
+ */
+void ast_dtmf_stream_external(struct ast_channel *chan, const char *digits, int between, unsigned int duration);
+
 /*! \brief Stream a filename (or file descriptor) as a generator. */
 int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride);
 
index 331c8275066e31b49b9aca6947bacf748422b117..e7aab10b1fabf14afcbfcaf9b9134b283b74a89c 100644 (file)
@@ -875,25 +875,37 @@ int ast_vm_test_destroy_user(const char *context, const char *mailbox)
 }
 #endif
 
-int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)
+static int external_sleep(struct ast_channel *chan, int ms)
+{
+       usleep(ms * 1000);
+       return 0;
+}
+
+static int dtmf_stream(struct ast_channel *chan, const char *digits, int between, unsigned int duration, int is_external)
 {
        const char *ptr;
        int res;
        struct ast_silence_generator *silgen = NULL;
+       int (*my_sleep)(struct ast_channel *chan, int ms);
+       int (*my_senddigit)(struct ast_channel *chan, char digit, unsigned int duration);
 
-       if (!between) {
-               between = 100;
+       if (is_external) {
+               my_sleep = external_sleep;
+               my_senddigit = ast_senddigit_external;
+       } else {
+               my_sleep = ast_safe_sleep;
+               my_senddigit = ast_senddigit;
        }
 
-       if (peer && ast_autoservice_start(peer)) {
-               return -1;
+       if (!between) {
+               between = 100;
        }
 
        /* Need a quiet time before sending digits. */
        if (ast_opt_transmit_silence) {
                silgen = ast_channel_start_silence_generator(chan);
        }
-       res = ast_safe_sleep(chan, 100);
+       res = my_sleep(chan, 100);
        if (res) {
                goto dtmf_stream_cleanup;
        }
@@ -901,12 +913,14 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
        for (ptr = digits; *ptr; ptr++) {
                if (*ptr == 'w') {
                        /* 'w' -- wait half a second */
-                       if ((res = ast_safe_sleep(chan, 500))) {
+                       res = my_sleep(chan, 500);
+                       if (res) {
                                break;
                        }
                } else if (*ptr == 'W') {
                        /* 'W' -- wait a second */
-                       if ((res = ast_safe_sleep(chan, 1000))) {
+                       res = my_sleep(chan, 1000);
+                       if (res) {
                                break;
                        }
                } else if (strchr("0123456789*#abcdfABCDF", *ptr)) {
@@ -915,10 +929,11 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
                                ast_indicate(chan, AST_CONTROL_FLASH);
                        } else {
                                /* Character represents valid DTMF */
-                               ast_senddigit(chan, *ptr, duration);
+                               my_senddigit(chan, *ptr, duration);
                        }
                        /* pause between digits */
-                       if ((res = ast_safe_sleep(chan, between))) {
+                       res = my_sleep(chan, between);
+                       if (res) {
                                break;
                        }
                } else {
@@ -930,6 +945,18 @@ dtmf_stream_cleanup:
        if (silgen) {
                ast_channel_stop_silence_generator(chan, silgen);
        }
+
+       return res;
+}
+
+int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)
+{
+       int res;
+
+       if (peer && ast_autoservice_start(peer)) {
+               return -1;
+       }
+       res = dtmf_stream(chan, digits, between, duration, 0);
        if (peer && ast_autoservice_stop(peer)) {
                res = -1;
        }
@@ -937,6 +964,11 @@ dtmf_stream_cleanup:
        return res;
 }
 
+void ast_dtmf_stream_external(struct ast_channel *chan, const char *digits, int between, unsigned int duration)
+{
+       dtmf_stream(chan, digits, between, duration, 1);
+}
+
 struct linear_state {
        int fd;
        int autoclose;
index df97931a749ddb4369006a2af5c62bc7ce4624ae..1821f20849989679514e1bd8bbb636340790e58c 100644 (file)
@@ -503,15 +503,21 @@ struct stasis_app_control_dtmf_data {
        char dtmf[];
 };
 
-static int app_control_dtmf(struct stasis_app_control *control,
-       struct ast_channel *chan, void *data)
+static void dtmf_in_bridge(struct ast_channel *chan, struct stasis_app_control_dtmf_data *dtmf_data)
 {
-       struct stasis_app_control_dtmf_data *dtmf_data = data;
+       if (dtmf_data->before) {
+               usleep(dtmf_data->before * 1000);
+       }
 
-       if (ast_channel_state(chan) != AST_STATE_UP) {
-               ast_indicate(chan, AST_CONTROL_PROGRESS);
+       ast_dtmf_stream_external(chan, dtmf_data->dtmf, dtmf_data->between, dtmf_data->duration);
+
+       if (dtmf_data->after) {
+               usleep(dtmf_data->after * 1000);
        }
+}
 
+static void dtmf_no_bridge(struct ast_channel *chan, struct stasis_app_control_dtmf_data *dtmf_data)
+{
        if (dtmf_data->before) {
                ast_safe_sleep(chan, dtmf_data->before);
        }
@@ -521,6 +527,22 @@ static int app_control_dtmf(struct stasis_app_control *control,
        if (dtmf_data->after) {
                ast_safe_sleep(chan, dtmf_data->after);
        }
+}
+
+static int app_control_dtmf(struct stasis_app_control *control,
+       struct ast_channel *chan, void *data)
+{
+       struct stasis_app_control_dtmf_data *dtmf_data = data;
+
+       if (ast_channel_state(chan) != AST_STATE_UP) {
+               ast_indicate(chan, AST_CONTROL_PROGRESS);
+       }
+
+       if (stasis_app_get_bridge(control)) {
+               dtmf_in_bridge(chan, dtmf_data);
+       } else {
+               dtmf_no_bridge(chan, dtmf_data);
+       }
 
        return 0;
 }