From 7d874c1af78a74efa226bab9501d5ba63a907ab7 Mon Sep 17 00:00:00 2001
From: Richard Mudgett <rmudgett@digium.com>
Date: Wed, 13 Jun 2018 13:05:03 -0500
Subject: [PATCH] AMI PlayDTMF Action: Make not compete with channel's media
 thread.

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: Ia341f1a6f4d54f2022261abec9021fe5b2eb4905
---
 apps/app_senddtmf.c        |  2 +-
 include/asterisk/channel.h | 18 ++++++++++++++++++
 main/channel.c             | 20 ++++++++++++++++++--
 3 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/apps/app_senddtmf.c b/apps/app_senddtmf.c
index 178b13ff03..e0362e7d30 100644
--- a/apps/app_senddtmf.c
+++ b/apps/app_senddtmf.c
@@ -167,7 +167,7 @@ static int manager_play_dtmf(struct mansession *s, const struct message *m)
 		return 0;
 	}
 
-	ast_senddigit(chan, *digit, duration_ms);
+	ast_senddigit_external(chan, *digit, duration_ms);
 
 	chan = ast_channel_unref(chan);
 
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index c865a8a32b..91aed34683 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -2177,13 +2177,31 @@ int ast_recvchar(struct ast_channel *chan, int timeout);
 
 /*!
  * \brief Send a DTMF digit to a channel.
+ *
  * \param chan channel to act upon
  * \param digit the DTMF digit to send, encoded in ASCII
  * \param duration the duration of the digit ending in ms
+ *
+ * \pre This must only be called by the channel's media handler thread.
+ *
  * \return 0 on success, -1 on failure
  */
 int ast_senddigit(struct ast_channel *chan, char digit, unsigned int duration);
 
+/*!
+ * \brief Send a DTMF digit to a channel from an external thread.
+ *
+ * \param chan channel to act upon
+ * \param digit the DTMF digit to send, encoded in ASCII
+ * \param duration the duration of the digit ending in ms
+ *
+ * \pre This must only be called by threads that are not the channel's
+ * media handler thread.
+ *
+ * \return 0 on success, -1 on failure
+ */
+int ast_senddigit_external(struct ast_channel *chan, char digit, unsigned int duration);
+
 /*!
  * \brief Send a DTMF digit to a channel.
  * \param chan channel to act upon
diff --git a/main/channel.c b/main/channel.c
index d0261219e2..647959792e 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -4810,12 +4810,28 @@ int ast_senddigit_end(struct ast_channel *chan, char digit, unsigned int duratio
 
 int ast_senddigit(struct ast_channel *chan, char digit, unsigned int duration)
 {
+	if (duration < AST_DEFAULT_EMULATE_DTMF_DURATION) {
+		duration = AST_DEFAULT_EMULATE_DTMF_DURATION;
+	}
+	if (ast_channel_tech(chan)->send_digit_begin) {
+		ast_senddigit_begin(chan, digit);
+		ast_safe_sleep(chan, duration);
+	}
+
+	return ast_senddigit_end(chan, digit, duration);
+}
+
+int ast_senddigit_external(struct ast_channel *chan, char digit, unsigned int duration)
+{
+	if (duration < AST_DEFAULT_EMULATE_DTMF_DURATION) {
+		duration = AST_DEFAULT_EMULATE_DTMF_DURATION;
+	}
 	if (ast_channel_tech(chan)->send_digit_begin) {
 		ast_senddigit_begin(chan, digit);
-		ast_safe_sleep(chan, (duration >= AST_DEFAULT_EMULATE_DTMF_DURATION ? duration : AST_DEFAULT_EMULATE_DTMF_DURATION));
+		usleep(duration * 1000);
 	}
 
-	return ast_senddigit_end(chan, digit, (duration >= AST_DEFAULT_EMULATE_DTMF_DURATION ? duration : AST_DEFAULT_EMULATE_DTMF_DURATION));
+	return ast_senddigit_end(chan, digit, duration);
 }
 
 int ast_prod(struct ast_channel *chan)
-- 
GitLab