diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 0c535d703f0a413e1f92cbd91e08deca10a69ed5..7680aec54ccaf52e5fa8dac1e805346d659706fc 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -58,6 +58,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stasis_channels.h" #include "asterisk/indications.h" #include "asterisk/format_cache.h" +#include "asterisk/translate.h" #include "asterisk/threadstorage.h" #include "asterisk/features_config.h" #include "asterisk/pickup.h" @@ -654,14 +655,21 @@ static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *frame) return 0; } if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(128); + struct ast_str *write_transpath = ast_str_alloca(256); + struct ast_str *read_transpath = ast_str_alloca(256); ast_log(LOG_WARNING, - "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", + "Channel %s asked to send %s frame when native formats are %s (rd:%s->%s;%s wr:%s->%s;%s)\n", + ast_channel_name(ast), ast_format_get_name(frame->subclass.format), ast_format_cap_get_names(ast_channel_nativeformats(ast), &cap_buf), + ast_format_get_name(ast_channel_rawreadformat(ast)), ast_format_get_name(ast_channel_readformat(ast)), - ast_format_get_name(ast_channel_writeformat(ast))); + ast_translate_path_to_str(ast_channel_readtrans(ast), &read_transpath), + ast_format_get_name(ast_channel_writeformat(ast)), + ast_format_get_name(ast_channel_rawwriteformat(ast)), + ast_translate_path_to_str(ast_channel_writetrans(ast), &write_transpath)); return 0; } if (media->rtp) { diff --git a/main/bridge.c b/main/bridge.c index a3ca8a97696d6056ea3409caa6f2db06369e1794..0478e4686d5f20677f10b34bf67af8faaa4254c5 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -939,12 +939,14 @@ int ast_bridge_destroy(struct ast_bridge *bridge, int cause) static int bridge_make_compatible(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { struct ast_str *codec_buf = ast_str_alloca(64); - struct ast_format *read_format; - struct ast_format *write_format; struct ast_format *best_format; + RAII_VAR(struct ast_format *, read_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, write_format, NULL, ao2_cleanup); - read_format = ast_channel_readformat(bridge_channel->chan); - write_format = ast_channel_writeformat(bridge_channel->chan); + ast_channel_lock(bridge_channel->chan); + read_format = ao2_bump(ast_channel_readformat(bridge_channel->chan)); + write_format = ao2_bump(ast_channel_writeformat(bridge_channel->chan)); + ast_channel_unlock(bridge_channel->chan); /* Are the formats currently in use something this bridge can handle? */ if (ast_format_cap_iscompatible_format(bridge->technology->format_capabilities, read_format) == AST_FORMAT_CMP_NOT_EQUAL) { diff --git a/main/bridge_channel.c b/main/bridge_channel.c index f6b46654550bd5cc977f859b895cd134d1d1a3f5..5bf85126adc4ed9b281c8bef7d2dede31fb2a9f0 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -323,6 +323,8 @@ void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channe ast_assert(bridge_channel->read_format != NULL); ast_assert(bridge_channel->write_format != NULL); + ast_channel_lock(bridge_channel->chan); + /* Restore original formats of the channel as they came in */ if (ast_format_cmp(ast_channel_readformat(bridge_channel->chan), bridge_channel->read_format) == AST_FORMAT_CMP_NOT_EQUAL) { ast_debug(1, "Bridge is returning %p(%s) to read format %s\n", @@ -344,6 +346,8 @@ void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channe ast_format_get_name(bridge_channel->write_format)); } } + + ast_channel_unlock(bridge_channel->chan); } struct ast_bridge *ast_bridge_channel_merge_inhibit(struct ast_bridge_channel *bridge_channel, int request) @@ -2354,9 +2358,6 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel) int res = 0; struct ast_bridge_features *channel_features; - bridge_channel->read_format = ao2_bump(ast_channel_readformat(bridge_channel->chan)); - bridge_channel->write_format = ao2_bump(ast_channel_writeformat(bridge_channel->chan)); - ast_debug(1, "Bridge %s: %p(%s) is joining\n", bridge_channel->bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan)); @@ -2368,6 +2369,10 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel) ast_bridge_lock(bridge_channel->bridge); ast_channel_lock(bridge_channel->chan); + + bridge_channel->read_format = ao2_bump(ast_channel_readformat(bridge_channel->chan)); + bridge_channel->write_format = ao2_bump(ast_channel_writeformat(bridge_channel->chan)); + /* Make sure we're still good to be put into a bridge */ if (ast_channel_internal_bridge(bridge_channel->chan) || ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_ZOMBIE)) { diff --git a/main/channel.c b/main/channel.c index 8e9f13dc974fef3f8d623e890599dd6f57add2d6..4595b5944c0c1fca65ac59399165bf4aebded545 100644 --- a/main/channel.c +++ b/main/channel.c @@ -5229,54 +5229,86 @@ done: return res; } -struct set_format_trans_access { - struct ast_trans_pvt *(*get)(const struct ast_channel *chan); - void (*set)(struct ast_channel *chan, struct ast_trans_pvt *value); +struct set_format_access { + const char *direction; + struct ast_trans_pvt *(*get_trans)(const struct ast_channel *chan); + void (*set_trans)(struct ast_channel *chan, struct ast_trans_pvt *value); + struct ast_format *(*get_format)(struct ast_channel *chan); + void (*set_format)(struct ast_channel *chan, struct ast_format *format); + struct ast_format *(*get_rawformat)(struct ast_channel *chan); + void (*set_rawformat)(struct ast_channel *chan, struct ast_format *format); + int setoption; }; -static const struct set_format_trans_access set_format_readtrans = { - .get = ast_channel_readtrans, - .set = ast_channel_readtrans_set, +static const struct set_format_access set_format_access_read = { + .direction = "read", + .get_trans = ast_channel_readtrans, + .set_trans = ast_channel_readtrans_set, + .get_format = ast_channel_readformat, + .set_format = ast_channel_set_readformat, + .get_rawformat = ast_channel_rawreadformat, + .set_rawformat = ast_channel_set_rawreadformat, + .setoption = AST_OPTION_FORMAT_READ, }; -static const struct set_format_trans_access set_format_writetrans = { - .get = ast_channel_writetrans, - .set = ast_channel_writetrans_set, +static const struct set_format_access set_format_access_write = { + .direction = "write", + .get_trans = ast_channel_writetrans, + .set_trans = ast_channel_writetrans_set, + .get_format = ast_channel_writeformat, + .set_format = ast_channel_set_writeformat, + .get_rawformat = ast_channel_rawwriteformat, + .set_rawformat = ast_channel_set_rawwriteformat, + .setoption = AST_OPTION_FORMAT_WRITE, }; -static int set_format(struct ast_channel *chan, - struct ast_format_cap *cap_set, - struct ast_format *rawformat, - struct ast_format *format, - const struct set_format_trans_access *trans, - const int direction) +static int set_format(struct ast_channel *chan, struct ast_format_cap *cap_set, const int direction) { struct ast_trans_pvt *trans_pvt; struct ast_format_cap *cap_native; - RAII_VAR(struct ast_format *, best_set_fmt, ast_format_cap_get_format(cap_set, 0), ao2_cleanup); + const struct set_format_access *access; + struct ast_format *rawformat; + struct ast_format *format; + RAII_VAR(struct ast_format *, best_set_fmt, NULL, ao2_cleanup); RAII_VAR(struct ast_format *, best_native_fmt, NULL, ao2_cleanup); int res; - ast_assert(format != NULL); - ast_assert(rawformat != NULL); + if (!direction) { + /* reading */ + access = &set_format_access_read; + } else { + /* writing */ + access = &set_format_access_write; + } + + best_set_fmt = ast_format_cap_get_format(cap_set, 0); /* See if the underlying channel driver is capable of performing transcoding for us */ - if (!ast_channel_setoption(chan, direction ? AST_OPTION_FORMAT_WRITE : AST_OPTION_FORMAT_READ, &best_set_fmt, sizeof(best_set_fmt), 0)) { - ast_debug(1, "Channel driver natively set channel %s to %s format %s\n", ast_channel_name(chan), - direction ? "write" : "read", ast_format_get_name(best_set_fmt)); + res = ast_channel_setoption(chan, access->setoption, + &best_set_fmt, sizeof(best_set_fmt), 0); + if (!res) { + ast_debug(1, "Channel driver natively set channel %s to %s format %s\n", + ast_channel_name(chan), access->direction, ast_format_get_name(best_set_fmt)); ast_channel_lock(chan); cap_native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - ast_format_cap_append(cap_native, best_set_fmt, 0); + if (!cap_native + || ast_format_cap_append(cap_native, best_set_fmt, 0)) { + ast_channel_unlock(chan); + ao2_cleanup(cap_native); + return -1; + } ast_channel_nativeformats_set(chan, cap_native); ao2_cleanup(cap_native); - ast_channel_unlock(chan); + access->set_format(chan, best_set_fmt); + access->set_rawformat(chan, best_set_fmt); - trans_pvt = trans->get(chan); + trans_pvt = access->get_trans(chan); if (trans_pvt) { ast_translator_free_path(trans_pvt); - trans->set(chan, NULL); + access->set_trans(chan, NULL); } + ast_channel_unlock(chan); /* If there is a generator on the channel, it needs to know about this * change if it is the write format. */ @@ -5288,6 +5320,12 @@ static int set_format(struct ast_channel *chan, } ast_channel_lock(chan); + + format = access->get_format(chan); + rawformat = access->get_rawformat(chan); + ast_assert(format != NULL); + ast_assert(rawformat != NULL); + cap_native = ast_channel_nativeformats(chan); /* Find a translation path from the native format to one of the desired formats */ @@ -5314,17 +5352,17 @@ static int set_format(struct ast_channel *chan, /* Now we have a good choice for both. */ if ((ast_format_cmp(rawformat, best_native_fmt) != AST_FORMAT_CMP_NOT_EQUAL) && (ast_format_cmp(format, best_set_fmt) != AST_FORMAT_CMP_NOT_EQUAL) && - ((ast_format_cmp(rawformat, format) != AST_FORMAT_CMP_NOT_EQUAL) || trans->get(chan))) { + ((ast_format_cmp(rawformat, format) != AST_FORMAT_CMP_NOT_EQUAL) || access->get_trans(chan))) { /* the channel is already in these formats, so nothing to do */ ast_channel_unlock(chan); return 0; } /* Free any translation we have right now */ - trans_pvt = trans->get(chan); + trans_pvt = access->get_trans(chan); if (trans_pvt) { ast_translator_free_path(trans_pvt); - trans->set(chan, NULL); + access->set_trans(chan, NULL); } /* Build a translation path from the raw format to the desired format */ @@ -5343,24 +5381,17 @@ static int set_format(struct ast_channel *chan, /* writing */ trans_pvt = ast_translator_build_path(best_native_fmt, best_set_fmt); } - trans->set(chan, trans_pvt); + access->set_trans(chan, trans_pvt); res = trans_pvt ? 0 : -1; } if (!res) { - if (!direction) { - /* reading */ - ast_channel_set_readformat(chan, best_set_fmt); - ast_channel_set_rawreadformat(chan, best_native_fmt); - } else { - /* writing */ - ast_channel_set_writeformat(chan, best_set_fmt); - ast_channel_set_rawwriteformat(chan, best_native_fmt); - } + access->set_format(chan, best_set_fmt); + access->set_rawformat(chan, best_native_fmt); ast_debug(1, "Set channel %s to %s format %s\n", ast_channel_name(chan), - direction ? "write" : "read", + access->direction, ast_format_get_name(best_set_fmt)); } @@ -5387,12 +5418,7 @@ int ast_set_read_format(struct ast_channel *chan, struct ast_format *format) } ast_format_cap_append(cap, format, 0); - res = set_format(chan, - cap, - ast_channel_rawreadformat(chan), - ast_channel_readformat(chan), - &set_format_readtrans, - 0); + res = set_format(chan, cap, 0); ao2_cleanup(cap); return res; @@ -5400,12 +5426,7 @@ int ast_set_read_format(struct ast_channel *chan, struct ast_format *format) int ast_set_read_format_from_cap(struct ast_channel *chan, struct ast_format_cap *cap) { - return set_format(chan, - cap, - ast_channel_rawreadformat(chan), - ast_channel_readformat(chan), - &set_format_readtrans, - 0); + return set_format(chan, cap, 0); } int ast_set_write_format(struct ast_channel *chan, struct ast_format *format) @@ -5420,12 +5441,7 @@ int ast_set_write_format(struct ast_channel *chan, struct ast_format *format) } ast_format_cap_append(cap, format, 0); - res = set_format(chan, - cap, - ast_channel_rawwriteformat(chan), - ast_channel_writeformat(chan), - &set_format_writetrans, - 1); + res = set_format(chan, cap, 1); ao2_cleanup(cap); return res; @@ -5433,12 +5449,7 @@ int ast_set_write_format(struct ast_channel *chan, struct ast_format *format) int ast_set_write_format_from_cap(struct ast_channel *chan, struct ast_format_cap *cap) { - return set_format(chan, - cap, - ast_channel_rawwriteformat(chan), - ast_channel_writeformat(chan), - &set_format_writetrans, - 1); + return set_format(chan, cap, 1); } const char *ast_channel_reason2str(int reason) diff --git a/main/file.c b/main/file.c index b12883d4916bb3a6c0439ffd6236f5f64f6dfdf5..393832cdd31735c8ed4f9255b54d98fd088e5377 100644 --- a/main/file.c +++ b/main/file.c @@ -777,9 +777,11 @@ struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char } /* Set the channel to a format we can work with and save off the previous format. */ + ast_channel_lock(chan); ast_channel_set_oldwriteformat(chan, ast_channel_writeformat(chan)); /* Set the channel to the best format that exists for the file. */ res = ast_set_write_format_from_cap(chan, file_fmt_cap); + ast_channel_unlock(chan); /* don't need this anymore now that the channel's write format is set. */ ao2_ref(file_fmt_cap, -1); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index ca018c86b5a1e7e6fb1d39da713e79719cf97987..938d5ea9298aa67d6565274f0b1f35fe8e6767cb 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -265,15 +265,20 @@ static int set_caps(struct ast_sip_session *session, struct ast_sip_session_medi if (session->channel) { struct ast_format *fmt; + ast_channel_lock(session->channel); ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_UNKNOWN); ast_format_cap_remove_by_type(caps, media_type); fmt = ast_format_cap_get_format(joint, 0); ast_format_cap_append(caps, fmt, 0); - /* Apply the new formats to the channel, potentially changing read/write formats while doing so */ + /* + * Apply the new formats to the channel, potentially changing + * raw read/write formats and translation path while doing so. + */ ast_channel_nativeformats_set(session->channel, caps); - ast_channel_set_rawwriteformat(session->channel, fmt); - ast_channel_set_rawreadformat(session->channel, fmt); + ast_set_read_format(session->channel, ast_channel_readformat(session->channel)); + ast_set_write_format(session->channel, ast_channel_writeformat(session->channel)); + ast_channel_unlock(session->channel); ao2_ref(fmt, -1); }