From 0b805cb87526fd229e3f2811f95d3ba9b4fd64f0 Mon Sep 17 00:00:00 2001
From: Richard Mudgett <rmudgett@digium.com>
Date: Fri, 10 Apr 2015 16:32:28 +0000
Subject: [PATCH] translate.c: Only select audio codecs to determine the best
 translation choice.

Given a source capability of h264 and ulaw, a destination capability of
h264 and g722 then ast_translator_best_choice() would pick h264 as the
best choice even though h264 is a video codec and Asterisk only supports
translation of audio codecs.  When the audio starts flowing, there are
warnings about a codec mismatch when the channel tries to write a frame to
the peer.

* Made ast_translator_best_choice() only select audio codecs.

* Restore a check in channel.c:set_format() lost after v1.8 to prevent
trying to set a non-audio codec.

This is an intermediate patch for a series of patches aimed at improving
translation path choices for ASTERISK-24841.

This patch is a complete enough fix for ASTERISK-21777 as the v11 version
of ast_translator_best_choice() does the same thing.  However, chan_sip.c
still somehow tries to call ast_codec_choose() which then calls
ast_best_codec() with a capability set that doesn't contain any audio
formats for the incoming call.  The remaining warning message seems to be
a benign transient.

ASTERISK-21777 #close
Reported by: Nick Ruggles

ASTERISK-24380 #close
Reported by: Matt Jordan

Review: https://reviewboard.asterisk.org/r/4605/
........

Merged revisions 434614 from http://svn.asterisk.org/svn/asterisk/branches/11
........

Merged revisions 434615 from http://svn.asterisk.org/svn/asterisk/branches/13


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@434616 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 main/channel.c   |  9 +++++++-
 main/translate.c | 60 ++++++++++++++++++++++--------------------------
 2 files changed, 35 insertions(+), 34 deletions(-)

diff --git a/main/channel.c b/main/channel.c
index 2d1b6ddd1e..70ced02107 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -5268,7 +5268,14 @@ static int set_format(struct ast_channel *chan, struct ast_format_cap *cap_set,
 		access = &set_format_access_write;
 	}
 
-	best_set_fmt = ast_format_cap_get_format(cap_set, 0);
+	best_set_fmt = ast_format_cap_get_best_by_type(cap_set, AST_MEDIA_TYPE_AUDIO);
+	if (!best_set_fmt) {
+		/*
+		 * Not setting any audio formats?
+		 * Assume a call without any sounds (video, text)
+		 */
+		return 0;
+	}
 
 	/* See if the underlying channel driver is capable of performing transcoding for us */
 	res = ast_channel_setoption(chan, access->setoption,
diff --git a/main/translate.c b/main/translate.c
index bb07d50ab2..2b11d7b4a1 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -1271,9 +1271,12 @@ int ast_translator_best_choice(struct ast_format_cap *dst_cap,
 {
 	unsigned int besttablecost = INT_MAX;
 	unsigned int beststeps = INT_MAX;
+	struct ast_format *fmt;
+	struct ast_format *dst;
+	struct ast_format *src;
 	RAII_VAR(struct ast_format *, best, NULL, ao2_cleanup);
 	RAII_VAR(struct ast_format *, bestdst, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_format_cap *, joint_cap, NULL, ao2_cleanup);
+	struct ast_format_cap *joint_cap;
 	int i;
 	int j;
 
@@ -1282,80 +1285,71 @@ int ast_translator_best_choice(struct ast_format_cap *dst_cap,
 		return -1;
 	}
 
-	if (!(joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+	joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	if (!joint_cap) {
 		return -1;
 	}
 	ast_format_cap_get_compatible(dst_cap, src_cap, joint_cap);
 
-	for (i = 0; i < ast_format_cap_count(joint_cap); ++i) {
-		struct ast_format *fmt =
-			ast_format_cap_get_format(joint_cap, i);
-
-		if (!fmt) {
-			continue;
-		}
-
-		if (!best) {
-			/* No ao2_ref operations needed, we're done with fmt */
-			best = fmt;
+	for (i = 0; i < ast_format_cap_count(joint_cap); ++i, ao2_cleanup(fmt)) {
+		fmt = ast_format_cap_get_format(joint_cap, i);
+		if (!fmt
+			|| ast_format_get_type(fmt) != AST_MEDIA_TYPE_AUDIO) {
 			continue;
 		}
 
-		if (ast_format_get_sample_rate(best) <
-		    ast_format_get_sample_rate(fmt)) {
+		if (!best
+			|| ast_format_get_sample_rate(best) < ast_format_get_sample_rate(fmt)) {
 			ao2_replace(best, fmt);
 		}
-		ao2_ref(fmt, -1);
 	}
+	ao2_ref(joint_cap, -1);
 
 	if (best) {
 		ao2_replace(*dst_fmt_out, best);
 		ao2_replace(*src_fmt_out, best);
 		return 0;
 	}
+
 	/* need to translate */
 	AST_RWLIST_RDLOCK(&translators);
-
-	for (i = 0; i < ast_format_cap_count(dst_cap); ++i) {
-		struct ast_format *dst =
-			ast_format_cap_get_format(dst_cap, i);
-
-		if (!dst) {
+	for (i = 0; i < ast_format_cap_count(dst_cap); ++i, ao2_cleanup(dst)) {
+		dst = ast_format_cap_get_format(dst_cap, i);
+		if (!dst
+			|| ast_format_get_type(dst) != AST_MEDIA_TYPE_AUDIO) {
 			continue;
 		}
 
-		for (j = 0; j < ast_format_cap_count(src_cap); ++j) {
-			struct ast_format *src =
-				ast_format_cap_get_format(src_cap, j);
-			int x, y;
+		for (j = 0; j < ast_format_cap_count(src_cap); ++j, ao2_cleanup(src)) {
+			int x;
+			int y;
 
-			if (!src) {
+			src = ast_format_cap_get_format(src_cap, j);
+			if (!src
+				|| ast_format_get_type(src) != AST_MEDIA_TYPE_AUDIO) {
 				continue;
 			}
 
 			x = format2index(src);
 			y = format2index(dst);
 			if (x < 0 || y < 0) {
-				ao2_ref(src, -1);
 				continue;
 			}
 			if (!matrix_get(x, y) || !(matrix_get(x, y)->step)) {
-				ao2_ref(src, -1);
 				continue;
 			}
-			if (((matrix_get(x, y)->table_cost < besttablecost) ||
-			     (matrix_get(x, y)->multistep < beststeps))) {
+			if (matrix_get(x, y)->table_cost < besttablecost
+				|| matrix_get(x, y)->multistep < beststeps) {
 				/* better than what we have so far */
 				ao2_replace(best, src);
 				ao2_replace(bestdst, dst);
 				besttablecost = matrix_get(x, y)->table_cost;
 				beststeps = matrix_get(x, y)->multistep;
 			}
-			ao2_ref(src, -1);
 		}
-		ao2_ref(dst, -1);
 	}
 	AST_RWLIST_UNLOCK(&translators);
+
 	if (!best) {
 		return -1;
 	}
-- 
GitLab