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


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/13@434615 65c4cc65-6c06-0410-ace0-fbb531ad65f3
changes/43/43/1
Richard Mudgett 10 years ago
parent c9791dba1f
commit a63f7ad04a

@ -5268,7 +5268,14 @@ static int set_format(struct ast_channel *chan, struct ast_format_cap *cap_set,
access = &set_format_access_write; 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 */ /* See if the underlying channel driver is capable of performing transcoding for us */
res = ast_channel_setoption(chan, access->setoption, res = ast_channel_setoption(chan, access->setoption,

@ -1271,9 +1271,12 @@ int ast_translator_best_choice(struct ast_format_cap *dst_cap,
{ {
unsigned int besttablecost = INT_MAX; unsigned int besttablecost = INT_MAX;
unsigned int beststeps = 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 *, best, NULL, ao2_cleanup);
RAII_VAR(struct ast_format *, bestdst, 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 i;
int j; int j;
@ -1282,80 +1285,71 @@ int ast_translator_best_choice(struct ast_format_cap *dst_cap,
return -1; 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; return -1;
} }
ast_format_cap_get_compatible(dst_cap, src_cap, joint_cap); ast_format_cap_get_compatible(dst_cap, src_cap, joint_cap);
for (i = 0; i < ast_format_cap_count(joint_cap); ++i) { for (i = 0; i < ast_format_cap_count(joint_cap); ++i, ao2_cleanup(fmt)) {
struct ast_format *fmt = fmt = ast_format_cap_get_format(joint_cap, i);
ast_format_cap_get_format(joint_cap, i); if (!fmt
|| ast_format_get_type(fmt) != AST_MEDIA_TYPE_AUDIO) {
if (!fmt) {
continue;
}
if (!best) {
/* No ao2_ref operations needed, we're done with fmt */
best = fmt;
continue; continue;
} }
if (ast_format_get_sample_rate(best) < if (!best
ast_format_get_sample_rate(fmt)) { || ast_format_get_sample_rate(best) < ast_format_get_sample_rate(fmt)) {
ao2_replace(best, fmt); ao2_replace(best, fmt);
} }
ao2_ref(fmt, -1);
} }
ao2_ref(joint_cap, -1);
if (best) { if (best) {
ao2_replace(*dst_fmt_out, best); ao2_replace(*dst_fmt_out, best);
ao2_replace(*src_fmt_out, best); ao2_replace(*src_fmt_out, best);
return 0; return 0;
} }
/* need to translate */ /* need to translate */
AST_RWLIST_RDLOCK(&translators); AST_RWLIST_RDLOCK(&translators);
for (i = 0; i < ast_format_cap_count(dst_cap); ++i, ao2_cleanup(dst)) {
for (i = 0; i < ast_format_cap_count(dst_cap); ++i) { dst = ast_format_cap_get_format(dst_cap, i);
struct ast_format *dst = if (!dst
ast_format_cap_get_format(dst_cap, i); || ast_format_get_type(dst) != AST_MEDIA_TYPE_AUDIO) {
if (!dst) {
continue; continue;
} }
for (j = 0; j < ast_format_cap_count(src_cap); ++j) { for (j = 0; j < ast_format_cap_count(src_cap); ++j, ao2_cleanup(src)) {
struct ast_format *src = int x;
ast_format_cap_get_format(src_cap, j); int y;
int x, y;
if (!src) { src = ast_format_cap_get_format(src_cap, j);
if (!src
|| ast_format_get_type(src) != AST_MEDIA_TYPE_AUDIO) {
continue; continue;
} }
x = format2index(src); x = format2index(src);
y = format2index(dst); y = format2index(dst);
if (x < 0 || y < 0) { if (x < 0 || y < 0) {
ao2_ref(src, -1);
continue; continue;
} }
if (!matrix_get(x, y) || !(matrix_get(x, y)->step)) { if (!matrix_get(x, y) || !(matrix_get(x, y)->step)) {
ao2_ref(src, -1);
continue; continue;
} }
if (((matrix_get(x, y)->table_cost < besttablecost) || if (matrix_get(x, y)->table_cost < besttablecost
(matrix_get(x, y)->multistep < beststeps))) { || matrix_get(x, y)->multistep < beststeps) {
/* better than what we have so far */ /* better than what we have so far */
ao2_replace(best, src); ao2_replace(best, src);
ao2_replace(bestdst, dst); ao2_replace(bestdst, dst);
besttablecost = matrix_get(x, y)->table_cost; besttablecost = matrix_get(x, y)->table_cost;
beststeps = matrix_get(x, y)->multistep; beststeps = matrix_get(x, y)->multistep;
} }
ao2_ref(src, -1);
} }
ao2_ref(dst, -1);
} }
AST_RWLIST_UNLOCK(&translators); AST_RWLIST_UNLOCK(&translators);
if (!best) { if (!best) {
return -1; return -1;
} }

Loading…
Cancel
Save