translate.c: Only select audio codecs to determine the best translation choice.
authorRichard Mudgett <rmudgett@digium.com>
Fri, 10 Apr 2015 16:32:28 +0000 (16:32 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Fri, 10 Apr 2015 16:32:28 +0000 (16:32 +0000)
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
main/translate.c

index 2d1b6dd..70ced02 100644 (file)
@@ -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,
index bb07d50..2b11d7b 100644 (file)
@@ -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;
        }