diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index eae28af1451ff2bfdc76f36d08e4e86e38b80aaf..b463f9936db50a999c770aedfe94d2171bd08598 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -57,6 +57,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define MAX_DATALEN 8096 +/*! The minimum sample rate of the bridge. */ +#define SOFTMIX_MIN_SAMPLE_RATE 8000 /* 8 kHz sample rate */ + /*! \brief Interval at which mixing will take place. Valid options are 10, 20, and 40. */ #define DEFAULT_SOFTMIX_INTERVAL 20 @@ -96,8 +99,8 @@ struct softmix_channel { struct ast_slinfactory factory; /*! Frame that contains mixed audio to be written out to the channel */ struct ast_frame write_frame; - /*! Frame that contains mixed audio read from the channel */ - struct ast_frame read_frame; + /*! Current expected read slinear format. */ + struct ast_format *read_slin_format; /*! DSP for detecting silence */ struct ast_dsp *dsp; /*! @@ -353,7 +356,9 @@ static void softmix_translate_helper_cleanup(struct softmix_translate_helper *tr static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_channel *bridge_channel, int reset) { struct softmix_channel *sc = bridge_channel->tech_pvt; - unsigned int channel_read_rate = ast_format_get_sample_rate(ast_channel_rawreadformat(bridge_channel->chan)); + struct ast_format *slin_format; + + slin_format = ast_format_cache_get_slin_by_rate(rate); ast_mutex_lock(&sc->lock); if (reset) { @@ -369,31 +374,29 @@ static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_ch * for the channel. The translated format may not be a * static cached format. */ - ao2_replace(sc->write_frame.subclass.format, ast_format_cache_get_slin_by_rate(rate)); + ao2_replace(sc->write_frame.subclass.format, slin_format); sc->write_frame.data.ptr = sc->final_buf; sc->write_frame.datalen = SOFTMIX_DATALEN(rate, interval); sc->write_frame.samples = SOFTMIX_SAMPLES(rate, interval); - /* Setup read frame parameters */ - sc->read_frame.frametype = AST_FRAME_VOICE; /* - * NOTE: The read_frame format does not hold a reference because it + * NOTE: The read_slin_format does not hold a reference because it * will always be a signed linear format. */ - sc->read_frame.subclass.format = ast_format_cache_get_slin_by_rate(channel_read_rate); - sc->read_frame.data.ptr = sc->our_buf; - sc->read_frame.datalen = SOFTMIX_DATALEN(channel_read_rate, interval); - sc->read_frame.samples = SOFTMIX_SAMPLES(channel_read_rate, interval); + sc->read_slin_format = slin_format; /* Setup smoother */ - ast_slinfactory_init_with_format(&sc->factory, sc->write_frame.subclass.format); + ast_slinfactory_init_with_format(&sc->factory, slin_format); /* set new read and write formats on channel. */ - ast_set_read_format(bridge_channel->chan, sc->read_frame.subclass.format); - ast_set_write_format(bridge_channel->chan, sc->write_frame.subclass.format); + ast_channel_lock(bridge_channel->chan); + ast_set_read_format_path(bridge_channel->chan, + ast_channel_rawreadformat(bridge_channel->chan), slin_format); + ast_channel_unlock(bridge_channel->chan); + ast_set_write_format(bridge_channel->chan, slin_format); /* set up new DSP. This is on the read side only right before the read frame enters the smoother. */ - sc->dsp = ast_dsp_new_with_rate(channel_read_rate); + sc->dsp = ast_dsp_new_with_rate(rate); /* we want to aggressively detect silence to avoid feedback */ if (bridge_channel->tech_args.talking_threshold) { ast_dsp_set_threshold(sc->dsp, bridge_channel->tech_args.talking_threshold); @@ -591,6 +594,28 @@ static void softmix_bridge_write_voice(struct ast_bridge *bridge, struct ast_bri /* Write the frame into the conference */ ast_mutex_lock(&sc->lock); + + if (ast_format_cmp(frame->subclass.format, sc->read_slin_format) != AST_FORMAT_CMP_EQUAL) { + /* + * The incoming frame is not the expected format. Update + * the channel's translation path to get us slinear from + * the new format for the next frame. + * + * There is the possibility that this frame is an old slinear + * rate frame that was in flight when the softmix bridge + * changed rates. If so it will self correct on subsequent + * frames. + */ + ast_channel_lock(bridge_channel->chan); + ast_debug(1, "Channel %s wrote unexpected format into bridge. Got %s, expected %s.\n", + ast_channel_name(bridge_channel->chan), + ast_format_get_name(frame->subclass.format), + ast_format_get_name(sc->read_slin_format)); + ast_set_read_format_path(bridge_channel->chan, frame->subclass.format, + sc->read_slin_format); + ast_channel_unlock(bridge_channel->chan); + } + ast_dsp_silence_with_energy(sc->dsp, frame, &totalsilence, &cur_energy); if (bridge->softmix.video_mode.mode == AST_BRIDGE_VIDEO_MODE_TALKER_SRC) { @@ -729,15 +754,19 @@ static void gather_softmix_stats(struct softmix_stats *stats, struct ast_bridge_channel *bridge_channel) { int channel_native_rate; - int i; + /* Gather stats about channel sample rates. */ - channel_native_rate = MAX(ast_format_get_sample_rate(ast_channel_rawwriteformat(bridge_channel->chan)), + ast_channel_lock(bridge_channel->chan); + channel_native_rate = MAX(SOFTMIX_MIN_SAMPLE_RATE, ast_format_get_sample_rate(ast_channel_rawreadformat(bridge_channel->chan))); + ast_channel_unlock(bridge_channel->chan); - if (channel_native_rate > stats->highest_supported_rate) { + if (stats->highest_supported_rate < channel_native_rate) { stats->highest_supported_rate = channel_native_rate; } - if (channel_native_rate > softmix_data->internal_rate) { + if (softmix_data->internal_rate < channel_native_rate) { + int i; + for (i = 0; i < ARRAY_LEN(stats->sample_rates); i++) { if (stats->sample_rates[i] == channel_native_rate) { stats->num_channels[i]++; @@ -749,7 +778,7 @@ static void gather_softmix_stats(struct softmix_stats *stats, } } stats->num_above_internal_rate++; - } else if (channel_native_rate == softmix_data->internal_rate) { + } else if (softmix_data->internal_rate == channel_native_rate) { stats->num_at_internal_rate++; } } @@ -1119,8 +1148,8 @@ static int softmix_bridge_create(struct ast_bridge *bridge) softmix_bridge_data_destroy(softmix_data); return -1; } - /* start at 8khz, let it grow from there */ - softmix_data->internal_rate = 8000; + /* start at minimum rate, let it grow from there */ + softmix_data->internal_rate = SOFTMIX_MIN_SAMPLE_RATE; softmix_data->internal_mixing_interval = DEFAULT_SOFTMIX_INTERVAL; bridge->tech_pvt = softmix_data; diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 745347cb18384f5fdb2cd0284950240503db0c3f..ca0e5cc037261c4febda46ea6b5425e171ad474f 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -629,22 +629,6 @@ static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) return f; } - if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_format_cap *caps; - - ast_debug(1, "Oooh, format changed to %s\n", ast_format_get_name(f->subclass.format)); - - caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (caps) { - ast_format_cap_append(caps, f->subclass.format, 0); - ast_channel_nativeformats_set(ast, caps); - ao2_ref(caps, -1); - } - - ast_set_read_format(ast, ast_channel_readformat(ast)); - ast_set_write_format(ast, ast_channel_writeformat(ast)); - } - if (channel->session->dsp) { f = ast_dsp_process(ast, channel->session->dsp, f); diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 6dd3ac49c974d6dc2eb125d54042783376834c2e..82abe99c1e915c664d6ed72b0f6fba0c2d0414fd 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -1952,6 +1952,21 @@ int ast_write_text(struct ast_channel *chan, struct ast_frame *frame); /*! \brief Send empty audio to prime a channel driver */ int ast_prod(struct ast_channel *chan); +/*! + * \brief Set specific read path on channel. + * \since 13.4.0 + * + * \param chan Channel to setup read path. + * \param raw_format Format to expect from the channel driver. + * \param core_format What the core wants to read. + * + * \pre chan is locked + * + * \retval 0 on success. + * \retval -1 on error. + */ +int ast_set_read_format_path(struct ast_channel *chan, struct ast_format *raw_format, struct ast_format *core_format); + /*! * \brief Sets read format on channel chan from capabilities * Set read format for channel to whichever component of "format" is best. diff --git a/main/channel.c b/main/channel.c index 6aca21ac696efbdfffab9abe23717eabc1d9f3ea..af93956161015e08d0da9d19de45657ca81c3c7d 100644 --- a/main/channel.c +++ b/main/channel.c @@ -4114,78 +4114,133 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) ast_frfree(f); f = &ast_null_frame; } - } else if (f->frametype == AST_FRAME_VOICE && ast_format_cap_iscompatible_format(ast_channel_nativeformats(chan), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - /* This frame is not one of the current native formats -- drop it on the floor */ - struct ast_str *codec_buf = ast_str_alloca(64); - ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %s since our native format has changed to %s\n", - ast_channel_name(chan), ast_format_get_name(f->subclass.format), ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf)); - ast_frfree(f); - f = &ast_null_frame; - } else if (f->frametype == AST_FRAME_VOICE) { - /* Send frame to audiohooks if present */ - if (ast_channel_audiohooks(chan)) { - struct ast_frame *old_frame = f; - f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f); - if (old_frame != f) - ast_frfree(old_frame); + break; + } + if (f->frametype != AST_FRAME_VOICE) { + break; + } + if (ast_format_cmp(f->subclass.format, ast_channel_rawreadformat(chan)) != AST_FORMAT_CMP_EQUAL + && ast_format_cmp(f->subclass.format, ast_channel_readformat(chan)) != AST_FORMAT_CMP_EQUAL) { + struct ast_format *core_format; + + /* + * Note: This frame may not be one of the current native + * formats. We may have gotten it out of the read queue from + * a previous multi-frame translation, from a framehook + * injected frame, or the device we're talking to isn't + * respecting negotiated formats. Regardless we will accept + * all frames. + * + * Update the read translation path to handle the new format + * that just came in. If the core wants slinear we need to + * setup a new translation path because the core is usually + * doing something with the audio itself and may not handle + * any other format. e.g., Softmix bridge, holding bridge + * announcer channel, recording, AMD... Otherwise, we'll + * setup to pass the frame as is to the core. In this case + * the core doesn't care. The channel is likely in + * autoservice, safesleep, or the channel is in a bridge. + * Let the bridge technology deal with format compatibility + * between the channels in the bridge. + * + * Beware of the transcode_via_slin and genericplc options as + * they force any transcoding to go through slin on a bridge. + * Unfortunately transcode_via_slin is enabled by default and + * genericplc is enabled in the codecs.conf.sample file. + * + * XXX Only updating translation to slinear frames has some + * corner cases if slinear is one of the native formats and + * there are different sample rates involved. We might wind + * up with conflicting translation paths between channels + * where the read translation path on this channel reduces + * the sample rate followed by a write translation path on + * the peer channel that increases the sample rate. + */ + core_format = ast_channel_readformat(chan); + if (!ast_format_cache_is_slinear(core_format)) { + core_format = f->subclass.format; + } + if (ast_set_read_format_path(chan, f->subclass.format, core_format)) { + /* Drop frame. We couldn't make it compatible with the core. */ + ast_frfree(f); + f = &ast_null_frame; + break; } - if (ast_channel_monitor(chan) && ast_channel_monitor(chan)->read_stream ) { - /* XXX what does this do ? */ + } + /* Send frame to audiohooks if present */ + if (ast_channel_audiohooks(chan)) { + struct ast_frame *old_frame = f; + + f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f); + if (old_frame != f) { + ast_frfree(old_frame); + } + } + if (ast_channel_monitor(chan) && ast_channel_monitor(chan)->read_stream) { + /* XXX what does this do ? */ #ifndef MONITOR_CONSTANT_DELAY - int jump = ast_channel_outsmpl(chan) - ast_channel_insmpl(chan) - 4 * f->samples; - if (jump >= 0) { - jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)), - ast_format_get_sample_rate(f->subclass.format), - ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format)); - if (ast_seekstream(ast_channel_monitor(chan)->read_stream, jump, SEEK_FORCECUR) == -1) { - ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n"); - } - ast_channel_insmpl_set(chan, ast_channel_insmpl(chan) + (ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)) + f->samples); - } else { - ast_channel_insmpl_set(chan, ast_channel_insmpl(chan) + f->samples); + int jump = ast_channel_outsmpl(chan) - ast_channel_insmpl(chan) - 4 * f->samples; + if (jump >= 0) { + jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)), + ast_format_get_sample_rate(f->subclass.format), + ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format)); + if (ast_seekstream(ast_channel_monitor(chan)->read_stream, jump, SEEK_FORCECUR) == -1) { + ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n"); } + ast_channel_insmpl_set(chan, ast_channel_insmpl(chan) + (ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)) + f->samples); + } else { + ast_channel_insmpl_set(chan, ast_channel_insmpl(chan) + f->samples); + } #else - int jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)), - ast_format_get_sample_rate(f->subclass.codec), - ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format)); - if (jump - MONITOR_DELAY >= 0) { - if (ast_seekstream(ast_channel_monitor(chan)->read_stream, jump - f->samples, SEEK_FORCECUR) == -1) - ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n"); - ast_channel_insmpl(chan) += ast_channel_outsmpl(chan) - ast_channel_insmpl(chan); - } else - ast_channel_insmpl(chan) += f->samples; -#endif - if (ast_channel_monitor(chan)->state == AST_MONITOR_RUNNING) { - if (ast_writestream(ast_channel_monitor(chan)->read_stream, f) < 0) - ast_log(LOG_WARNING, "Failed to write data to channel monitor read stream\n"); + int jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)), + ast_format_get_sample_rate(f->subclass.codec), + ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format)); + if (jump - MONITOR_DELAY >= 0) { + if (ast_seekstream(ast_channel_monitor(chan)->read_stream, jump - f->samples, SEEK_FORCECUR) == -1) { + ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n"); } + ast_channel_insmpl(chan) += ast_channel_outsmpl(chan) - ast_channel_insmpl(chan); + } else { + ast_channel_insmpl(chan) += f->samples; } +#endif + if (ast_channel_monitor(chan)->state == AST_MONITOR_RUNNING) { + if (ast_writestream(ast_channel_monitor(chan)->read_stream, f) < 0) + ast_log(LOG_WARNING, "Failed to write data to channel monitor read stream\n"); + } + } - if (ast_channel_readtrans(chan) && (f = ast_translate(ast_channel_readtrans(chan), f, 1)) == NULL) { + if (ast_channel_readtrans(chan) + && ast_format_cmp(f->subclass.format, ast_channel_rawreadformat(chan)) == AST_FORMAT_CMP_EQUAL) { + f = ast_translate(ast_channel_readtrans(chan), f, 1); + if (!f) { f = &ast_null_frame; } + } - /* it is possible for the translation process on chan->readtrans to have - produced multiple frames from the single input frame we passed it; if - this happens, queue the additional frames *before* the frames we may - have queued earlier. if the readq was empty, put them at the head of - the queue, and if it was not, put them just after the frame that was - at the end of the queue. - */ - if (AST_LIST_NEXT(f, frame_list)) { - if (!readq_tail) { - ast_queue_frame_head(chan, AST_LIST_NEXT(f, frame_list)); - } else { - __ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list), 0, readq_tail); - } - ast_frfree(AST_LIST_NEXT(f, frame_list)); - AST_LIST_NEXT(f, frame_list) = NULL; + /* + * It is possible for the translation process on the channel to have + * produced multiple frames from the single input frame we passed it; if + * this happens, queue the additional frames *before* the frames we may + * have queued earlier. if the readq was empty, put them at the head of + * the queue, and if it was not, put them just after the frame that was + * at the end of the queue. + */ + if (AST_LIST_NEXT(f, frame_list)) { + if (!readq_tail) { + ast_queue_frame_head(chan, AST_LIST_NEXT(f, frame_list)); + } else { + __ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list), 0, readq_tail); } - - /* Run generator sitting on the line if timing device not available - * and synchronous generation of outgoing frames is necessary */ - ast_read_generator_actions(chan, f); + ast_frfree(AST_LIST_NEXT(f, frame_list)); + AST_LIST_NEXT(f, frame_list) = NULL; } + + /* + * Run generator sitting on the line if timing device not available + * and synchronous generation of outgoing frames is necessary + */ + ast_read_generator_actions(chan, f); break; default: /* Just pass it on! */ @@ -5034,29 +5089,35 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) } /* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */ - if (ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) != AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) == AST_FORMAT_CMP_EQUAL) { f = fr; } else { - if ((ast_format_cap_iscompatible_format(ast_channel_nativeformats(chan), fr->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) && - (ast_format_cmp(ast_channel_writeformat(chan), fr->subclass.format) != AST_FORMAT_CMP_EQUAL)) { - struct ast_str *codec_buf = ast_str_alloca(64); + if (ast_format_cmp(ast_channel_writeformat(chan), fr->subclass.format) != AST_FORMAT_CMP_EQUAL) { + struct ast_str *codec_buf = ast_str_alloca(256); /* - * XXX Something is not right. We are not compatible with this - * frame. Bad things can happen. Problems range from no audio, - * one-way audio, to unexplained line hangups. As a last resort - * try to adjust the format. Ideally, we do not want to do this - * because it indicates a deeper problem. For now, we log these - * events to reduce user impact and help identify the problem - * areas. + * We are not setup to write this frame. Things may have changed + * on the peer side of the world and we try to adjust the format to + * make it compatible again. However, bad things can happen if we + * cannot setup a new translation path. Problems range from no + * audio, one-way audio, to garbled audio. The best we can do is + * request the call to hangup since we could not make it compatible. + * + * Being continuously spammed by this message likely indicates a + * problem with the peer because it cannot make up its mind about + * which format to use. */ - ast_log(LOG_WARNING, "Codec mismatch on channel %s setting write format to %s from %s native formats %s\n", - ast_channel_name(chan), ast_format_get_name(fr->subclass.format), ast_format_get_name(ast_channel_writeformat(chan)), + ast_debug(1, "Channel %s changing write format from %s to %s, native formats %s\n", + ast_channel_name(chan), + ast_format_get_name(ast_channel_writeformat(chan)), + ast_format_get_name(fr->subclass.format), ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf)); - ast_set_write_format(chan, fr->subclass.format); + if (ast_set_write_format(chan, fr->subclass.format)) { + /* Could not handle the new write format. Induce a hangup. */ + break; + } } - - f = (ast_channel_writetrans(chan)) ? ast_translate(ast_channel_writetrans(chan), fr, 0) : fr; + f = ast_channel_writetrans(chan) ? ast_translate(ast_channel_writetrans(chan), fr, 0) : fr; } if (!f) { @@ -5216,6 +5277,42 @@ done: return res; } +int ast_set_read_format_path(struct ast_channel *chan, struct ast_format *raw_format, struct ast_format *core_format) +{ + struct ast_trans_pvt *trans_old; + struct ast_trans_pvt *trans_new; + + if (ast_format_cmp(ast_channel_rawreadformat(chan), raw_format) == AST_FORMAT_CMP_EQUAL + && ast_format_cmp(ast_channel_readformat(chan), core_format) == AST_FORMAT_CMP_EQUAL) { + /* Nothing to setup */ + return 0; + } + + ast_debug(1, "Channel %s setting read format path: %s -> %s\n", + ast_channel_name(chan), + ast_format_get_name(raw_format), + ast_format_get_name(core_format)); + + /* Setup new translation path. */ + if (ast_format_cmp(raw_format, core_format) != AST_FORMAT_CMP_EQUAL) { + trans_new = ast_translator_build_path(core_format, raw_format); + if (!trans_new) { + return -1; + } + } else { + /* No translation needed. */ + trans_new = NULL; + } + trans_old = ast_channel_readtrans(chan); + if (trans_old) { + ast_translator_free_path(trans_old); + } + ast_channel_readtrans_set(chan, trans_new); + ast_channel_set_rawreadformat(chan, raw_format); + ast_channel_set_readformat(chan, core_format); + return 0; +} + struct set_format_access { const char *direction; struct ast_trans_pvt *(*get_trans)(const struct ast_channel *chan); @@ -6209,15 +6306,17 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a RAII_VAR(struct ast_format *, best_dst_fmt, NULL, ao2_cleanup); int no_path; - ast_channel_lock_both(from, to); + /* + * We cannot short circuit this code because it is possible to ask + * to make compatible two channels that are "compatible" because + * they already have translation paths setup but together make for + * a sub-optimal path. e.g., The From channel has g722 -> ulaw + * and the To channel has ulaw -> g722. They are "compatible" but + * together the translations are unnecessary and the audio loses + * fidelity in the process. + */ - if ((ast_format_cmp(ast_channel_readformat(from), ast_channel_writeformat(to)) != AST_FORMAT_CMP_NOT_EQUAL) && - (ast_format_cmp(ast_channel_readformat(to), ast_channel_writeformat(from)) != AST_FORMAT_CMP_NOT_EQUAL)) { - /* Already compatible! Moving on ... */ - ast_channel_unlock(to); - ast_channel_unlock(from); - return 0; - } + ast_channel_lock_both(from, to); src_cap = ast_channel_nativeformats(from); /* shallow copy, do not destroy */ dst_cap = ast_channel_nativeformats(to); /* shallow copy, do not destroy */ diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 2ecd11a84404f3363914938bef7cd7c505ffc804..7756179b3249a6e6efc1eff859cefbd7da51fbc6 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -252,8 +252,8 @@ static int set_caps(struct ast_sip_session *session, struct ast_sip_session_medi /* get the joint capabilities between peer and endpoint */ ast_format_cap_get_compatible(caps, peer, joint); if (!ast_format_cap_count(joint)) { - struct ast_str *usbuf = ast_str_alloca(64); - struct ast_str *thembuf = ast_str_alloca(64); + struct ast_str *usbuf = ast_str_alloca(256); + struct ast_str *thembuf = ast_str_alloca(256); ast_rtp_codecs_payloads_destroy(&codecs); ast_log(LOG_NOTICE, "No joint capabilities for '%s' media stream between our configuration(%s) and incoming SDP(%s)\n", @@ -269,33 +269,22 @@ static int set_caps(struct ast_sip_session *session, struct ast_sip_session_medi ast_format_cap_append_from_cap(session->req_caps, joint, AST_MEDIA_TYPE_UNKNOWN); if (session->channel) { - struct ast_format *fmt; - ast_channel_lock(session->channel); ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN); - ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_UNKNOWN); + 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); - - /* - * XXX Historically we picked the "best" joint format to use - * and stuck with it. It would be nice to just append the - * determined joint media capabilities to give translation - * more formats to choose from when necessary. Unfortunately, - * there are some areas of the system where this doesn't work - * very well. (The softmix bridge in particular is reluctant - * to pick higher fidelity formats and has a problem with - * asymmetric sample rates.) - */ - fmt = ast_format_cap_get_format(joint, 0); - ast_format_cap_append(caps, fmt, 0); + ast_format_cap_append_from_cap(caps, joint, media_type); /* * 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_set_read_format(session->channel, ast_channel_readformat(session->channel)); - ast_set_write_format(session->channel, ast_channel_writeformat(session->channel)); + if (media_type == AST_MEDIA_TYPE_AUDIO) { + ast_set_read_format(session->channel, ast_channel_readformat(session->channel)); + ast_set_write_format(session->channel, ast_channel_writeformat(session->channel)); + } if ((session->endpoint->dtmf == AST_SIP_DTMF_AUTO) && (ast_rtp_instance_dtmf_mode_get(session_media->rtp) == AST_RTP_DTMF_MODE_RFC2833) && (session->dsp)) { @@ -309,8 +298,6 @@ static int set_caps(struct ast_sip_session *session, struct ast_sip_session_medi } } ast_channel_unlock(session->channel); - - ao2_ref(fmt, -1); } ast_rtp_codecs_payloads_destroy(&codecs);