From 852bc686c973951cebd39e5828393d87b60d38f1 Mon Sep 17 00:00:00 2001
From: Brent Eagles <beagles@digium.com>
Date: Tue, 13 Nov 2012 18:48:43 +0000
Subject: [PATCH] Patch to prevent stopping the active generator when it is not
 the silence generator.

This patch introduces an internal helper function to safely check whether the
current generator is the one that is expected before deactivating it. The
current externally accessible ast_channel_stop_generator() function has been
modified to be implemented in terms of the new function.

(closes issue ASTERISK-19918)
Reported by: Eduardo Abad
........

Merged revisions 376199 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 376208 from http://svn.asterisk.org/svn/asterisk/branches/10


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@376217 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 main/channel.c | 47 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 39 insertions(+), 8 deletions(-)

diff --git a/main/channel.c b/main/channel.c
index e2ac10a10e..ec338e7b9d 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -3096,7 +3096,11 @@ static int generator_force(const void *data)
 
 	res = generate(chan, tmp, 0, ast_format_rate(ast_channel_writeformat(chan)) / 50);
 
-	ast_channel_generatordata_set(chan, tmp);
+	ast_channel_lock(chan);
+	if (ast_channel_generator(chan) && generate == ast_channel_generator(chan)->generate) {
+		ast_channel_generatordata_set(chan, tmp);
+	}
+	ast_channel_unlock(chan);
 
 	if (res) {
 		ast_debug(1, "Auto-deactivating generator\n");
@@ -8722,18 +8726,45 @@ struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_cha
 	return state;
 }
 
-void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
+static int internal_deactivate_generator(struct ast_channel *chan, void* generator)
 {
-	if (!state)
-		return;
+	ast_channel_lock(chan);
 
-	ast_deactivate_generator(chan);
+	if (!ast_channel_generatordata(chan)) {
+		ast_debug(1, "Trying to stop silence generator when there is no "
+		    "generator on '%s'\n", ast_channel_name(chan));
+		ast_channel_unlock(chan);
+		return 0;
+	}
+	if (ast_channel_generator(chan) != generator) {
+		ast_debug(1, "Trying to stop silence generator when it is not the current "
+		    "generator on '%s'\n", ast_channel_name(chan));
+		ast_channel_unlock(chan);
+		return 0;
+	}
+	if (ast_channel_generator(chan) && ast_channel_generator(chan)->release) {
+		ast_channel_generator(chan)->release(chan, ast_channel_generatordata(chan));
+	}
+	ast_channel_generatordata_set(chan, NULL);
+	ast_channel_generator_set(chan, NULL);
+	ast_channel_set_fd(chan, AST_GENERATOR_FD, -1);
+	ast_clear_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT);
+	ast_settimeout(chan, 0, NULL, NULL);
+	ast_channel_unlock(chan);
 
-	ast_debug(1, "Stopped silence generator on '%s'\n", ast_channel_name(chan));
+	return 1;
+}
 
-	if (ast_set_write_format(chan, &state->old_write_format) < 0)
-		ast_log(LOG_ERROR, "Could not return write format to its original state\n");
+void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
+{
+	if (!state)
+		return;
 
+	if (internal_deactivate_generator(chan, &silence_generator)) {
+		ast_debug(1, "Stopped silence generator on '%s'\n", ast_channel_name(chan));
+		if (ast_set_write_format(chan, &state->old_write_format) < 0)
+			ast_log(LOG_ERROR, "Could not return write format to its original state\n");
+	}
 	ast_free(state);
 }
 
-- 
GitLab