diff --git a/CHANGES b/CHANGES
index 5fe4a19189cb8b98b783392ea1fb2e3b642f463b..2f47a04d971025950f3df71162e264607444ba0c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -543,6 +543,8 @@ Miscellaneous
  * The UNISTIM channel driver (chan_unistim) has been updated to support devices that
    have less than 3 lines on the LCD.
  * Realtime now supports database failover.  See the sample extconfig.conf for details.
+ * The addition of improved translation path building for wideband codecs.  Sample
+   rate changes during translation are now avoided unless absolutely necessary.
 
 CLI Changes
 -----------
diff --git a/include/asterisk/translate.h b/include/asterisk/translate.h
index 1d87adbf53af2d83098e1a8544460e6298fdb413..821463bf19865d3315cdf9aae4b35636a8f080ea 100644
--- a/include/asterisk/translate.h
+++ b/include/asterisk/translate.h
@@ -254,6 +254,14 @@ unsigned int ast_translate_path_steps(format_t dest, format_t src);
  */
 format_t ast_translate_available_formats(format_t dest, format_t src);
 
+/*!
+ * \brief Puts a string representation of the translation path into outbuf
+ * \param translator structure containing the translation path
+ * \param ast_str output buffer
+ * \retval on success pointer to beginning of outbuf. on failure "".
+ */
+const char *ast_translate_path_to_str(struct ast_trans_pvt *t, struct ast_str **str);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
diff --git a/main/cli.c b/main/cli.c
index ebb7deb6d437e6a01b9c5e08f5ab20e28eb790de..3c14879c038a342f321ac658c403006df669fe50 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -46,6 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/lock.h"
 #include "editline/readline/readline.h"
 #include "asterisk/threadstorage.h"
+#include "asterisk/translate.h"
 
 /*!
  * \brief List of restrictions per user.
@@ -1343,6 +1344,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 	struct ast_str *out = ast_str_thread_get(&ast_str_thread_global_buf, 16);
 	char cdrtime[256];
 	char nf[256], wf[256], rf[256];
+	struct ast_str *write_transpath = ast_str_alloca(256);
+	struct ast_str *read_transpath = ast_str_alloca(256);
 	long elapsed_seconds=0;
 	int hour=0, min=0, sec=0;
 #ifdef CHANNEL_TRACE
@@ -1398,8 +1401,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 		"  NativeFormats: %s\n"
 		"    WriteFormat: %s\n"
 		"     ReadFormat: %s\n"
-		" WriteTranscode: %s\n"
-		"  ReadTranscode: %s\n"
+		" WriteTranscode: %s %s\n"
+		"  ReadTranscode: %s %s\n"
 		"1st File Descriptor: %d\n"
 		"      Frames in: %d%s\n"
 		"     Frames out: %d%s\n"
@@ -1426,7 +1429,9 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 		ast_getformatname_multiple(wf, sizeof(wf), c->writeformat), 
 		ast_getformatname_multiple(rf, sizeof(rf), c->readformat),
 		c->writetrans ? "Yes" : "No",
+		ast_translate_path_to_str(c->writetrans, &write_transpath),
 		c->readtrans ? "Yes" : "No",
+		ast_translate_path_to_str(c->readtrans, &read_transpath),
 		c->fds[0],
 		c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
 		c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
diff --git a/main/translate.c b/main/translate.c
index 24d886473245fa481f53d4e18791882460803d5a..61b4a4686d83065aa83c0ba7eb053e896a00adcf 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -45,10 +45,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 /*! \brief the list of translators */
 static AST_RWLIST_HEAD_STATIC(translators, ast_translator);
 
+
+/*! \brief these values indicate how a translation path will affect the sample rate
+ *
+ *  \note These must stay in this order.  They are ordered by most optimal selection first.
+ */
+enum path_samp_change {
+	RATE_CHANGE_NONE = 0, /*!< path uses the same sample rate consistently */
+	RATE_CHANGE_UPSAMP = 1, /*!< path will up the sample rate during a translation */
+	RATE_CHANGE_DOWNSAMP = 2, /*!< path will have to down the sample rate during a translation. */
+	RATE_CHANGE_UPSAMP_DOWNSAMP = 3, /*!< path will both up and down the sample rate during translation */
+};
+
 struct translator_path {
 	struct ast_translator *step;	/*!< Next step translator */
 	unsigned int cost;		/*!< Complete cost to destination */
 	unsigned int multistep;		/*!< Multiple conversions required for this translation */
+	enum path_samp_change rate_change; /*!< does this path require a sample rate change, if so what kind. */
 };
 
 /*! \brief a matrix that, for any pair of supported formats,
@@ -402,6 +415,24 @@ static void calc_cost(struct ast_translator *t, int seconds)
 		t->cost = 1;
 }
 
+static enum path_samp_change get_rate_change_result(format_t src, format_t dst)
+{
+	int src_rate = ast_format_rate(src);
+	int dst_rate = ast_format_rate(dst);
+
+	/* if src rate is less than dst rate, a sample upgrade is required */
+	if (src_rate < dst_rate) {
+		return RATE_CHANGE_UPSAMP;
+	}
+
+	/* if src rate is larger than dst rate, a downgrade is required */
+	if (src_rate > dst_rate) {
+		return RATE_CHANGE_DOWNSAMP;
+	}
+
+	return RATE_CHANGE_NONE;
+}
+
 /*!
  * \brief rebuild a translation matrix.
  * \note This function expects the list of translators to be locked
@@ -409,6 +440,8 @@ static void calc_cost(struct ast_translator *t, int seconds)
 static void rebuild_matrix(int samples)
 {
 	struct ast_translator *t;
+	int new_rate_change;
+	int newcost;
 	int x;      /* source format index */
 	int y;      /* intermediate format index */
 	int z;      /* destination format index */
@@ -427,10 +460,21 @@ static void rebuild_matrix(int samples)
 
 		if (samples)
 			calc_cost(t, samples);
-	  
-		if (!tr_matrix[x][z].step || t->cost < tr_matrix[x][z].cost) {
+
+		new_rate_change = get_rate_change_result(1LL << t->srcfmt, 1LL << t->dstfmt);
+
+		/* this translator is the best choice if any of the below are true.
+		 * 1. no translation path is set between x and z yet.
+		 * 2. the new translation costs less and sample rate is no worse than old one. 
+		 * 3. the new translation has a better sample rate conversion than the old one.
+		 */
+		if (!tr_matrix[x][z].step ||
+			((t->cost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) ||
+			(new_rate_change < tr_matrix[x][z].rate_change)) {
+
 			tr_matrix[x][z].step = t;
 			tr_matrix[x][z].cost = t->cost;
+			tr_matrix[x][z].rate_change = new_rate_change;
 		}
 	}
 
@@ -442,31 +486,73 @@ static void rebuild_matrix(int samples)
 	 */
 	for (;;) {
 		int changed = 0;
+		int better_choice = 0;
 		for (x = 0; x < MAX_FORMAT; x++) {      /* source format */
 			for (y = 0; y < MAX_FORMAT; y++) {    /* intermediate format */
 				if (x == y)                     /* skip ourselves */
 					continue;
-
-				for (z = 0; z<MAX_FORMAT; z++) {  /* dst format */
-					int newcost;
-
+				for (z = 0; z < MAX_FORMAT; z++) {  /* dst format */
 					if (z == x || z == y)       /* skip null conversions */
 						continue;
 					if (!tr_matrix[x][y].step)  /* no path from x to y */
 						continue;
 					if (!tr_matrix[y][z].step)  /* no path from y to z */
 						continue;
+
+					/* Does x->y->z result in a less optimal sample rate change?
+					 * Never downgrade the sample rate conversion quality regardless
+					 * of any cost improvements */
+					if (tr_matrix[x][z].step &&
+						((tr_matrix[x][z].rate_change < tr_matrix[x][y].rate_change) ||
+						(tr_matrix[x][z].rate_change < tr_matrix[y][z].rate_change))) {
+						continue;
+					}
+
+					/* is x->y->z a better sample rate confersion that the current x->z? */
+					new_rate_change = tr_matrix[x][y].rate_change + tr_matrix[y][z].rate_change;
+
+					/* calculate cost from x->y->z */
 					newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost;
-					if (tr_matrix[x][z].step && newcost >= tr_matrix[x][z].cost)
-						continue;               /* x->y->z is more expensive than
-						                         * the existing path */
+
+					/* Is x->y->z a better choice than x->z?
+					 * There are three conditions for x->y->z to be a better choice than x->z
+					 * 1. if there is no step directly between x->z then x->y->z is the best and only current option.
+					 * 2. if x->y->z costs less and the sample rate conversion is no less optimal.
+					 * 3. if x->y->z results in a more optimal sample rate conversion. */
+					if (!tr_matrix[x][z].step) {
+						better_choice = 1;
+					} else if ((newcost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) {
+						better_choice = 1;
+					} else if (new_rate_change < tr_matrix[x][z].rate_change) {
+						better_choice = 1;
+					} else {
+						better_choice = 0;
+					}
+
+					if (!better_choice) {
+						continue;
+					}
 					/* ok, we can get from x to z via y with a cost that
-					   is the sum of the transition from x to y and
-					   from y to z */
-						 
+					   is the sum of the transition from x to y and from y to z */
 					tr_matrix[x][z].step = tr_matrix[x][y].step;
 					tr_matrix[x][z].cost = newcost;
 					tr_matrix[x][z].multistep = 1;
+
+					/* now calculate what kind of sample rate change is required for this multi-step path
+					 * 
+					 * if both paths require a change in rate, and they are not in the same direction
+					 * then this is a up sample down sample conversion scenario. */
+					if ((tr_matrix[x][y].rate_change > RATE_CHANGE_NONE) &&
+						(tr_matrix[y][z].rate_change > RATE_CHANGE_NONE) &&
+						(tr_matrix[x][y].rate_change != tr_matrix[y][z].rate_change)) {
+
+						tr_matrix[x][z].rate_change = RATE_CHANGE_UPSAMP_DOWNSAMP;
+					} else {
+						/* else just set the rate change to whichever is worse */
+						tr_matrix[x][z].rate_change = tr_matrix[x][y].rate_change > tr_matrix[y][z].rate_change
+							? tr_matrix[x][y].rate_change : tr_matrix[y][z].rate_change;
+					}
+
 					ast_debug(3, "Discovered %d cost path from %s to %s, via %s\n", tr_matrix[x][z].cost,
 						  ast_getformatname(1LL << x), ast_getformatname(1LL << z), ast_getformatname(1LL << y));
 					changed++;
@@ -478,30 +564,134 @@ static void rebuild_matrix(int samples)
 	}
 }
 
+const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str)
+{
+	struct ast_trans_pvt *pn = p;
+
+	if (!p || !p->t) {
+		return "";
+	}
+
+	ast_str_set(str, 0, "%s", ast_getformatname(1LL << p->t->srcfmt));
+
+	while ( (p = pn) ) {
+		pn = p->next;
+		ast_str_append(str, 0, "->%s", ast_getformatname(1LL << p->t->dstfmt));
+	}
+
+	return ast_str_buffer(*str);
+}
+
+static char *complete_trans_path_choice(const char *line, const char *word, int pos, int state)
+{
+	int which = 0;
+	int wordlen = strlen(word);
+	int i;
+	char *ret = NULL;
+	size_t len = 0;
+	const struct ast_format_list *format_list = ast_get_format_list(&len);
+
+	for (i = 0; i < len; i++) {
+		if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) {
+			continue;
+		}
+		if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) {
+			ret = ast_strdup(format_list[i].name);
+			break;
+		}
+	}
+	return ret;
+}
+
 static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-#define SHOW_TRANS 16
+#define SHOW_TRANS 64
+	static const char * const option1[] = { "recalc", "paths", NULL };
 	int x, y, z;
 	int curlen = 0, longest = 0, magnitude[SHOW_TRANS] = { 0, };
 
 	switch (cmd) {
 	case CLI_INIT:
-		e->command = "core show translation [recalc]";
+		e->command = "core show translation";
 		e->usage =
-			"Usage: core show translation [recalc [<recalc seconds>]]\n"
-			"       Displays known codec translators and the cost associated\n"
-			"       with each conversion.  If the argument 'recalc' is supplied along\n"
-			"       with optional number of seconds to test a new test will be performed\n"
-			"       as the chart is being displayed.\n";
+			"Usage: 'core show translation' can be used in two ways.\n"
+			"       1. 'core show translation [recalc [<recalc seconds>]]\n"
+			"          Displays known codec translators and the cost associated\n"
+			"          with each conversion.  If the argument 'recalc' is supplied along\n"
+			"          with optional number of seconds to test a new test will be performed\n"
+			"          as the chart is being displayed.\n"
+			"       2. 'core show translation paths [codec]'\n"
+			"           This will display all the translation paths associated with a codec\n";
 		return NULL;
 	case CLI_GENERATE:
+		if (a->pos == 3) {
+			return ast_cli_complete(a->word, option1, a->n);
+		}
+		if (a->pos == 4 && !strcasecmp(a->argv[3], option1[1])) {
+			return complete_trans_path_choice(a->line, a->word, a->pos, a->n);
+		}
 		return NULL;
 	}
 
 	if (a->argc > 5)
 		return CLI_SHOWUSAGE;
 
-	if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) {
+	if (a->argv[3] && !strcasecmp(a->argv[3], option1[1]) && a->argc == 5) {
+		format_t input_src = 0;
+		format_t src = 0;
+		size_t len = 0;
+		int dst;
+		int i;
+		const struct ast_format_list *format_list = ast_get_format_list(&len);
+		struct ast_str *str = ast_str_alloca(256);
+		struct ast_translator *step;
+
+		for (i = 0; i < len; i++) {
+			if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) {
+				continue;
+			}
+			if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) {
+				input_src = format_list[i].bits;
+			}
+		}
+
+		if (!input_src) {
+			ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]);
+			return CLI_FAILURE;
+		}
+
+		AST_RWLIST_RDLOCK(&translators);
+		ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(input_src));
+		for (i = 0; i < len; i++) {
+			if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK) || (format_list[i].bits == input_src)) {
+				continue;
+			}
+			dst = powerof(format_list[i].bits);
+			src = powerof(input_src);
+			ast_str_reset(str);
+			if (tr_matrix[src][dst].step) {
+				ast_str_append(&str, 0, "%s", ast_getformatname(1LL << tr_matrix[src][dst].step->srcfmt));
+				while (src != dst) {
+					step = tr_matrix[src][dst].step;
+					if (!step) {
+						ast_str_reset(str);
+						break;
+					}
+					ast_str_append(&str, 0, "->%s", ast_getformatname(1LL << step->dstfmt));
+					src = step->dstfmt;
+				}
+			}
+
+			if (ast_strlen_zero(ast_str_buffer(str))) {
+				ast_str_set(&str, 0, "No Translation Path");
+			}
+
+			ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str));
+		}
+		AST_RWLIST_UNLOCK(&translators);
+
+		return CLI_SUCCESS;
+	} else if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) {
 		z = a->argv[4] ? atoi(a->argv[4]) : 1;
 
 		if (z <= 0) {
@@ -526,22 +716,33 @@ static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd,
 	ast_cli(a->fd, "          Source Format (Rows) Destination Format (Columns)\n\n");
 	/* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
 	for (x = 0; x < SHOW_TRANS; x++) {
+		/* translation only applies to audio right now. */
+		if (!(AST_FORMAT_AUDIO_MASK & (1LL << (x))))
+			continue;
 		curlen = strlen(ast_getformatname(1LL << (x)));
 		if (curlen > longest)
 			longest = curlen;
 		for (y = 0; y < SHOW_TRANS; y++) {
+			if (!(AST_FORMAT_AUDIO_MASK & (1LL << (y))))
+				continue;
 			if (tr_matrix[x][y].cost > pow(10, magnitude[x])) {
 				magnitude[y] = floor(log10(tr_matrix[x][y].cost));
 			}
 		}
 	}
 	for (x = -1; x < SHOW_TRANS; x++) {
-		struct ast_str *out = ast_str_alloca(125);
+		struct ast_str *out = ast_str_alloca(256);
+		/* translation only applies to audio right now. */
+		if (x >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (x))))
+			continue;
 		/*Go ahead and move to next iteration if dealing with an unknown codec*/
 		if(x >= 0 && !strcmp(ast_getformatname(1LL << (x)), "unknown"))
 			continue;
 		ast_str_set(&out, -1, " ");
 		for (y = -1; y < SHOW_TRANS; y++) {
+			/* translation only applies to audio right now. */
+			if (y >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (y))))
+				continue;
 			/*Go ahead and move to next iteration if dealing with an unknown codec*/
 			if (y >= 0 && !strcmp(ast_getformatname(1LL << (y)), "unknown"))
 				continue;
@@ -715,37 +916,65 @@ void ast_translator_deactivate(struct ast_translator *t)
 format_t ast_translator_best_choice(format_t *dst, format_t *srcs)
 {
 	int x,y;
+	int better = 0;
+	int besttime = INT_MAX;
+	int beststeps = INT_MAX;
+	unsigned int best_rate_change = INT_MAX;
 	format_t best = -1;
 	format_t bestdst = 0;
 	format_t cur, cursrc;
-	int besttime = INT_MAX;
-	int beststeps = INT_MAX;
 	format_t common = ((*dst) & (*srcs)) & AST_FORMAT_AUDIO_MASK;	/* are there common formats ? */
 
 	if (common) { /* yes, pick one and return */
 		for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
-			if (cur & common)	/* guaranteed to find one */
-				break;
+			if (!(cur & common)) {
+				continue;
+			}
+
+			/* We are guaranteed to find one common format. */
+			if (best == -1) {
+				best = cur;
+				continue;
+			}
+			/* If there are multiple common formats, pick the one with the highest sample rate */
+			if (ast_format_rate(best) < ast_format_rate(cur)) {
+				best = cur;
+				continue;
+			}
 		}
 		/* We are done, this is a common format to both. */
-		*srcs = *dst = cur;
+		*srcs = *dst = best;
 		return 0;
-	} else {	/* No, we will need to translate */
+	} else {      /* No, we will need to translate */
 		AST_RWLIST_RDLOCK(&translators);
 		for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
-			if (! (cur & *dst))
+			if (! (cur & *dst)) {
 				continue;
+			}
 			for (cursrc = 1, x = 0; x <= MAX_AUDIO_FORMAT; cursrc <<= 1, x++) {
-				if (!(*srcs & cursrc) || !tr_matrix[x][y].step ||
-				    tr_matrix[x][y].cost >  besttime)
-					continue;	/* not existing or no better */
-				if (tr_matrix[x][y].cost < besttime ||
-				    tr_matrix[x][y].multistep < beststeps) {
+				if (!(*srcs & cursrc) || !tr_matrix[x][y].step) {
+					continue;
+				}
+
+				/* This is a better choice if any of the following are true.
+				 * 1. The sample rate conversion is better than the current pick.
+				 * 2. the sample rate conversion is no worse than the current pick and the cost or multistep is better
+				 */
+				better = 0;
+				if (tr_matrix[x][y].rate_change < best_rate_change) {
+					better = 1; /* this match has a better rate conversion */
+				}
+				if ((tr_matrix[x][y].rate_change <= best_rate_change) &&
+					(tr_matrix[x][y].cost < besttime || tr_matrix[x][y].multistep < beststeps)) {
+					better = 1; /* this match has no worse rate conversion and the conversion cost is less */
+				}
+				if (better) {
 					/* better than what we have so far */
 					best = cursrc;
 					bestdst = cur;
 					besttime = tr_matrix[x][y].cost;
 					beststeps = tr_matrix[x][y].multistep;
+					best_rate_change = tr_matrix[x][y].rate_change;
 				}
 			}
 		}