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);