summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bridges/bridge_softmix.c73
-rw-r--r--channels/chan_pjsip.c16
-rw-r--r--include/asterisk/channel.h15
-rw-r--r--main/channel.c267
-rw-r--r--res/res_pjsip_sdp_rtp.c31
5 files changed, 258 insertions, 144 deletions
diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c
index eae28af14..b463f9936 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 745347cb1..ca0e5cc03 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 6dd3ac49c..82abe99c1 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -1953,6 +1953,21 @@ int ast_write_text(struct ast_channel *chan, struct ast_frame *frame);
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.
* \param chan channel to change
diff --git a/main/channel.c b/main/channel.c
index 6aca21ac6..af9395616 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 2ecd11a84..7756179b3 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);