Index: Makefile
===================================================================
--- Makefile	(revision 34061)
+++ Makefile	(working copy)
@@ -710,6 +710,47 @@
 		echo ";astctl = asterisk.ctl" ; \
 		echo ";[options]" ; \
 		echo ";internal_timing = yes" ; \
+		echo ";"; \
+		echo "; The following section allows to choose the translation and the codec"; \
+		echo "; negotiation algorithms"; \
+		echo ";"; \
+		echo "[codec_negotiation]"; \
+		echo ";"; \
+		echo "; The translation_algorithm option allows to choose between two"; \
+		echo "; algorythms:"; \
+		echo ";"; \
+		echo "; 1. Always follow the format of data that the peer sends in."; \
+		echo "; For example suppose the peer announced support for G729 and ULAW and"; \
+		echo "; sends data in G729. Then Asterisk will translate all outgoing frames"; \
+		echo "; to G729 regardless of initial format of the outgoing frames even if"; \
+		echo "; they are in ULAW format. Outgoing G729 frames of course will not be"; \
+		echo "; translated."; \
+		echo ";"; \
+		echo "; The name of this algorithm is:"; \
+		echo ";	strict"; \
+		echo ";"; \
+		echo "; Synonyms are:"; \
+		echo ";	follow_peer"; \
+		echo ";	avoid_asymmetry"; \
+		echo ";"; \
+		echo "; 2. Avoid translations if possible."; \
+		echo "; For example suppose the peer announced support for G729 and ULAW and"; \
+		echo "; sends data in G729. If Asterisk is to send the frame in G729 or ULAW"; \
+		echo "; format then no translation will be performed and so frame is sent"; \
+		echo "; unchanged. If the outgoing frame is in other format (not G729 or ULAW)"; \
+		echo "; then the frame will be translated to G729 format."; \
+		echo ";"; \
+		echo "; The name of the algorithm is:"; \
+		echo ";	loose"; \
+		echo ";"; \
+		echo "; Synonyms are:"; \
+		echo ";	save_cpu"; \
+		echo ";	avoid_translation"; \
+		echo ";	asymmetric"; \
+		echo ";"; \
+		echo "; Default: strict"; \
+		echo ";"; \
+		echo ";translation_algorithm = strict"; \
 		) > $(DESTDIR)$(ASTCONFPATH) ; \
 	else \
 		echo "Skipping asterisk.conf creation"; \
Index: apps/app_chanisavail.c
===================================================================
--- apps/app_chanisavail.c	(revision 34061)
+++ apps/app_chanisavail.c	(working copy)
@@ -122,7 +122,7 @@
 				snprintf(trychan, sizeof(trychan), "%s/%s",cur,number);
 				status = inuse = ast_device_state(trychan);
 			}
-			if ((inuse <= 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status))) {
+			if ((inuse <= 1) && (tempchan = ast_request(tech, &chan->nativeformats, number, &status))) {
 					pbx_builtin_setvar_helper(chan, "AVAILCHAN", tempchan->name);
 					/* Store the originally used channel too */
 					snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
Index: apps/app_dial.c
===================================================================
--- apps/app_dial.c	(revision 34061)
+++ apps/app_dial.c	(working copy)
@@ -482,7 +482,7 @@
 					if (option_verbose > 2)
 						ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, c->name);
 					/* Setup parameters */
-					c = o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
+					c = o->chan = ast_request(tech, &in->nativeformats, stuff, &cause);
 					/* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */
 					if (ast_test_flag(peerflags, OPT_IGNORE_FORWARDING)) {
 						if (option_verbose > 2)
@@ -491,7 +491,7 @@
 						cause = AST_CAUSE_BUSY;
 					} else {
 						/* Setup parameters */
-						c = o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
+						c = o->chan = ast_request(tech, &in->nativeformats, stuff, &cause);
 						if (!c)
 							ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
 						else
@@ -1063,7 +1063,7 @@
 		}
 		ast_copy_string(numsubst, number, sizeof(numsubst));
 		/* Request the peer */
-		tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause);
+		tmp->chan = ast_request(tech, &chan->nativeformats, numsubst, &cause);
 		if (!tmp->chan) {
 			/* If we can't, just go on to the next call */
 			ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n", tech, cause, ast_cause2str(cause));
@@ -1098,7 +1098,7 @@
 					if (option_verbose > 2)
 						ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s/%s' prevented.\n", chan->name, tech, stuff);
 				} else {
-					tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause);
+					tmp->chan = ast_request(tech, &chan->nativeformats, stuff, &cause);
 				}
 				if (!tmp->chan)
 					ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
Index: apps/app_dumpchan.c
===================================================================
--- apps/app_dumpchan.c	(revision 34061)
+++ apps/app_dumpchan.c	(working copy)
@@ -112,7 +112,7 @@
 			 ast_state2str(c->_state),
 			 c->_state,
 			 c->rings,
-			 ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->nativeformats),
+			 ast_codec_pref_dump(formatbuf, sizeof(formatbuf), &c->nativeformats),
 			 ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->writeformat),
 			 ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->readformat),
 			 c->fds[0], c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
Index: apps/app_echo.c
===================================================================
--- apps/app_echo.c	(revision 34061)
+++ apps/app_echo.c	(working copy)
@@ -62,7 +62,7 @@
 
 	LOCAL_USER_ADD(u);
 
-	format = ast_best_codec(chan->nativeformats);
+	format = ast_best_codec(ast_codec_pref_bits(&chan->nativeformats));
 	ast_set_write_format(chan, format);
 	ast_set_read_format(chan, format);
 
Index: apps/app_followme.c
===================================================================
--- apps/app_followme.c	(revision 34061)
+++ apps/app_followme.c	(working copy)
@@ -823,7 +823,7 @@
 				return;
 			}
 					
-			outbound = ast_request("Local", ast_best_codec(caller->nativeformats), dialarg, &dg);
+			outbound = ast_request("Local", &caller->nativeformats, dialarg, &dg);
 			if (outbound) {
 				ast_set_callerid(outbound, caller->cid.cid_num, caller->cid.cid_name, caller->cid.cid_num);
 				ast_channel_inherit_variables(tpargs->chan, outbound);
Index: apps/app_meetme.c
===================================================================
--- apps/app_meetme.c	(revision 34061)
+++ apps/app_meetme.c	(working copy)
@@ -521,6 +521,9 @@
 	if (!cnf && (make || dynamic)) {
 		/* Make a new one */
 		if ((cnf = ast_calloc(1, sizeof(*cnf)))) {
+			struct ast_codec_pref formats;
+			ast_codec_pref_set2(&formats, AST_FORMAT_ULAW);
+
 			ast_mutex_init(&cnf->playlock);
 			ast_mutex_init(&cnf->listenlock);
 			ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
@@ -528,7 +531,7 @@
 			ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
 			cnf->refcount = 0;
 			cnf->markedusers = 0;
-			cnf->chan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
+			cnf->chan = ast_request("zap", &formats, "pseudo", NULL);
 			if (cnf->chan) {
 				ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
 				ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
@@ -558,7 +561,7 @@
 				cnf = NULL;
 				goto cnfout;
 			}
-			cnf->lchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
+			cnf->lchan = ast_request("zap", &formats, "pseudo", NULL);
 			if (cnf->lchan) {
 				ast_set_read_format(cnf->lchan, AST_FORMAT_SLINEAR);
 				ast_set_write_format(cnf->lchan, AST_FORMAT_SLINEAR);
Index: apps/app_page.c
===================================================================
--- apps/app_page.c	(revision 34061)
+++ apps/app_page.c	(working copy)
@@ -89,7 +89,10 @@
 static void *page_thread(void *data)
 {
 	struct calloutdata *cd = data;
-	ast_pbx_outgoing_app(cd->tech, AST_FORMAT_SLINEAR, cd->resource, 30000,
+	struct ast_codec_pref slin;
+	ast_codec_pref_init(&slin);
+	ast_codec_pref_append(&slin, AST_FORMAT_SLINEAR);
+	ast_pbx_outgoing_app(cd->tech, &slin, cd->resource, 30000,
 		"MeetMe", cd->meetmeopts, NULL, 0, cd->cidnum, cd->cidname, cd->variables, NULL, NULL);
 	free(cd);
 	return NULL;
Index: apps/app_parkandannounce.c
===================================================================
--- apps/app_parkandannounce.c	(revision 34061)
+++ apps/app_parkandannounce.c	(working copy)
@@ -95,6 +95,11 @@
 
 	struct localuser *u;
 
+	struct ast_codec_pref formats;
+
+	ast_codec_pref_init(&formats);
+	ast_codec_pref_append(&formats, AST_FORMAT_SLINEAR);
+
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce:template|timeout|dial|[return_context])\n");
 		return -1;
@@ -194,7 +199,7 @@
 	memset(&oh, 0, sizeof(oh));
 	oh.parent_channel = chan;
 	oh.vars = ast_variable_new("_PARKEDAT", buf);
-	dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh);
+	dchan = __ast_request_and_dial(dialtech, &formats, dialstr,30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh);
 
 	if(dchan) {
 		if(dchan->_state == AST_STATE_UP) {
Index: apps/app_queue.c
===================================================================
--- apps/app_queue.c	(revision 34061)
+++ apps/app_queue.c	(working copy)
@@ -1560,7 +1560,7 @@
 		location = "";
 
 	/* Request the peer */
-	tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
+	tmp->chan = ast_request(tech, &qe->chan->nativeformats, location, &status);
 	if (!tmp->chan) {			/* If we can't, just go on to the next call */
 #if 0
 		ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
@@ -1877,7 +1877,7 @@
 					if (option_verbose > 2)
 						ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
 					/* Setup parameters */
-					o->chan = ast_request(tech, in->nativeformats, stuff, &status);
+					o->chan = ast_request(tech, &in->nativeformats, stuff, &status);
 					if (status != o->oldstatus) 
 						update_dial_status(qe->parent, o->member, status);						
 					if (!o->chan) {
Index: asterisk.c
===================================================================
--- asterisk.c	(revision 34061)
+++ asterisk.c	(working copy)
@@ -166,6 +166,7 @@
 
 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
 char debug_filename[AST_FILENAME_MAX] = "";
+enum ast_trans_algorithm option_translation_algorithm = AST_TRANS_ALG_STRICT;
 
 static int ast_socket = -1;		/*!< UNIX Socket for allowing remote control */
 static int ast_consock = -1;		/*!< UNIX Socket for controlling another asterisk */
@@ -2303,6 +2304,30 @@
 			ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
 		} else if (!strcasecmp(v->name, "languageprefix")) {
 			ast_language_is_prefix = ast_true(v->value);
+		}
+	}
+	option_translation_algorithm = AST_TRANS_ALG_STRICT;
+	for (v = ast_variable_browse(cfg, "codec_negotiation"); v; v = v->next)
+	{
+		if (!strcasecmp(v->name, "translation_algorithm")) {
+			if (!strcasecmp(v->value, "loose") ||
+			    !strcasecmp(v->value, "save_cpu") ||
+			    !strcasecmp(v->value, "avoid_translation") ||
+			    !strcasecmp(v->value, "asymmetric"))
+			{
+				option_translation_algorithm = AST_TRANS_ALG_LOOSE;
+			}
+/*
+			else if (!strcasecmp(v->value, "strict") ||
+				 !strcasecmp(v->value, "follow_peer") ||
+				 !strcasecmp(v->value, "avoid_asymmetry"))
+			{
+				option_translation_algorithm = AST_TRANS_ALG_STRICT;
+			}
+*/
+			else {
+				option_translation_algorithm = AST_TRANS_ALG_STRICT;
+			}
 		}
 	}
 	ast_config_destroy(cfg);
Index: channel.c
===================================================================
--- channel.c	(revision 34061)
+++ channel.c	(working copy)
@@ -979,10 +979,7 @@
 		ast_moh_cleanup(chan);
 
 	/* Free translators */
-	if (chan->readtrans)
-		ast_translator_free_path(chan->readtrans);
-	if (chan->writetrans)
-		ast_translator_free_path(chan->writetrans);
+	ast_translator_free_translations(chan);
 	if (chan->pbx)
 		ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
 	free_cid(&chan->cid);
@@ -1424,14 +1421,9 @@
 
 static void free_translation(struct ast_channel *clone)
 {
-	if (clone->writetrans)
-		ast_translator_free_path(clone->writetrans);
-	if (clone->readtrans)
-		ast_translator_free_path(clone->readtrans);
-	clone->writetrans = NULL;
-	clone->readtrans = NULL;
-	clone->rawwriteformat = clone->nativeformats;
-	clone->rawreadformat = clone->nativeformats;
+	ast_translator_free_translations(clone);
+	clone->rawwriteformat = clone->nativeformats.audio_bits;
+	clone->rawreadformat = clone->nativeformats.audio_bits;
 }
 
 /*! \brief Hangup a channel */
@@ -2022,11 +2014,12 @@
 			if (dropaudio) {
 				ast_frfree(f);
 				f = &ast_null_frame;
-			} else if (!(f->subclass & chan->nativeformats)) {
+			} else if (!(f->subclass & chan->nativeformats.audio_bits)) {
+				char buf[512];
 				/* This frame can't be from the current native formats -- drop it on the
 				   floor */
 				ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %s since our native format has changed to %s\n",
-					chan->name, ast_getformatname(f->subclass), ast_getformatname(chan->nativeformats));
+					chan->name, ast_getformatname(f->subclass), ast_codec_pref_dump(buf, sizeof(buf), &chan->nativeformats));
 				ast_frfree(f);
 				f = &ast_null_frame;
 			} else {
@@ -2058,7 +2051,8 @@
 					}
 				}
 
-				if (chan->readtrans && (f = ast_translate(chan->readtrans, f, 1)) == NULL)
+				f = ast_translate_read(chan, f, 1);
+				if (!f)
 					f = &ast_null_frame;
 
 				/* Run generator sitting on the line if timing device not available
@@ -2396,7 +2390,7 @@
 		if (fr->subclass == chan->rawwriteformat)
 			f = fr;
 		else
-			f = (chan->writetrans) ? ast_translate(chan->writetrans, fr, 0) : fr;
+			f = ast_translate_write(chan, fr, 0);
 		if (f == NULL) {
 			res = 0;
 		} else {
@@ -2448,7 +2442,7 @@
 }
 
 static int set_format(struct ast_channel *chan, int fmt, int *rawformat, int *format,
-		      struct ast_trans_pvt **trans, const int direction)
+		      const int direction)
 {
 	int native;
 	int res;
@@ -2456,7 +2450,7 @@
 	/* Make sure we only consider audio */
 	fmt &= AST_FORMAT_AUDIO_MASK;
 	
-	native = chan->nativeformats;
+	native = ast_codec_pref_index_audio(&chan->nativeformats, 0);
 	/* Find a translation path from the native format to one of the desired formats */
 	if (!direction)
 		/* reading */
@@ -2466,26 +2460,19 @@
 		res = ast_translator_best_choice(&native, &fmt);
 
 	if (res < 0) {
+		char buf[512];
 		ast_log(LOG_WARNING, "Unable to find a codec translation path from %s to %s\n",
-			ast_getformatname(native), ast_getformatname(fmt));
+			ast_getformatname_multiple(buf, sizeof(buf), native), ast_getformatname(fmt));
+/*
 		return -1;
+*/
 	}
 	
 	/* Now we have a good choice for both. */
 	ast_channel_lock(chan);
-	*rawformat = native;
+	*rawformat = chan->lastreadformat = native;
 	/* User perspective is fmt */
 	*format = fmt;
-	/* Free any read translation we have right now */
-	if (*trans)
-		ast_translator_free_path(*trans);
-	/* Build a translation path from the raw format to the desired format */
-	if (!direction)
-		/* reading */
-		*trans = ast_translator_build_path(*format, *rawformat);
-	else
-		/* writing */
-		*trans = ast_translator_build_path(*rawformat, *format);
 	ast_channel_unlock(chan);
 	if (option_debug)
 		ast_log(LOG_DEBUG, "Set channel %s to %s format %s\n", chan->name,
@@ -2495,17 +2482,15 @@
 
 int ast_set_read_format(struct ast_channel *chan, int fmt)
 {
-	return set_format(chan, fmt, &chan->rawreadformat, &chan->readformat,
-			  &chan->readtrans, 0);
+	return set_format(chan, fmt, &chan->rawreadformat, &chan->readformat, 0);
 }
 
 int ast_set_write_format(struct ast_channel *chan, int fmt)
 {
-	return set_format(chan, fmt, &chan->rawwriteformat, &chan->writeformat,
-			  &chan->writetrans, 1);
+	return set_format(chan, fmt, &chan->rawwriteformat, &chan->writeformat, 1);
 }
 
-struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
+struct ast_channel *__ast_request_and_dial(const char *type, const struct ast_codec_pref *formats, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
 {
 	int dummy_outstate;
 	int cause = 0;
@@ -2517,7 +2502,7 @@
 	else
 		outstate = &dummy_outstate;	/* make outstate always a valid pointer */
 
-	chan = ast_request(type, format, data, &cause);
+	chan = ast_request(type, formats, data, &cause);
 	if (!chan) {
 		ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
 		/* compute error and return */
@@ -2620,21 +2605,20 @@
 	return chan;
 }
 
-struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cidnum, const char *cidname)
+struct ast_channel *ast_request_and_dial(const char *type, const struct ast_codec_pref *formats, void *data, int timeout, int *outstate, const char *cidnum, const char *cidname)
 {
-	return __ast_request_and_dial(type, format, data, timeout, outstate, cidnum, cidname, NULL);
+	return __ast_request_and_dial(type, formats, data, timeout, outstate, cidnum, cidname, NULL);
 }
 
-struct ast_channel *ast_request(const char *type, int format, void *data, int *cause)
+struct ast_channel *ast_request(const char *type, const struct ast_codec_pref *requested_formats, void *data, int *cause)
 {
 	struct chanlist *chan;
 	struct ast_channel *c;
-	int capabilities;
-	int fmt;
-	int res;
 	int foo;
-	int videoformat = format & AST_FORMAT_VIDEO_MASK;
+	struct ast_codec_pref formats;
 
+	memcpy(&formats, requested_formats, sizeof(formats));
+	ast_codec_pref_append_missing2(&formats, ast_compatible_audio_formats(formats.audio_bits));
 	if (!cause)
 		cause = &foo;
 	*cause = AST_CAUSE_NOTDEFINED;
@@ -2645,22 +2629,25 @@
 	}
 
 	AST_LIST_TRAVERSE(&backends, chan, list) {
+		struct ast_codec_pref tmp_formats;
 		if (strcasecmp(type, chan->tech->type))
 			continue;
 
-		capabilities = chan->tech->capabilities;
-		fmt = format & AST_FORMAT_AUDIO_MASK;
-		res = ast_translator_best_choice(&fmt, &capabilities);
-		if (res < 0) {
-			ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %d) to %d\n", type, chan->tech->capabilities, format);
+		if (!(chan->tech->capabilities & ast_codec_pref_bits(&formats)))
+	       	{
+			char buf[512];
+			ast_log(LOG_WARNING, "Channel %s does not support requested formats %s\n", type, ast_codec_pref_dump(buf, sizeof(buf), &formats));
 			AST_LIST_UNLOCK(&channels);
 			return NULL;
 		}
 		AST_LIST_UNLOCK(&channels);
-		if (!chan->tech->requester)
+		if (!chan->tech->requester) {
+			ast_log(LOG_WARNING, "Cannot allocate channel %s because it hasn't registered the requester function\n", type);
 			return NULL;
-		
-		if (!(c = chan->tech->requester(type, capabilities | videoformat, data, cause)))
+		}
+		memcpy(&tmp_formats, &formats, sizeof(formats));
+		ast_codec_pref_remove2(&tmp_formats, ~chan->tech->capabilities);
+		if (!(c = chan->tech->requester(type, &tmp_formats, data, cause)))
 			return NULL;
 
 		if (c->_state == AST_STATE_DOWN) {
@@ -2796,15 +2783,31 @@
 {
 	int src;
 	int dst;
+	int res = -1;
+	int i, j, done;
 
 	/* Set up translation from the chan to the peer */
-	src = chan->nativeformats;
-	dst = peer->nativeformats;
-	if (ast_translator_best_choice(&dst, &src) < 0) {
-		ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", chan->name, src, peer->name, dst);
+	done = 0;
+	for (i = 0; i < 32 && !done; ++i) {
+		dst = ast_codec_pref_index_audio(&peer->nativeformats, i);
+		if (!dst) break;
+		for (j = 0; j < 32 && !done; ++j) {
+			src = ast_codec_pref_index_audio(&chan->nativeformats, j);
+			if (!src) break;
+			res = ast_translator_best_choice(&dst, &src);
+			if (res >= 0)
+				done = 1;
+		}
+	}
+	if (res < 0) {
+		char buf[512], buf2[512];
+		ast_log(LOG_WARNING, "No path to translate from %s %s to %s %s\n",
+			chan->name,
+			ast_codec_pref_dump(buf, sizeof(buf), &chan->nativeformats),
+			peer->name,
+			ast_codec_pref_dump(buf2, sizeof(buf2), &peer->nativeformats));
 		return -1;
 	}
-
 	/* if the best path is not 'pass through', then
 	   transcoding is needed; if desired, force transcode path
 	   to use SLINEAR between channels, but only if there is
@@ -2822,10 +2825,25 @@
 	}
 
 	/* Set up translation from the peer to the chan */
-	src = peer->nativeformats;
-	dst = chan->nativeformats;
-	if (ast_translator_best_choice(&dst, &src) < 0) {
-		ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", peer->name, src, chan->name, dst);
+	done = 0;
+	for (i = 0; i < 32 && !done; ++i) {
+		dst = ast_codec_pref_index_audio(&peer->nativeformats, i);
+		if (!dst) break;
+		for (j = 0; j < 32 && !done; ++j) {
+			src = ast_codec_pref_index_audio(&chan->nativeformats, j);
+			if (!src) break;
+			res = ast_translator_best_choice(&src, &dst);
+			if (res >= 0)
+				done = 1;
+		}
+	}
+	if (res < 0) {
+		char buf[512], buf2[512];
+		ast_log(LOG_WARNING, "No path to translate from %s %s to %s %s\n",
+			peer->name,
+			ast_codec_pref_dump(buf2, sizeof(buf2), &peer->nativeformats),
+			chan->name,
+			ast_codec_pref_dump(buf, sizeof(buf), &chan->nativeformats));
 		return -1;
 	}
 
@@ -3157,7 +3175,7 @@
 	original->fds[AST_TIMING_FD] = original->timingfd;
 	
 	/* Our native formats are different now */
-	original->nativeformats = clone->nativeformats;
+	memcpy(&original->nativeformats, &clone->nativeformats, sizeof(struct ast_codec_pref));
 	
 	/* Context, extension, priority, app data, jump table,  remain the same */
 	/* pvt switches.  pbx stays the same, as does next */
@@ -3345,8 +3363,8 @@
 	cs[1] = c1;
 	pvt0 = c0->tech_pvt;
 	pvt1 = c1->tech_pvt;
-	o0nativeformats = c0->nativeformats;
-	o1nativeformats = c1->nativeformats;
+	o0nativeformats = ast_codec_pref_bits(&c0->nativeformats);
+	o1nativeformats = ast_codec_pref_bits(&c1->nativeformats);
 	watch_c0_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_0;
 	watch_c1_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_1;
 
@@ -3357,8 +3375,9 @@
 		struct ast_channel *who, *other;
 
 		if ((c0->tech_pvt != pvt0) || (c1->tech_pvt != pvt1) ||
-		    (o0nativeformats != c0->nativeformats) ||
-		    (o1nativeformats != c1->nativeformats)) {
+		    (o0nativeformats != ast_codec_pref_bits(&c0->nativeformats)) ||
+		    (o1nativeformats != ast_codec_pref_bits(&c1->nativeformats)))
+		{
 			/* Check for Masquerade, codec changes, etc */
 			res = AST_BRIDGE_RETRY;
 			break;
@@ -3521,8 +3540,8 @@
 		      "CallerID2: %s\r\n",
 		      c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num);
 
-	o0nativeformats = c0->nativeformats;
-	o1nativeformats = c1->nativeformats;
+	o1nativeformats = ast_codec_pref_bits(&c1->nativeformats);
+	o0nativeformats = ast_codec_pref_bits(&c0->nativeformats);
 
 	if (config->timelimit) {
 		nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
@@ -3645,7 +3664,8 @@
 		}
 	
 		if (((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat) ||
-		    (c0->nativeformats != o0nativeformats) || (c1->nativeformats != o1nativeformats)) &&
+		    (ast_codec_pref_bits(&c0->nativeformats) != o0nativeformats) ||
+		    (ast_codec_pref_bits(&c1->nativeformats) != o1nativeformats)) &&
 		    !(c0->generator || c1->generator)) {
 			if (ast_channel_make_compatible(c0, c1)) {
 				ast_log(LOG_WARNING, "Can't make %s and %s compatible\n", c0->name, c1->name);
@@ -3660,8 +3680,8 @@
 					      c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num);
 				return AST_BRIDGE_FAILED;
 			}
-			o0nativeformats = c0->nativeformats;
-			o1nativeformats = c1->nativeformats;
+			o0nativeformats = ast_codec_pref_bits(&c0->nativeformats);
+			o1nativeformats = ast_codec_pref_bits(&c1->nativeformats);
 		}
 		res = ast_generic_bridge(c0, c1, config, fo, rc, nexteventts);
 		if (res != AST_BRIDGE_RETRY)
Index: channels/chan_agent.c
===================================================================
--- channels/chan_agent.c	(revision 34061)
+++ channels/chan_agent.c	(working copy)
@@ -207,10 +207,10 @@
 
 #define CHECK_FORMATS(ast, p) do { \
 	if (p->chan) {\
-		if (ast->nativeformats != p->chan->nativeformats) { \
-			ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
+		if (!ast_codec_pref_eq_noorder(&ast->nativeformats, &p->chan->nativeformats)) { \
+			ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast_codec_pref_bits(&ast->nativeformats), ast_codec_pref_bits(&p->chan->nativeformats)); \
 			/* Native formats changed, reset things */ \
-			ast->nativeformats = p->chan->nativeformats; \
+			memcpy(&ast->nativeformats, &p->chan->nativeformats, sizeof(ast->nativeformats)); \
 			ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
 			ast_set_read_format(ast, ast->readformat); \
 			ast_set_write_format(ast, ast->writeformat); \
@@ -237,7 +237,7 @@
 	} \
 } while(0)
 
-static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
+static struct ast_channel *agent_request(const char *type, const struct ast_codec_pref *format, void *data, int *cause);
 static int agent_devicestate(void *data);
 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand);
 static int agent_digit(struct ast_channel *ast, char digit);
@@ -657,20 +657,20 @@
 		ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
 	}
 	if (!res) {
-		res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
+		res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats.audio_bits));
 		ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
 		if (res)
-			ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
+			ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats.audio_bits)));
 	} else {
 		/* Agent hung-up */
 		p->chan = NULL;
 	}
 
 	if (!res) {
-		ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
+		ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats.audio_bits));
 		ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
 		if (res)
-			ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
+			ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats.audio_bits)));
 	}
 	if( !res )
 	{
@@ -912,7 +912,7 @@
 			ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
 			ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
 		} else {
-			tmp->nativeformats = AST_FORMAT_SLINEAR;
+			ast_codec_pref_append(&tmp->nativeformats, AST_FORMAT_SLINEAR);
 			tmp->writeformat = AST_FORMAT_SLINEAR;
 			tmp->rawwriteformat = AST_FORMAT_SLINEAR;
 			tmp->readformat = AST_FORMAT_SLINEAR;
@@ -1236,7 +1236,7 @@
 }
 
 /*! \brief Part of the Asterisk PBX interface ---*/
-static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
+static struct ast_channel *agent_request(const char *type, const struct ast_codec_pref *formats, void *data, int *cause)
 {
 	struct agent_pvt *p;
 	struct ast_channel *chan = NULL;
@@ -1297,7 +1297,7 @@
 						chan = agent_new(p, AST_STATE_DOWN);
 					} else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
 						/* Adjustable agent */
-						p->chan = ast_request("Local", format, p->loginchan, cause);
+						p->chan = ast_request("Local", formats, p->loginchan, cause);
 						if (p->chan)
 							chan = agent_new(p, AST_STATE_DOWN);
 					}
@@ -1946,14 +1946,14 @@
 					AST_LIST_LOCK(&agents);
 					ast_mutex_lock(&p->lock);
 					if (!res) {
-						res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
+						res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats.audio_bits));
 						if (res)
-							ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
+							ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats.audio_bits));
 					}
 					if (!res) {
-						res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
+						res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats.audio_bits));
 						if (res)
-							ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
+							ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats.audio_bits));
 					}
 					/* Check once more just in case */
 					if (p->chan)
Index: channels/chan_alsa.c
===================================================================
--- channels/chan_alsa.c	(revision 34061)
+++ channels/chan_alsa.c	(working copy)
@@ -800,7 +800,7 @@
 		tmp->tech = &alsa_tech;
 		ast_string_field_build(tmp, name, "ALSA/%s", indevname);
 		tmp->fds[0] = readdev;
-		tmp->nativeformats = AST_FORMAT_SLINEAR;
+		ast_codec_pref_set2(&tmp->nativeformats, AST_FORMAT_SLINEAR);
 		tmp->readformat = AST_FORMAT_SLINEAR;
 		tmp->writeformat = AST_FORMAT_SLINEAR;
 		tmp->tech_pvt = p;
Index: channels/chan_features.c
===================================================================
--- channels/chan_features.c	(revision 34061)
+++ channels/chan_features.c	(working copy)
@@ -94,7 +94,7 @@
 #define SUB_CALLWAIT	1			/* Call-Waiting call on hold */
 #define SUB_THREEWAY	2			/* Three-way call */
 
-static struct ast_channel *features_request(const char *type, int format, void *data, int *cause);
+static struct ast_channel *features_request(const char *type, const struct ast_codec_pref *format, void *data, int *cause);
 static int features_digit(struct ast_channel *ast, char digit);
 static int features_call(struct ast_channel *ast, char *dest, int timeout);
 static int features_hangup(struct ast_channel *ast);
@@ -188,8 +188,8 @@
 			p->subs[index].owner->timingfd = p->subchan->timingfd;
 			p->subs[index].owner->alertpipe[0] = p->subchan->alertpipe[0];
 			p->subs[index].owner->alertpipe[1] = p->subchan->alertpipe[1];
-			if (p->subs[index].owner->nativeformats != p->subchan->readformat) {
-				p->subs[index].owner->nativeformats = p->subchan->readformat;
+			if (!(ast_codec_pref_bits(&p->subs[index].owner->nativeformats) & p->subchan->readformat)) {
+				ast_codec_pref_append(&p->subs[index].owner->nativeformats, p->subchan->readformat);
 				if (p->subs[index].owner->readformat)
 					ast_set_read_format(p->subs[index].owner, p->subs[index].owner->readformat);
 				if (p->subs[index].owner->writeformat)
@@ -378,7 +378,7 @@
 	return 0;
 }
 
-static struct feature_pvt *features_alloc(char *data, int format)
+static struct feature_pvt *features_alloc(char *data, const struct ast_codec_pref *formats)
 {
 	struct feature_pvt *tmp;
 	char *dest=NULL;
@@ -407,7 +407,7 @@
 	}
 	AST_LIST_UNLOCK(&features);
 	if (!tmp) {
-		chan = ast_request(tech, format, dest, &status);
+		chan = ast_request(tech, formats, dest, &status);
 		if (!chan) {
 			ast_log(LOG_NOTICE, "Unable to allocate subchannel '%s/%s'\n", tech, dest);
 			return NULL;
@@ -463,7 +463,7 @@
 	tmp->rawwriteformat = p->subchan->rawwriteformat;
 	tmp->readformat = p->subchan->readformat;
 	tmp->rawreadformat = p->subchan->rawreadformat;
-	tmp->nativeformats = p->subchan->readformat;
+	ast_codec_pref_append(&tmp->nativeformats, p->subchan->readformat);
 	tmp->tech_pvt = p;
 	p->subs[index].owner = tmp;
 	if (!p->owner)
@@ -476,12 +476,12 @@
 }
 
 
-static struct ast_channel *features_request(const char *type, int format, void *data, int *cause)
+static struct ast_channel *features_request(const char *type, const struct ast_codec_pref *formats, void *data, int *cause)
 {
 	struct feature_pvt *p;
 	struct ast_channel *chan = NULL;
 
-	p = features_alloc(data, format);
+	p = features_alloc(data, formats);
 	if (p && !p->subs[SUB_REAL].owner)
 		chan = features_new(p, AST_STATE_DOWN, SUB_REAL);
 	if (chan)
Index: channels/chan_h323.c
===================================================================
--- channels/chan_h323.c	(revision 34061)
+++ channels/chan_h323.c	(working copy)
@@ -219,7 +219,7 @@
 static int restart_monitor(void);
 static int h323_do_reload(void);
 
-static struct ast_channel *oh323_request(const char *type, int format, void *data, int *cause);
+static struct ast_channel *oh323_request(const char *type, const struct ast_codec_pref *format, void *data, int *cause);
 static int oh323_digit(struct ast_channel *c, char digit);
 static int oh323_call(struct ast_channel *c, char *dest, int timeout);
 static int oh323_hangup(struct ast_channel *c);
@@ -252,10 +252,11 @@
 /* Channel and private structures should be already locked */
 static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt)
 {
-	if (c->nativeformats != pvt->nativeformats) {
+	if (ast_codec_pref_bits(&c->nativeformats) != pvt->nativeformats) {
 		if (h323debug)
 			ast_log(LOG_DEBUG, "Preparing %s for new native format\n", c->name);
-		c->nativeformats = pvt->nativeformats;
+		ast_codec_pref_init(&c->nativeformats);
+		ast_codec_pref_append_missing2(&c->nativeformats, pvt->nativeformats);
 		ast_set_read_format(c, c->readformat);
 		ast_set_write_format(c, c->writeformat);
 	}
@@ -577,15 +578,15 @@
 	if (pvt->owner) {
 		/* We already hold the channel lock */
 		if (f->frametype == AST_FRAME_VOICE) {
-			if (f->subclass != pvt->owner->nativeformats) {
+			if (!(f->subclass & pvt->owner->nativeformats.audio_bits)) {
 				/* Try to avoid deadlock */
 				if (ast_mutex_trylock(&pvt->owner->lock)) {
 					ast_log(LOG_NOTICE, "Format changed but channel is locked. Ignoring frame...\n");
 					return &ast_null_frame;
 				}
 				ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
-				pvt->owner->nativeformats = f->subclass;
-				pvt->nativeformats = f->subclass;
+				ast_codec_pref_append(&pvt->owner->nativeformats, f->subclass);
+				pvt->nativeformats |= f->subclass;
 				ast_set_read_format(pvt->owner, pvt->owner->readformat);
 				ast_set_write_format(pvt->owner, pvt->owner->writeformat);
 				ast_mutex_unlock(&pvt->owner->lock);
@@ -630,9 +631,9 @@
 			return 0;
 		}
 	} else {
-		if (!(frame->subclass & c->nativeformats)) {
+		if (!(frame->subclass & c->nativeformats.audio_bits)) {
 			ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
-				frame->subclass, c->nativeformats, c->readformat, c->writeformat);
+				frame->subclass, ast_codec_pref_bits(&c->nativeformats), c->readformat, c->writeformat);
 			return 0;
 		}
 	}
@@ -753,12 +754,12 @@
 	if (ch) {
 		ch->tech = &oh323_tech;
 		ast_string_field_build(ch, name, "H323/%s", host);
-		ch->nativeformats = pvt->options.capability;
-		if (!ch->nativeformats) {
-			ch->nativeformats = global_options.capability;
+		ast_codec_pref_append_missing2(&ch->nativeformats, pvt->options.capability);
+		if (!ast_codec_pref_bits(&ch->nativeformats)) {
+			ast_codec_pref_append(&ch->nativeformats, global_options.capability);
 		}
-		pvt->nativeformats = ch->nativeformats;
-		fmt = ast_best_codec(ch->nativeformats);
+		pvt->nativeformats = ast_codec_pref_bits(&ch->nativeformats);
+		fmt = ast_best_codec(ch->nativeformats.audio_bits);
 		ch->fds[0] = ast_rtp_fd(pvt->rtp);
 		if (state == AST_STATE_RING) {
 			ch->rings = 1;
@@ -1029,9 +1030,8 @@
 		return 0;
 	}
 }
-static struct ast_channel *oh323_request(const char *type, int format, void *data, int *cause)
+static struct ast_channel *oh323_request(const char *type, const struct ast_codec_pref *formats, void *data, int *cause)
 {
-	int oldformat;
 	struct oh323_pvt *pvt;
 	struct ast_channel *tmpc = NULL;
 	char *dest = (char *)data;
@@ -1039,18 +1039,12 @@
 	char *h323id = NULL;
 	char tmp[256], tmp1[256];
 	
-	ast_log(LOG_DEBUG, "type=%s, format=%d, data=%s.\n", type, format, (char *)data);
+	ast_log(LOG_DEBUG, "type=%s, format=%d, data=%s.\n", type, ast_codec_pref_dump(tmp, sizeof(tmp), formats), (char *)data);
 	pvt = oh323_alloc(0);
 	if (!pvt) {
 		ast_log(LOG_WARNING, "Unable to build pvt data for '%s'\n", (char *)data);
 		return NULL;
 	}	
-	oldformat = format;
-	format &= ((AST_FORMAT_MAX_AUDIO << 1) - 1);
-	if (!format) {
-		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
-		return NULL;
-	}
 	strncpy(tmp, dest, sizeof(tmp) - 1);	
 	host = strchr(tmp, '@');
 	if (host) {
@@ -1186,14 +1180,6 @@
 }
 
 /**
- * Definition taken from rtp.c for rtpPayloadType because we need it here.
- */
-struct rtpPayloadType {
-	int isAstFormat;        /* whether the following code is an AST_FORMAT */
-	int code;
-};
-
-/**
   * Call-back function passing remote ip/port information from H.323 to asterisk 
   *
   * Returns nothing 
@@ -1220,7 +1206,8 @@
 	rtptype = ast_rtp_lookup_pt(pvt->rtp, pt);
 	pvt->nativeformats = rtptype.code;
 	if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
-		pvt->owner->nativeformats = pvt->nativeformats;
+		ast_codec_pref_init(&pvt->owner->nativeformats);
+		ast_codec_pref_append_missing2(&pvt->owner->nativeformats, pvt->nativeformats);
 		ast_set_read_format(pvt->owner, pvt->owner->readformat);
 		ast_set_write_format(pvt->owner, pvt->owner->writeformat);
 		if (pvt->options.progress_audio)
@@ -2310,7 +2297,7 @@
 	}
 }
 
-static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
+static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, const struct ast_codec_pref *codecs, int nat_active)
 {
 	/* XXX Deal with Video */
 	struct oh323_pvt *pvt;
Index: channels/chan_iax2.c
===================================================================
--- channels/chan_iax2.c	(revision 34061)
+++ channels/chan_iax2.c	(working copy)
@@ -779,7 +779,7 @@
 static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
 static int send_command_locked(unsigned short callno, char, int, unsigned int, const unsigned char *, int, int);
 static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int);
-static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause);
+static struct ast_channel *iax2_request(const char *type, const struct ast_codec_pref *format, void *data, int *cause);
 static struct ast_frame *iax2_read(struct ast_channel *c);
 static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, int temponly);
 static struct iax2_user *build_user(const char *name, struct ast_variable *v, int temponly);
@@ -1983,7 +1983,7 @@
 	char iabuf[INET_ADDRSTRLEN];
 	struct iax2_peer *peer;
 	char codec_buf[512];
-	int x = 0, codec = 0, load_realtime = 0;
+	int load_realtime = 0;
 
 	if (argc < 4)
 		return RESULT_SHOWUSAGE;
@@ -2008,19 +2008,9 @@
 		ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
 		ast_cli(fd, "%s\n", codec_buf);
 
-		ast_cli(fd, "  Codec Order  : (");
-		for(x = 0; x < 32 ; x++) {
-			codec = ast_codec_pref_index(&peer->prefs,x);
-			if(!codec)
-				break;
-			ast_cli(fd, "%s", ast_getformatname(codec));
-			if(x < 31 && ast_codec_pref_index(&peer->prefs,x+1))
-				ast_cli(fd, "|");
-		}
-
-		if (!x)
-			ast_cli(fd, "none");
-		ast_cli(fd, ")\n");
+		ast_cli(fd, "  Codec Order  : ");
+		ast_codec_pref_dump(codec_buf, sizeof(codec_buf), &peer->prefs);
+		ast_cli(fd, "%s\n", codec_buf);
 
 		ast_cli(fd, "  Status       : ");
 		peer_status(peer, status, sizeof(status));	
@@ -2651,7 +2641,7 @@
 			memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
 			sin->sin_port = htons(IAX_DEFAULT_PORTNO);
 			/* use global iax prefs for unknown peer/user */
-			ast_codec_pref_convert(&prefs, cai->prefs, sizeof(cai->prefs), 1);
+			ast_codec_pref_convert_to_buf(&prefs, cai->prefs, sizeof(cai->prefs));
 			return 0;
 		} else {
 			ast_log(LOG_WARNING, "No such host: %s\n", peername);
@@ -2680,7 +2670,7 @@
 	cai->capability = peer->capability;
 	cai->encmethods = peer->encmethods;
 	cai->sockfd = peer->sockfd;
-	ast_codec_pref_convert(&peer->prefs, cai->prefs, sizeof(cai->prefs), 1);
+	ast_codec_pref_convert_to_buf(&peer->prefs, cai->prefs, sizeof(cai->prefs));
 	ast_copy_string(cai->context, peer->context, sizeof(cai->context));
 	ast_copy_string(cai->peercontext, peer->peercontext, sizeof(cai->peercontext));
 	ast_copy_string(cai->username, peer->username, sizeof(cai->username));
@@ -2937,7 +2927,7 @@
 	if (pds.password)
 		ast_copy_string(iaxs[callno]->secret, pds.password, sizeof(iaxs[callno]->secret));
 
-	iax_ie_append_int(&ied, IAX_IE_FORMAT, c->nativeformats);
+	iax_ie_append_int(&ied, IAX_IE_FORMAT, ast_codec_pref_bits(&c->nativeformats));
 	iax_ie_append_int(&ied, IAX_IE_CAPABILITY, iaxs[callno]->capability);
 	iax_ie_append_short(&ied, IAX_IE_ADSICPE, c->adsicpe);
 	iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(cai.timezone));
@@ -3104,13 +3094,13 @@
 			}
 			return AST_BRIDGE_FAILED_NOWARN;
 		}
-		if (c0->nativeformats != c1->nativeformats) {
+		if (!ast_codec_pref_eq_noorder(&c0->nativeformats, &c1->nativeformats)) {
 			if (option_verbose > 2) {
 				char buf0[255];
 				char buf1[255];
-				ast_getformatname_multiple(buf0, sizeof(buf0) -1, c0->nativeformats);
-				ast_getformatname_multiple(buf1, sizeof(buf1) -1, c1->nativeformats);
-				ast_verbose(VERBOSE_PREFIX_3 "Operating with different codecs %d[%s] %d[%s] , can't native bridge...\n", c0->nativeformats, buf0, c1->nativeformats, buf1);
+				ast_codec_pref_dump(buf0, sizeof(buf0), &c0->nativeformats);
+				ast_codec_pref_dump(buf1, sizeof(buf1), &c1->nativeformats);
+				ast_verbose(VERBOSE_PREFIX_3 "Operating with different codecs %d[%s] %d[%s] , can't native bridge...\n", ast_codec_pref_bits(&c0->nativeformats), buf0, ast_codec_pref_bits(&c1->nativeformats), buf1);
 			}
 			/* Remove from native mode */
 			lock_both(callno0, callno1);
@@ -3277,7 +3267,7 @@
 		tmp->tech = &iax2_tech;
 		ast_string_field_build(tmp, name, "IAX2/%s-%d", i->host, i->callno);
 		/* We can support any format by default, until we get restricted */
-		tmp->nativeformats = capability;
+		ast_codec_pref_set2(&tmp->nativeformats, capability);
 		tmp->readformat = ast_best_codec(capability);
 		tmp->writeformat = ast_best_codec(capability);
 		tmp->tech_pvt = CALLNO_TO_PTR(i->callno);
@@ -4701,8 +4691,8 @@
 
 	/* Use provided preferences until told otherwise for actual preferences */
 	if(ies->codec_prefs) {
-		ast_codec_pref_convert(&iaxs[callno]->rprefs, ies->codec_prefs, 32, 0);
-		ast_codec_pref_convert(&iaxs[callno]->prefs, ies->codec_prefs, 32, 0);
+		ast_codec_pref_convert_from_buf(&iaxs[callno]->rprefs, ies->codec_prefs, 32);
+		ast_codec_pref_convert_from_buf(&iaxs[callno]->prefs, ies->codec_prefs, 32);
 	}
 
 	if (!gotcapability) 
@@ -6688,11 +6678,11 @@
 						}
 						if (iaxs[fr->callno]) {
 							if (iaxs[fr->callno]->owner) {
-								orignative = iaxs[fr->callno]->owner->nativeformats;
-								iaxs[fr->callno]->owner->nativeformats = f.subclass;
+								orignative = ast_codec_pref_bits(&iaxs[fr->callno]->owner->nativeformats);
+								ast_codec_pref_set2(&iaxs[fr->callno]->owner->nativeformats, f.subclass);
 								if (iaxs[fr->callno]->owner->readformat)
 									ast_set_read_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->readformat);
-								iaxs[fr->callno]->owner->nativeformats = orignative;
+								ast_codec_pref_set2(&iaxs[fr->callno]->owner->nativeformats, orignative);
 								ast_mutex_unlock(&iaxs[fr->callno]->owner->lock);
 							}
 						} else {
@@ -6837,8 +6827,8 @@
 							using_prefs = "mine";
 							/* If the information elements are in here... use them */
 							if (ies.codec_prefs)
-								ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
-							if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
+								ast_codec_pref_convert_from_buf(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32);
+							if (ast_codec_pref_index_audio(&iaxs[fr->callno]->rprefs, 0)) {
 								/* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/
 								if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
 									pref = iaxs[fr->callno]->rprefs;
@@ -6881,7 +6871,7 @@
 										strcpy(host_pref_buf,"disabled");
 									} else {
 										using_prefs = "mine";
-										if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
+										if (ast_codec_pref_index_audio(&iaxs[fr->callno]->rprefs, 0)) {
 											/* Do the opposite of what we tried above. */
 											if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
 												pref = iaxs[fr->callno]->prefs;								
@@ -7032,7 +7022,7 @@
 					iaxs[fr->callno]->peerformat = ies.format;
 				} else {
 					if (iaxs[fr->callno]->owner)
-						iaxs[fr->callno]->peerformat = iaxs[fr->callno]->owner->nativeformats;
+						iaxs[fr->callno]->peerformat = ast_codec_pref_bits(&iaxs[fr->callno]->owner->nativeformats);
 					else
 						iaxs[fr->callno]->peerformat = iaxs[fr->callno]->capability;
 				}
@@ -7049,9 +7039,11 @@
 					ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
 					if (iaxs[fr->callno]->owner) {
 						/* Switch us to use a compatible format */
-						iaxs[fr->callno]->owner->nativeformats = iaxs[fr->callno]->peerformat;
-						if (option_verbose > 2)
-							ast_verbose(VERBOSE_PREFIX_3 "Format for call is %s\n", ast_getformatname(iaxs[fr->callno]->owner->nativeformats));
+						ast_codec_pref_set2(&iaxs[fr->callno]->owner->nativeformats, iaxs[fr->callno]->peerformat);
+						if (option_verbose > 2) {
+							char buf[512];
+							ast_verbose(VERBOSE_PREFIX_3 "Format for call is %s\n", ast_codec_pref_dump(buf, sizeof(buf), &iaxs[fr->callno]->owner->nativeformats));
+						}
 retryowner2:
 						if (ast_mutex_trylock(&iaxs[fr->callno]->owner->lock)) {
 							ast_mutex_unlock(&iaxsl[fr->callno]);
@@ -7241,8 +7233,8 @@
 					} else {
 						using_prefs = "mine";
 						if (ies.codec_prefs)
-							ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
-						if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
+							ast_codec_pref_convert_from_buf(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32);
+						if (ast_codec_pref_index_audio(&iaxs[fr->callno]->rprefs, 0)) {
 							if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
 								pref = iaxs[fr->callno]->rprefs;
 								using_prefs = "caller";
@@ -7287,7 +7279,7 @@
 									strcpy(host_pref_buf,"disabled");
 								} else {
 									using_prefs = "mine";
-									if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
+									if (ast_codec_pref_index_audio(&iaxs[fr->callno]->rprefs, 0)) {
 										/* Do the opposite of what we tried above. */
 										if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
 											pref = iaxs[fr->callno]->prefs;						
@@ -8001,11 +7993,9 @@
 	}
 }
 
-static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause)
+static struct ast_channel *iax2_request(const char *type, const struct ast_codec_pref *formats, void *data, int *cause)
 {
 	int callno;
-	int res;
-	int fmt, native;
 	struct sockaddr_in sin;
 	struct ast_channel *c;
 	struct parsed_dial_string pds;
@@ -8059,22 +8049,8 @@
 
 	if (c) {
 		/* Choose a format we can live with */
-		if (c->nativeformats & format) 
-			c->nativeformats &= format;
-		else {
-			native = c->nativeformats;
-			fmt = format;
-			res = ast_translator_best_choice(&fmt, &native);
-			if (res < 0) {
-				ast_log(LOG_WARNING, "Unable to create translator path for %s to %s on %s\n",
-					ast_getformatname(c->nativeformats), ast_getformatname(fmt), c->name);
-				ast_hangup(c);
-				return NULL;
-			}
-			c->nativeformats = native;
-		}
-		c->readformat = ast_best_codec(c->nativeformats);
-		c->writeformat = c->readformat;
+		ast_codec_pref_remove2(&c->nativeformats, ~ast_codec_pref_bits(formats));
+		c->readformat = c->writeformat = ast_codec_pref_index_audio(&c->nativeformats, 0);
 	}
 
 	return c;
@@ -9476,7 +9452,7 @@
 			*ptr = '\0';
 		}
 		index = atoi(codecnum);
-		if((codec = ast_codec_pref_index(&peer->prefs, index))) {
+		if((codec = ast_codec_pref_index_audio(&peer->prefs, index))) {
 			ast_copy_string(buf, ast_getformatname(codec), len);
 		}
 	}
Index: channels/chan_local.c
===================================================================
--- channels/chan_local.c	(revision 34061)
+++ channels/chan_local.c	(working copy)
@@ -66,7 +66,7 @@
 
 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
 
-static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
+static struct ast_channel *local_request(const char *type, const struct ast_codec_pref *format, void *data, int *cause);
 static int local_digit(struct ast_channel *ast, char digit);
 static int local_call(struct ast_channel *ast, char *dest, int timeout);
 static int local_hangup(struct ast_channel *ast);
@@ -484,7 +484,7 @@
 }
 
 /*! \brief Create a call structure */
-static struct local_pvt *local_alloc(const char *data, int format)
+static struct local_pvt *local_alloc(const char *data, const struct ast_codec_pref *formats)
 {
 	struct local_pvt *tmp;
 	char *c;
@@ -505,7 +505,7 @@
 	if (c)
 		*c++ = '\0';
 	ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
-	tmp->reqformat = format;
+	tmp->reqformat = ast_codec_pref_bits(formats);
 	if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
 		ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
 		ast_mutex_destroy(&tmp->lock);
@@ -539,8 +539,8 @@
 	} 
 
 	tmp2->tech = tmp->tech = &local_tech;
-	tmp->nativeformats = p->reqformat;
-	tmp2->nativeformats = p->reqformat;
+	ast_codec_pref_append_missing2(&tmp->nativeformats, p->reqformat);
+	ast_codec_pref_append_missing2(&tmp2->nativeformats, p->reqformat);
 	ast_string_field_build(tmp, name, "Local/%s@%s-%04x,1", p->exten, p->context, randnum);
 	ast_string_field_build(tmp2, name, "Local/%s@%s-%04x,2", p->exten, p->context, randnum);
 	ast_setstate(tmp, state);
@@ -570,12 +570,12 @@
 
 
 /*! \brief Part of PBX interface */
-static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
+static struct ast_channel *local_request(const char *type, const struct ast_codec_pref *formats, void *data, int *cause)
 {
 	struct local_pvt *p;
 	struct ast_channel *chan = NULL;
 
-	p = local_alloc(data, format);
+	p = local_alloc(data, formats);
 	if (p)
 		chan = local_new(p, AST_STATE_DOWN);
 	return chan;
Index: channels/chan_mgcp.c
===================================================================
--- channels/chan_mgcp.c	(revision 34061)
+++ channels/chan_mgcp.c	(working copy)
@@ -491,7 +491,7 @@
 static int mgcp_do_reload(void);
 static int mgcp_reload(int fd, int argc, char *argv[]);
 
-static struct ast_channel *mgcp_request(const char *type, int format, void *data, int *cause);
+static struct ast_channel *mgcp_request(const char *type, const struct ast_codec_pref *format, void *data, int *cause);
 static int mgcp_call(struct ast_channel *ast, char *dest, int timeout);
 static int mgcp_hangup(struct ast_channel *ast);
 static int mgcp_answer(struct ast_channel *ast);
@@ -1225,9 +1225,10 @@
 	if (sub->owner) {
 		/* We already hold the channel lock */
 		if (f->frametype == AST_FRAME_VOICE) {
-			if (f->subclass != sub->owner->nativeformats) {
+			if (f->subclass != sub->owner->nativeformats.audio_bits) {
 				ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
-				sub->owner->nativeformats = f->subclass;
+/*				ast_codec_pref_init(&sub->owner->nativeformats);*/
+				ast_codec_pref_append(&sub->owner->nativeformats, f->subclass);
 				ast_set_read_format(sub->owner, sub->owner->readformat);
 				ast_set_write_format(sub->owner, sub->owner->writeformat);
 			}
@@ -1266,9 +1267,9 @@
 			return 0;
 		}
 	} else {
-		if (!(frame->subclass & ast->nativeformats)) {
+		if (!(frame->subclass & ast_codec_pref_bits(&ast->nativeformats))) {
 			ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
-				frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
+				frame->subclass, ast_codec_pref_bits(&ast->nativeformats), ast->readformat, ast->writeformat);
 			return -1;
 		}
 	}
@@ -1448,10 +1449,10 @@
 	tmp = ast_channel_alloc(1);
 	if (tmp) {
 		tmp->tech = &mgcp_tech;
-		tmp->nativeformats = i->capability;
-		if (!tmp->nativeformats)
-			tmp->nativeformats = capability;
-		fmt = ast_best_codec(tmp->nativeformats);
+		ast_codec_pref_set2(&tmp->nativeformats, i->capability);
+		if (!ast_codec_pref_bits(&tmp->nativeformats))
+			ast_codec_pref_set2(&tmp->nativeformats, capability);
+		fmt = ast_best_codec(tmp->nativeformats.audio_bits);
 		ast_string_field_build(tmp, name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
 		if (sub->rtp)
 			tmp->fds[0] = ast_rtp_fd(sub->rtp);
@@ -3552,20 +3553,13 @@
 	return 0;
 }
 
-static struct ast_channel *mgcp_request(const char *type, int format, void *data, int *cause)
+static struct ast_channel *mgcp_request(const char *type, const struct ast_codec_pref *formats, void *data, int *cause)
 {
-	int oldformat;
 	struct mgcp_subchannel *sub;
 	struct ast_channel *tmpc = NULL;
 	char tmp[256];
 	char *dest = data;
 
-	oldformat = format;
-	format &= capability;
-	if (!format) {
-		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
-		return NULL;
-	}
 	ast_copy_string(tmp, dest, sizeof(tmp));
 	if (ast_strlen_zero(tmp)) {
 		ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
@@ -3996,13 +3990,13 @@
 	return NULL;
 }
 
-static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
+static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, const struct ast_codec_pref *codecs, int nat_active)
 {
 	/* XXX Is there such thing as video support with MGCP? XXX */
 	struct mgcp_subchannel *sub;
 	sub = chan->tech_pvt;
 	if (sub && !sub->alreadygone) {
-		transmit_modify_with_sdp(sub, rtp, codecs);
+		transmit_modify_with_sdp(sub, rtp, ast_codec_pref_bits(codecs));
 		return 0;
 	}
 	return -1;
Index: channels/chan_oss.c
===================================================================
--- channels/chan_oss.c	(revision 34061)
+++ channels/chan_oss.c	(working copy)
@@ -396,7 +396,7 @@
 
 static int setformat(struct chan_oss_pvt *o, int mode);
 
-static struct ast_channel *oss_request(const char *type, int format, void *data
+static struct ast_channel *oss_request(const char *type, const struct ast_codec_pref *formats, void *data
 , int *cause);
 static int oss_digit(struct ast_channel *c, char digit);
 static int oss_text(struct ast_channel *c, const char *text);
@@ -980,7 +980,7 @@
 	if (o->sounddev < 0)
 		setformat(o, O_RDWR);
 	c->fds[0] = o->sounddev; /* -1 if device closed, override later */
-	c->nativeformats = AST_FORMAT_SLINEAR;
+	ast_codec_pref_append(&c->nativeformats, AST_FORMAT_SLINEAR);
 	c->readformat = AST_FORMAT_SLINEAR;
 	c->writeformat = AST_FORMAT_SLINEAR;
 	c->tech_pvt = o;
@@ -1020,7 +1020,7 @@
 }
 
 static struct ast_channel *oss_request(const char *type,
-	int format, void *data, int *cause)
+	const struct ast_codec_pref *formats, void *data, int *cause)
 {
 	struct ast_channel *c;
 	struct chan_oss_pvt *o = find_desc(data);
@@ -1030,10 +1030,6 @@
 	if (o == NULL) {
 		ast_log(LOG_NOTICE, "Device %s not found\n", (char *)data);
 		/* XXX we could default to 'dsp' perhaps ? */
-		return NULL;
-	}
-	if ((format & AST_FORMAT_SLINEAR) == 0) {
-		ast_log(LOG_NOTICE, "Format 0x%x unsupported\n", format);
 		return NULL;
 	}
 	if (o->owner) {
Index: channels/chan_phone.c
===================================================================
--- channels/chan_phone.c	(revision 34061)
+++ channels/chan_phone.c	(working copy)
@@ -159,7 +159,7 @@
 static char cid_num[AST_MAX_EXTENSION];
 static char cid_name[AST_MAX_EXTENSION];
 
-static struct ast_channel *phone_request(const char *type, int format, void *data, int *cause);
+static struct ast_channel *phone_request(const char *type, const struct ast_codec_pref *formats, void *data, int *cause);
 static int phone_digit(struct ast_channel *ast, char digit);
 static int phone_call(struct ast_channel *ast, char *dest, int timeout);
 static int phone_hangup(struct ast_channel *ast);
@@ -829,20 +829,20 @@
 		/* XXX Switching formats silently causes kernel panics XXX */
 		if (i->mode == MODE_FXS &&
 		    ioctl(i->fd, PHONE_QUERY_CODEC, &codec) == 0) {
-			if (codec.type == LINEAR16)
-				tmp->nativeformats =
+			if (codec.type == LINEAR16) {
+				ast_codec_pref_append(&tmp->nativeformats, AST_FORMAT_SLINEAR);
 				tmp->rawreadformat =
 				tmp->rawwriteformat =
 				AST_FORMAT_SLINEAR;
-			else {
-				tmp->nativeformats =
+			} else {
+				ast_codec_pref_append_missing2(&tmp->nativeformats, prefformat & ~AST_FORMAT_SLINEAR);
 				tmp->rawreadformat =
 				tmp->rawwriteformat =
 				prefformat & ~AST_FORMAT_SLINEAR;
 			}
 		}
 		else {
-			tmp->nativeformats = prefformat;
+			ast_codec_pref_append_missing2(&tmp->nativeformats, prefformat);
 			tmp->rawreadformat = prefformat;
 			tmp->rawwriteformat = prefformat;
 		}
@@ -1188,9 +1188,8 @@
 	return tmp;
 }
 
-static struct ast_channel *phone_request(const char *type, int format, void *data, int *cause)
+static struct ast_channel *phone_request(const char *type, const struct ast_codec_pref *formats, void *data, int *cause)
 {
-	int oldformat;
 	struct phone_pvt *p;
 	struct ast_channel *tmp = NULL;
 	char *name = data;
@@ -1203,7 +1202,7 @@
 	p = iflist;
 	while(p) {
 		if (p->mode == MODE_FXS ||
-		    format & (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW)) {
+		    formats->audio_bits & (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW)) {
 		    size_t length = strlen(p->dev + 5);
     		if (strncmp(name, p->dev + 5, length) == 0 &&
     		    !isalnum(name[length])) {
@@ -1218,14 +1217,6 @@
 	}
 	ast_mutex_unlock(&iflock);
 	restart_monitor();
-	if (tmp == NULL) {
-		oldformat = format;
-		format &= (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW);
-		if (!format) {
-			ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
-			return NULL;
-		}
-	}
 	return tmp;
 }
 
Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 34061)
+++ channels/chan_sip.c	(working copy)
@@ -871,7 +871,9 @@
 		AST_STRING_FIELD(rpid);		/*!< Our RPID header */
 		AST_STRING_FIELD(rpid_from);	/*!< Our RPID From header */
 	);
-	struct ast_codec_pref prefs;		/*!< codec prefs */
+	struct ast_codec_pref userprefs;	/*!< user codec prefs */
+	int usercapability;                     /*!< user capabilities */
+	struct ast_codec_pref formats;          /*!< current channel formats */
 	unsigned int ocseq;			/*!< Current outgoing seqno */
 	unsigned int icseq;			/*!< Current incoming seqno */
 	ast_group_t callgroup;			/*!< Call group */
@@ -880,12 +882,7 @@
 	struct ast_flags flags[2];		/*!< SIP_ flags */
 	int timer_t1;				/*!< SIP timer T1, ms rtt */
 	unsigned int sipoptions;		/*!< Supported SIP sipoptions on the other end */
-	int capability;				/*!< Special capability (codec) */
-	int jointcapability;			/*!< Supported capability at both ends (codecs ) */
-	int peercapability;			/*!< Supported peer capability */
-	int prefcodec;				/*!< Preferred codec (outbound only) */
 	int noncodeccapability;			/*!< DTMF RFC2833 telephony-event */
-	int redircodecs;			/*!< Redirect codecs */
 	int maxcallbitrate;			/*!< Maximum Call Bitrate for Video Calls */	
 	struct t38properties t38;		/*!< T38 settings */
 	struct sockaddr_in udptlredirip;	/*!< Where our T.38 UDPTL should be going if not to us */
@@ -900,6 +897,7 @@
 	struct sockaddr_in sa;			/*!< Our peer */
 	struct sockaddr_in redirip;		/*!< Where our RTP should be going if not to us */
 	struct sockaddr_in vredirip;		/*!< Where our Video RTP should be going if not to us */
+	struct ast_codec_pref redircodecs;	/*!< Redirect codecs */
 	struct sockaddr_in recv;		/*!< Received as */
 	struct in_addr ourip;			/*!< Our IP */
 	struct ast_channel *owner;		/*!< Who owns us */
@@ -1126,7 +1124,7 @@
 	in coming releases */
 
 /*--- PBX interface functions */
-static struct ast_channel *sip_request_call(const char *type, int format, void *data, int *cause);
+static struct ast_channel *sip_request_call(const char *type, const struct ast_codec_pref *format, void *data, int *cause);
 static int sip_devicestate(void *data);
 static int sip_sendtext(struct ast_channel *ast, const char *text);
 static int sip_call(struct ast_channel *ast, char *dest, int timeout);
@@ -1376,6 +1374,7 @@
 /*--- Parsing SIP requests and responses */
 static void append_date(struct sip_request *req);	/* Append date to SIP packet */
 static int determine_firstline_parts(struct sip_request *req);
+static void sip_fixup_codecs(struct ast_channel *chan, const struct ast_codec_pref *peer_codecs);
 static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
 static const char *gettag(const struct sip_request *req, const char *header, char *tagbuf, int tagbufsize);
 static int find_sip_method(const char *msg);
@@ -1458,10 +1457,9 @@
 static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno);
 
 /*----- RTP interface functions */
-static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active);
+static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, const struct ast_codec_pref *codecs, int nat_active);
 static struct ast_rtp *sip_get_rtp_peer(struct ast_channel *chan);
 static struct ast_rtp *sip_get_vrtp_peer(struct ast_channel *chan);
-static int sip_get_codec(struct ast_channel *chan);
 static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect);
 
 /*------ T38 Support --------- */
@@ -1475,7 +1473,7 @@
 static const struct ast_channel_tech sip_tech = {
 	.type = "SIP",
 	.description = "Session Initiation Protocol (SIP)",
-	.capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
+	.capabilities = ((AST_FORMAT_MAX_VIDEO << 1) - 1),
 	.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
 	.requester = sip_request_call,
 	.devicestate = sip_devicestate,
@@ -1491,6 +1489,7 @@
 	.send_digit = sip_senddigit,
 	.bridge = ast_rtp_bridge,
 	.send_text = sip_sendtext,
+	.fixup_codecs = sip_fixup_codecs,
 };
 
 /**--- some list management macros. **/
@@ -1508,7 +1507,6 @@
 	get_rtp_info: sip_get_rtp_peer,
 	get_vrtp_info: sip_get_vrtp_peer,
 	set_rtp_peer: sip_set_rtp_peer,
-	get_codec: sip_get_codec,
 };
 
 /*! \brief Interface structure with callbacks used to connect to UDPTL module*/
@@ -2447,12 +2445,11 @@
 
 	ast_copy_flags(&r->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&r->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
-	r->capability = peer->capability;
 	if (!ast_test_flag(&r->flags[1], SIP_PAGE2_VIDEOSUPPORT) && r->vrtp) {
 		ast_rtp_destroy(r->vrtp);
 		r->vrtp = NULL;
 	}
-	r->prefs = peer->prefs;
+	r->userprefs = peer->prefs;
 	if (ast_test_flag(&r->flags[1], SIP_PAGE2_T38SUPPORT)) {
 		r->t38.capability = global_t38_capability;
 		if (r->udptl) {
@@ -2681,7 +2678,6 @@
 	res = update_call_counter(p, INC_CALL_RINGING);
 	if ( res != -1 ) {
 		p->callingpres = ast->cid.cid_pres;
-		p->jointcapability = p->capability;
 		p->t38.jointcapability = p->t38.capability;
 		if (option_debug)
 			ast_log(LOG_DEBUG,"Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability);
@@ -3256,12 +3252,19 @@
 
 	fmt = ast_getformatbyname(codec);
 	if (fmt) {
-		ast_log(LOG_NOTICE, "Changing codec to '%s' for this call because of ${SIP_CODEC) variable\n", codec);
-		if (p->jointcapability & fmt) {
-			p->jointcapability &= fmt;
-			p->capability &= fmt;
+		if (fmt & p->usercapability)
+		{
+			ast_log(LOG_NOTICE, "Changing codec to '%s' for this call because of ${SIP_CODEC) variable\n", codec);
+			if (ast_codec_pref_bits(&p->formats) & fmt) {
+				ast_codec_pref_remove(&p->formats, ~fmt);
+				if (p->owner) {
+					memcpy(&p->owner->nativeformats, &p->formats, sizeof(p->formats));
+				}
+
+			} else
+				ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because it is not shared by both ends.\n");
 		} else
-			ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because it is not shared by both ends.\n");
+			ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because codec %s is disallowed by user preferences.\n", codec);
 	} else
 		ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because of unrecognized/not configured codec (check allow/disallow in sip.conf): %s\n", codec);
 	return;	
@@ -3302,9 +3305,9 @@
 
 	switch (frame->frametype) {
 	case AST_FRAME_VOICE:
-		if (!(frame->subclass & ast->nativeformats)) {
+		if (!(frame->subclass & ast->nativeformats.audio_bits)) {
 			ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
-				frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
+				frame->subclass, ast->nativeformats.audio_bits, ast->readformat, ast->writeformat);
 			return 0;
 		}
 		if (p) {
@@ -3314,6 +3317,9 @@
 				if ((ast->_state != AST_STATE_UP) &&
 				    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
 				    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+					int compatible_codecs = ast_compatible_audio_formats(frame->subclass) | ast->nativeformats.video_bits;
+					ast_codec_pref_remove2(&ast->nativeformats, ~compatible_codecs);
+					ast_codec_pref_remove2(&p->formats, ~compatible_codecs);
 					transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
 					ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);	
 				}
@@ -3536,7 +3542,29 @@
 	return res;
 }
 
-
+/*--- sip_fixup_codecs: try to fixup codec list
+*/
+static void sip_fixup_codecs(struct ast_channel *chan, const struct ast_codec_pref *peer_codecs)
+{
+	struct sip_pvt *p = chan->tech_pvt;
+	int codecs_to_preserve;
+	ast_mutex_lock(&p->lock);
+	if (!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+		/* This is incoming call so its codec list is to be reordered */
+		codecs_to_preserve = ast_codec_pref_bits(&chan->nativeformats);
+		memcpy(&chan->nativeformats, peer_codecs, sizeof(chan->nativeformats));
+	}
+	else {
+		codecs_to_preserve = ast_codec_pref_bits(peer_codecs);
+	}
+	ast_codec_pref_remove2(&chan->nativeformats, ~codecs_to_preserve);
+	memcpy(&p->formats, &chan->nativeformats, sizeof(chan->nativeformats));
+	ast_codec_pref_remove2(&p->formats, ~p->usercapability);
+	if (AST_STATE_UP == chan->_state) {
+		transmit_reinvite_with_sdp(p);
+	}
+	ast_mutex_unlock(&p->lock);
+}
 
 /*! \brief Initiate a call in the SIP channel
 	called from sip_request_call (calls from the pbx ) for outbound channels
@@ -3548,7 +3576,6 @@
 	struct ast_channel *tmp;
 	struct ast_variable *v = NULL;
 	int fmt;
-	int what;
 	int needvideo = 0;
 	
 	ast_mutex_unlock(&i->lock);
@@ -3563,38 +3590,13 @@
 
 	/* Select our native format based on codec preference until we receive
 	   something from another device to the contrary. */
-	if (i->jointcapability)	 	/* The joint capabilities of us and peer */
-		what = i->jointcapability;
-	else if (i->capability)		/* Our configured capability for this peer */
-		what = i->capability;
-	else
-		what = global_capability;	/* Global codec support */
+	memcpy(&tmp->nativeformats, &i->formats, sizeof(i->formats));
 
-	/* Set the native formats for audio  and merge in video */
-	tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
-	if (option_debug > 2) {
-		char buf[BUFSIZ];
-		ast_log(LOG_DEBUG, "*** Our native formats are %s \n", ast_getformatname_multiple(buf, BUFSIZ, tmp->nativeformats));
-		ast_log(LOG_DEBUG, "*** Joint capabilities are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->jointcapability));
-		ast_log(LOG_DEBUG, "*** Our capabilities are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->capability));
-		ast_log(LOG_DEBUG, "*** AST_CODEC_CHOOSE formats are %s \n", ast_getformatname_multiple(buf, BUFSIZ, ast_codec_choose(&i->prefs, what, 1)));
-		if (i->prefcodec)
-			ast_log(LOG_DEBUG, "*** Our preferred formats from the incoming channel are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->prefcodec));
-	}
+	ast_codec_pref_remove2(&tmp->nativeformats, ~i->usercapability);
+	fmt = ast_codec_pref_index_audio(&tmp->nativeformats, 0);
 
-	/* XXX Why are we choosing a codec from the native formats?? */
-	fmt = ast_best_codec(tmp->nativeformats);
-
-	/* If we have a prefcodec setting, we have an inbound channel that set a 
-	   preferred format for this call. Otherwise, we check the jointcapability
-	   We also check for vrtp. If it's not there, we are not allowed do any video anyway.
-	 */
-	if (i->vrtp) {
-		if (i->prefcodec)
-			needvideo = i->prefcodec & AST_FORMAT_VIDEO_MASK;	/* Outbound call */
- 		else
-			needvideo = i->jointcapability & AST_FORMAT_VIDEO_MASK;	/* Inbound call */
-	}
+	if (i->vrtp)
+		needvideo = ast_codec_pref_bits(&i->formats) & AST_FORMAT_VIDEO_MASK;
 
 	if (option_debug > 2) {
 		if (needvideo) 
@@ -3858,10 +3860,10 @@
 	if (p->owner) {
 		/* We already hold the channel lock */
 		if (f->frametype == AST_FRAME_VOICE) {
-			if (f->subclass != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
+			if (!(f->subclass & p->owner->nativeformats.audio_bits)) {
 				if (option_debug)
 					ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
-				p->owner->nativeformats = (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass;
+				ast_codec_pref_append(&p->owner->nativeformats, f->subclass);
 				ast_set_read_format(p->owner, p->owner->readformat);
 				ast_set_write_format(p->owner, p->owner->writeformat);
 			}
@@ -3980,7 +3982,8 @@
 	p->autokillid = -1;
 	p->subscribed = NONE;
 	p->stateid = -1;
-	p->prefs = default_prefs;		/* Set default codecs for this call */
+	p->userprefs = default_prefs;		/* Set default codecs for this call */
+	p->usercapability = global_capability;
 
 	if (intended_method != SIP_OPTIONS)	/* Peerpoke has it's own system */
 		p->timer_t1 = 500;	/* Default SIP retransmission timer T1 (RFC 3261) */
@@ -4056,7 +4059,6 @@
 		ast_string_field_set(p, callid, callid);
 	/* Assign default music on hold class */
 	ast_string_field_set(p, musicclass, default_musicclass);
-	p->capability = global_capability;
 	p->allowtransfer = global_allowtransfer;
 	if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
 	    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
@@ -4451,9 +4453,11 @@
 	int sendonly = 0;
 	int numberofports;
 	struct ast_channel *bridgepeer = NULL;
+	int codec_index = 0;
+	int codec_pt_order[256];
+	int x;
+
 	struct ast_rtp *newaudiortp, *newvideortp;	/* Buffers for codec handling */
-	int newjointcapability;				/* Negotiated capability */
-	int newpeercapability;
 	int newnoncodeccapability;
 	int numberofmediastreams = 0;
 	int debug = sip_debug_test_pvt(p);
@@ -4527,6 +4531,8 @@
 				if (debug)
 					ast_verbose("Found RTP audio format %d\n", codec);
 				ast_rtp_set_m_type(newaudiortp, codec);
+				codec_pt_order[codec_index++] = codec;
+				codecs = ast_skip_blanks(codecs + len);
 			}
 		} else if ((sscanf(m, "video %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2) ||
 		    (sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1)) {
@@ -4542,6 +4548,8 @@
 				if (debug)
 					ast_verbose("Found RTP video format %d\n", codec);
 				ast_rtp_set_m_type(newvideortp, codec);
+				codec_pt_order[codec_index++] = codec;
+				codecs = ast_skip_blanks(codecs + len);
 			}
 		} else if (p->udptl && (sscanf(m, "image %d udptl t38 %n", &x, &len) == 1)) {
 			if (debug)
@@ -4688,6 +4696,17 @@
 		if (p->vrtp)
 			ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype);
 	}
+        ast_codec_pref_init(&p->formats);
+        for (x = 0; x < codec_index; ++x) {
+                struct rtpPayloadType pt;
+                pt = ast_rtp_lookup_pt(p->rtp, codec_pt_order[x]);
+                if (!pt.isAstFormat && !pt.code && p->vrtp)
+                        pt = ast_rtp_lookup_pt(p->vrtp, codec_pt_order[x]);
+                if (pt.isAstFormat) {
+                        ast_codec_pref_append(&p->formats, pt.code);
+                }
+        }
+        ast_codec_pref_remove2(&p->formats, ~p->usercapability);
 	
 	if (udptlportno != -1) {
 		int found = 0, x;
@@ -4810,8 +4829,6 @@
 	ast_rtp_get_current_formats(newaudiortp, &peercapability, &peernoncodeccapability);
 	ast_rtp_get_current_formats(newvideortp, &vpeercapability, &vpeernoncodeccapability);
 
-	newjointcapability = p->capability & (peercapability | vpeercapability);
-	newpeercapability = (peercapability | vpeercapability);
 	newnoncodeccapability = noncodeccapability & peernoncodeccapability;
 		
 		
@@ -4820,17 +4837,17 @@
 		char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ], s4[BUFSIZ];
 
 		ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s, combined - %s\n",
-			ast_getformatname_multiple(s1, BUFSIZ, p->capability),
-			ast_getformatname_multiple(s2, BUFSIZ, newpeercapability),
+			ast_getformatname_multiple(s1, BUFSIZ, p->usercapability),
+			ast_getformatname_multiple(s2, BUFSIZ, peercapability),
 			ast_getformatname_multiple(s3, BUFSIZ, vpeercapability),
-			ast_getformatname_multiple(s4, BUFSIZ, newjointcapability));
+			ast_codec_pref_dump(s4, BUFSIZ, &p->formats));
 
 		ast_verbose("Non-codec capabilities (dtmf): us - %s, peer - %s, combined - %s\n",
 			ast_rtp_lookup_mime_multiple(s1, BUFSIZ, noncodeccapability, 0),
 			ast_rtp_lookup_mime_multiple(s2, BUFSIZ, peernoncodeccapability, 0),
 			ast_rtp_lookup_mime_multiple(s3, BUFSIZ, newnoncodeccapability, 0));
 	}
-	if (!newjointcapability) {
+	if (!ast_codec_pref_bits(&p->formats)) {
 		ast_log(LOG_NOTICE, "No compatible codecs, not accepting this offer!\n");
 		/* Do NOT Change current setting */
 		return -1;
@@ -4838,8 +4855,6 @@
 
 	/* We are now ready to change the sip session and p->rtp and p->vrtp with the offered codecs, since
 		they are acceptable */
-	p->jointcapability = newjointcapability;	/* Our joint codec profile for this call */
-	p->peercapability = newpeercapability;		/* The other sides capability in latest offer */
 	p->noncodeccapability = newnoncodeccapability;	/* DTMF capabilities */
 
 	ast_rtp_pt_copy(p->rtp, newaudiortp);
@@ -4873,24 +4888,13 @@
 	/* Ok, we're going with this offer */
 	if (option_debug > 1) {
 		char buf[BUFSIZ];
-		ast_log(LOG_DEBUG, "We're settling with these formats: %s\n", ast_getformatname_multiple(buf, BUFSIZ, p->jointcapability));
+		ast_log(LOG_DEBUG, "We're settling with these formats: %s\n", ast_codec_pref_dump(buf, BUFSIZ, &p->formats));
 	}
 
 	if (!p->owner) 	/* There's no open channel owning us so we can return here. For a re-invite or so, we proceed */
 		return 0;
 
-
-	if (!(p->owner->nativeformats & p->jointcapability & AST_FORMAT_AUDIO_MASK)) {
-		if (debug) {
-			char s1[BUFSIZ], s2[BUFSIZ];
-			ast_log(LOG_DEBUG, "Oooh, we need to change our audio formats since our peer supports only %s and not %s\n", 
-				ast_getformatname_multiple(s1, BUFSIZ, p->jointcapability),
-				ast_getformatname_multiple(s2, BUFSIZ, p->owner->nativeformats));
-		}
-		p->owner->nativeformats = ast_codec_choose(&p->prefs, p->jointcapability, 1) | (p->capability & vpeercapability);
-		ast_set_read_format(p->owner, p->owner->readformat);
-		ast_set_write_format(p->owner, p->owner->writeformat);
-	}
+	memcpy(&p->owner->nativeformats, &p->formats, sizeof(p->formats));
 
 	if ((bridgepeer = ast_bridged_channel(p->owner))) {
 		/* We have a bridge */
@@ -5528,8 +5532,10 @@
 
 	if (debug)
 		ast_verbose("Adding codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec));
-	if ((rtp_code = ast_rtp_lookup_code(p->rtp, 1, codec)) == -1)
-		return;
+	if ((rtp_code = ast_rtp_lookup_code(p->rtp, 1, codec)) == -1) {
+		if (!p->vrtp || (rtp_code = ast_rtp_lookup_code(p->vrtp, 1, codec)) == -1)
+			return;
+	}
 
 	ast_build_string(m_buf, m_size, " %d", rtp_code);
 	ast_build_string(a_buf, a_size, "a=rtpmap:%d %s/%d\r\n", rtp_code,
@@ -5731,9 +5737,10 @@
 
 	char iabuf[INET_ADDRSTRLEN];
 	int x;
-	int capability;
+	const struct ast_codec_pref *capability;
 	int needvideo = FALSE;
 	int debug = sip_debug_test_pvt(p);
+	int pref_codec;
 
 	m_video[0] = '\0';	/* Reset the video media string if it's not needed */
 
@@ -5741,6 +5748,7 @@
 		ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
 		return -1;
 	}
+	capability = &p->formats;
 
 	/* Set RTP Session ID and version */
 	if (!p->sessionid) {
@@ -5757,21 +5765,22 @@
 	/* Is this a re-invite to move the media out, then use the original offer from caller  */
 	if (p->redirip.sin_addr.s_addr) {
 		dest.sin_port = p->redirip.sin_port;
-		dest.sin_addr = p->redirip.sin_addr;
-		if (p->redircodecs)
-			capability = p->redircodecs;
+		if (ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_ROUTE)
+			dest.sin_addr = p->ourip;
+		else
+			dest.sin_addr = p->redirip.sin_addr;
+                if (ast_codec_pref_bits(&p->redircodecs)) {
+                        /* We are to get all compatible with redircodecs codecs */
+			capability = &p->redircodecs;
+                }
 	} else {
 		dest.sin_addr = p->ourip;
 		dest.sin_port = sin.sin_port;
 	}
 
-	/* Ok, let's start working with codec selection here */
-	capability = p->jointcapability;
-
 	if (option_debug > 1) {
 		char codecbuf[BUFSIZ];
-		ast_log(LOG_DEBUG, "** Our capability: %s Video flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability), ast_test_flag(&p->flags[0], SIP_NOVIDEO) ? "True" : "False");
-		ast_log(LOG_DEBUG, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcodec));
+		ast_log(LOG_DEBUG, "** Our capability: %s Video flag: %s\n", ast_codec_pref_dump(codecbuf, sizeof(codecbuf), capability), ast_test_flag(&p->flags[0], SIP_NOVIDEO) ? "True" : "False");
 	}
 	
 	if ((ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_RTP))) {
@@ -5780,7 +5789,7 @@
 	}
 
 	/* Check if we need video in this call */
-	if((capability & AST_FORMAT_VIDEO_MASK) && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
+	if (capability->video_bits && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
 		if (p->vrtp) {
 			needvideo = TRUE;
 			if (option_debug > 1)
@@ -5811,8 +5820,8 @@
 			ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ntohs(vsin.sin_port));	
 
 		/* For video, we can't negotiate video offers. Let's compare the incoming call with what we got. */
-		if (p->prefcodec) {
-			int videocapability = (capability & p->prefcodec) & AST_FORMAT_VIDEO_MASK; /* Outbound call */
+		if (p->formats.video_bits) {
+			int videocapability = p->formats.video_bits; /* Outbound call */
 		
 			/*! \todo XXX We need to select one codec, not many, since there's no transcoding */
 
@@ -5823,14 +5832,11 @@
 					ast_log(LOG_DEBUG, "** No compatible video codecs... Disabling video.\n");
 			} 
 
-			/* Replace video capabilities with the new videocapability */
-			capability = (capability & AST_FORMAT_AUDIO_MASK) | videocapability;
-
 			if (option_debug > 4) {
 				char codecbuf[BUFSIZ];
 				if (videocapability)
 					ast_log(LOG_DEBUG, "** Our video codec selection is: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), videocapability));
-				ast_log(LOG_DEBUG, "** Capability now set to : %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability));
+				ast_log(LOG_DEBUG, "** Capability now set to : %s \n", ast_codec_pref_dump(codecbuf, sizeof(codecbuf), capability));
 			}
 		}
 	}
@@ -5860,53 +5866,79 @@
 	/* Prefer the audio codec we were requested to use, first, no matter what 
 		Note that p->prefcodec can include video codecs, so mask them out
 	 */
-	if (capability & p->prefcodec) {
-		add_codec_to_sdp(p, p->prefcodec & AST_FORMAT_AUDIO_MASK, 8000,
-				 &m_audio_next, &m_audio_left,
-				 &a_audio_next, &a_audio_left,
-				 debug);
-		alreadysent |= p->prefcodec & AST_FORMAT_AUDIO_MASK;
+	pref_codec = ast_codec_pref_index_audio(capability, 0);
+	if (pref_codec) {
+		add_codec_to_sdp(p, pref_codec, 8000,
+				&m_audio_next, &m_audio_left,
+				&a_audio_next, &a_audio_left,
+				debug);
+		alreadysent |= pref_codec;
+	}
+	pref_codec = ast_codec_pref_index_video(capability, 0);
+	if (pref_codec) {
+		add_codec_to_sdp(p, pref_codec, 90000,
+				&m_video_next, &m_video_left,
+				&a_video_next, &a_video_left,
+				debug);
+		alreadysent |= pref_codec;
 	}
 
 
 	/* Start by sending our preferred audio codecs */
 	for (x = 0; x < 32; x++) {
-		int pref_codec;
-
-		if (!(pref_codec = ast_codec_pref_index(&p->prefs, x)))
+		if (!(pref_codec = ast_codec_pref_index_audio(&p->userprefs, x)))
 			break; 
 
-		if (!(capability & pref_codec))
+		if (!(capability->audio_bits & pref_codec) ||
+		    (alreadysent & pref_codec))
+		{
 			continue;
+		}
+		add_codec_to_sdp(p, pref_codec, 8000,
+				&m_audio_next, &m_audio_left,
+				&a_audio_next, &a_audio_left,
+				debug);
+		alreadysent |= pref_codec;
+	}
+	for (x = 0; x < 32; x++) {
+		if (!(pref_codec = ast_codec_pref_index_video(&p->userprefs, x)))
+			break;
 
+		if (!(capability->video_bits & pref_codec) ||
+		    (alreadysent & pref_codec))
+		{
+			continue;
+		}
+		add_codec_to_sdp(p, pref_codec, 90000,
+				&m_video_next, &m_video_left,
+				&a_video_next, &a_video_left,
+				debug);
+		alreadysent |= pref_codec;
+	}
+	/* Now send any other common codecs, and non-codec formats: */
+	for (x = 0 ; x < 32 ; x++) {
+		if(!(pref_codec = ast_codec_pref_index_audio(capability, x)))
+			break;
 		if (alreadysent & pref_codec)
 			continue;
 
 		add_codec_to_sdp(p, pref_codec, 8000,
-				 &m_audio_next, &m_audio_left,
-				 &a_audio_next, &a_audio_left,
-				 debug);
+				&m_audio_next, &m_audio_left,
+				&a_audio_next, &a_audio_left,
+				debug);
 		alreadysent |= pref_codec;
 	}
-
-	/* Now send any other common audio and video codecs, and non-codec formats: */
-	for (x = 1; x <= (needvideo ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO); x <<= 1) {
-		if (!(capability & x))	/* Codec not requested */
-			continue;
-
-		if (alreadysent & x)	/* Already added to SDP */
+	for (x = 0; x < 32; x++) {
+		if (!(pref_codec = ast_codec_pref_index_video(&p->userprefs, x)))
+			break;
+		if (alreadysent & pref_codec)
 			continue;
 
-		if (x <= AST_FORMAT_MAX_AUDIO)
-			add_codec_to_sdp(p, x, 8000,
-					 &m_audio_next, &m_audio_left,
-					 &a_audio_next, &a_audio_left,
-					 debug);
-		else 
-			add_codec_to_sdp(p, x, 90000,
-					 &m_video_next, &m_video_left,
-					 &a_video_next, &a_video_left,
-					 debug);
+		add_codec_to_sdp(p, pref_codec, 90000,
+				&m_video_next, &m_video_left,
+				&a_video_next, &a_video_left,
+				debug);
+		alreadysent |= pref_codec;
 	}
 
 	/* Now add DTMF RFC2833 telephony-event as a codec */
@@ -5960,7 +5992,7 @@
 
 	if (option_debug > 2) {
 		char buf[BUFSIZ];
-		ast_log(LOG_DEBUG, "Done building SDP. Settling with this capability: %s\n", ast_getformatname_multiple(buf, BUFSIZ, capability));
+		ast_log(LOG_DEBUG, "Done building SDP. Settling with this capability: %s\n", ast_codec_pref_dump(buf, BUFSIZ, capability));
 	}
 
 	return 0;
@@ -8577,7 +8609,8 @@
 				p->chanvars = tmpvar;
 			}
 		}
-		p->prefs = user->prefs;
+		p->usercapability = user->capability;
+		p->userprefs = user->prefs;
 		/* replace callerid if rpid found, and not restricted */
 		if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
 			char *tmp;
@@ -8641,12 +8674,8 @@
 			p->pickupgroup = user->pickupgroup;
 			if (user->callingpres)	/* User callingpres setting will override RPID header */
 				p->callingpres = user->callingpres;
+			ast_codec_pref_remove2(&p->formats, ~user->capability);
 			
-			/* Set default codec settings for this call */
-			p->capability = user->capability;		/* User codec choice */
-			p->jointcapability = user->capability;		/* Our codecs */
-			if (p->peercapability)				/* AND with peer's codecs */
-				p->jointcapability &= p->peercapability;
 			if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
 			    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
 				p->noncodeccapability |= AST_RTP_DTMF;
@@ -8774,11 +8803,8 @@
 				p->amaflags = peer->amaflags;
 				p->callgroup = peer->callgroup;
 				p->pickupgroup = peer->pickupgroup;
-				p->capability = peer->capability;
-				p->prefs = peer->prefs;
-				p->jointcapability = peer->capability;
-				if (p->peercapability)
-					p->jointcapability &= p->peercapability;
+				ast_codec_pref_remove2(&p->formats, ~peer->capability);
+				p->userprefs = peer->prefs;
 				p->maxcallbitrate = peer->maxcallbitrate;
 				if (!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) {
 					ast_rtp_destroy(p->vrtp);
@@ -9434,18 +9460,9 @@
 /*! \brief Print codec list from preference to CLI/manager */
 static void print_codec_to_cli(int fd, struct ast_codec_pref *pref)
 {
-	int x, codec;
-
-	for(x = 0; x < 32 ; x++) {
-		codec = ast_codec_pref_index(pref, x);
-		if (!codec)
-			break;
-		ast_cli(fd, "%s", ast_getformatname(codec));
-		if (x < 31 && ast_codec_pref_index(pref, x + 1))
-			ast_cli(fd, ",");
-	}
-	if (!x)
-		ast_cli(fd, "none");
+	char buf[512];
+	ast_codec_pref_dump(buf, sizeof(buf), pref);
+	ast_cli(fd, "%s", buf);
 }
 
 /*! \brief Print domain mode to cli */
@@ -9530,10 +9547,9 @@
 	char iabuf[INET_ADDRSTRLEN];
 	struct sip_peer *peer;
 	char codec_buf[512];
-	struct ast_codec_pref *pref;
 	struct ast_variable *v;
 	struct sip_auth *auth;
-	int x = 0, codec = 0, load_realtime;
+	int x, load_realtime;
 	int realtimepeers;
 
 	realtimepeers = ast_check_realtime("sippeers");
@@ -9629,10 +9645,9 @@
 		ast_cli(fd, "  Codecs       : ");
 		ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
 		ast_cli(fd, "%s\n", codec_buf);
-		ast_cli(fd, "  Codec Order  : (");
+		ast_cli(fd, "  Codec Order  : ");
 		print_codec_to_cli(fd, &peer->prefs);
-
-		ast_cli(fd, ")\n");
+		ast_cli(fd, "\n");
 
 		ast_cli(fd, "  Status       : ");
 		peer_status(peer, status, sizeof(status));
@@ -9696,17 +9711,8 @@
 		ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
 		astman_append(s, "%s\r\n", codec_buf);
 		astman_append(s, "CodecOrder: ");
-		pref = &peer->prefs;
-		for(x = 0; x < 32 ; x++) {
-			codec = ast_codec_pref_index(pref,x);
-			if (!codec)
-				break;
-			astman_append(s, "%s", ast_getformatname(codec));
-			if (x < 31 && ast_codec_pref_index(pref,x+1))
-				astman_append(s, ",");
-		}
-
-		astman_append(s, "\r\n");
+		ast_codec_pref_dump(codec_buf, sizeof(codec_buf), &peer->prefs);
+		astman_append(s, "%s\r\n", codec_buf);
 		astman_append(s, "Status: ");
 		peer_status(peer, status, sizeof(status));
 		astman_append(s, "%s\r\n", status);
@@ -9734,9 +9740,8 @@
 {
 	char cbuf[256];
 	struct sip_user *user;
-	struct ast_codec_pref *pref;
 	struct ast_variable *v;
-	int x = 0, codec = 0, load_realtime;
+	int load_realtime;
 
 	if (argc < 4)
 		return RESULT_SHOWUSAGE;
@@ -9765,20 +9770,9 @@
 		print_group(fd, user->pickupgroup, 0);
 		ast_cli(fd, "  Callerid     : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), user->cid_name, user->cid_num, "<unspecified>"));
 		ast_cli(fd, "  ACL          : %s\n", (user->ha?"Yes":"No"));
-		ast_cli(fd, "  Codec Order  : (");
-		pref = &user->prefs;
-		for(x = 0; x < 32 ; x++) {
-			codec = ast_codec_pref_index(pref,x);
-			if (!codec)
-				break;
-			ast_cli(fd, "%s", ast_getformatname(codec));
-			if (x < 31 && ast_codec_pref_index(pref,x+1))
-				ast_cli(fd, "|");
-		}
-
-		if (!x)
-			ast_cli(fd, "none");
-		ast_cli(fd, ")\n");
+		ast_cli(fd, "  Codec Order  : ");
+		print_codec_to_cli(fd, &user->prefs);
+		ast_cli(fd, "\n");
 
 		if (user->chanvars) {
  			ast_cli(fd, "  Variables    :\n");
@@ -9986,7 +9980,7 @@
 				S_OR(cur->username, S_OR(cur->cid_num, "(None)")),
 				cur->callid, 
 				cur->ocseq, cur->icseq, 
-				ast_getformatname(cur->owner ? cur->owner->nativeformats : 0), 
+				ast_getformatname(cur->owner ? ast_codec_pref_index_audio(&cur->owner->nativeformats, 0)	: 0), 
 				ast_test_flag(&cur->flags[0], SIP_CALL_ONHOLD) ? "Yes" : "No",
 				ast_test_flag(&cur->flags[0], SIP_NEEDDESTROY) ? "(d)" : "",
 				cur->lastmsg ,
@@ -10155,6 +10149,7 @@
 	char iabuf[INET_ADDRSTRLEN];
 	size_t len;
 	int found = 0;
+	char buf[512];
 
 	if (argc != 4)
 		return RESULT_SHOWUSAGE;
@@ -10162,7 +10157,6 @@
 	ast_mutex_lock(&iflock);
 	for (cur = iflist; cur; cur = cur->next) {
 		if (!strncasecmp(cur->callid, argv[3], len)) {
-			char formatbuf[BUFSIZ/2];
 			ast_cli(fd,"\n");
 			if (cur->subscribed != NONE)
 				ast_cli(fd, "  * Subscription (type: %s)\n", subscription_type2str(cur->subscribed));
@@ -10171,11 +10165,8 @@
 			ast_cli(fd, "  Direction:              %s\n", ast_test_flag(&cur->flags[0], SIP_OUTGOING)?"Outgoing":"Incoming");
 			ast_cli(fd, "  Call-ID:                %s\n", cur->callid);
 			ast_cli(fd, "  Owner channel ID:       %s\n", cur->owner ? cur->owner->name : "<none>");
-			ast_cli(fd, "  Our Codec Capability:   %d\n", cur->capability);
 			ast_cli(fd, "  Non-Codec Capability (DTMF):   %d\n", cur->noncodeccapability);
-			ast_cli(fd, "  Their Codec Capability:   %d\n", cur->peercapability);
-			ast_cli(fd, "  Joint Codec Capability:   %d\n", cur->jointcapability);
-			ast_cli(fd, "  Format:                 %s\n", ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->owner ? cur->owner->nativeformats : 0) );
+			ast_cli(fd, "  Formats                 %s\n", cur->owner ? ast_codec_pref_dump(buf, sizeof(buf), &cur->owner->nativeformats) : "Unknown");
 			ast_cli(fd, "  MaxCallBR:              %d kbps\n", cur->maxcallbitrate);
 			ast_cli(fd, "  Theoretical Address:    %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr), ntohs(cur->sa.sin_port));
 			ast_cli(fd, "  Received Address:       %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), cur->recv.sin_addr), ntohs(cur->recv.sin_port));
@@ -10941,7 +10932,7 @@
 		codecnum = colname + 6;	/* move past the '[' */
 		codecnum = strsep(&codecnum, "]"); /* trim trailing ']' if any */
 		index = atoi(codecnum);
-		if((codec = ast_codec_pref_index(&peer->prefs, index))) {
+		if((codec = ast_codec_pref_index_audio(&peer->prefs, index))) {
 			ast_copy_string(buf, ast_getformatname(codec), len);
 		}
 	}
@@ -12681,7 +12672,6 @@
 					return -1;
 				}
 			} else {
-				p->jointcapability = p->capability;
 				ast_log(LOG_DEBUG, "Hm....  No sdp for the moment\n");
 			}
 			if (recordhistory) /* This is a response, note what it was for */
@@ -12721,7 +12711,6 @@
 				return -1;
 			}
 		} else {	/* No SDP in invite, call control session */
-			p->jointcapability = p->capability;
 			if (option_debug > 1)
 				ast_log(LOG_DEBUG, "No SDP in Invite, third party call control\n");
 		}
@@ -12955,7 +12944,7 @@
 		if (p && !ast_test_flag(&p->flags[0], SIP_NEEDDESTROY)) {
 			const char *msg;
 
-			if (!p->jointcapability)
+			if (!ast_codec_pref_bits(&p->formats))
 				msg = "488 Not Acceptable Here (codec error)";
 			else {
 				ast_log(LOG_NOTICE, "Unable to create/find SIP channel for this INVITE\n");
@@ -14528,23 +14517,16 @@
 
 /*! \brief PBX interface function -build SIP pvt structure */
 /* SIP calls initiated by the PBX arrive here */
-static struct ast_channel *sip_request_call(const char *type, int format, void *data, int *cause)
+static struct ast_channel *sip_request_call(const char *type, const struct ast_codec_pref *formats, void *data, int *cause)
 {
-	int oldformat;
 	struct sip_pvt *p;
 	struct ast_channel *tmpc = NULL;
 	char *ext, *host;
 	char tmp[256];
 	char *dest = data;
 
-	oldformat = format;
-	if (!(format &= ((AST_FORMAT_MAX_AUDIO << 1) - 1))) {
-		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format %s while capability is %s\n", ast_getformatname(oldformat), ast_getformatname(global_capability));
-		*cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;	/* Can't find codec to connect to host */
-		return NULL;
-	}
 	if (option_debug)
-		ast_log(LOG_DEBUG, "Asked to create a SIP channel with formats: %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), oldformat));
+		ast_log(LOG_DEBUG, "Asked to create a SIP channel with formats: %s\n", ast_codec_pref_dump(tmp, sizeof(tmp), formats));
 
 	if (!(p = sip_alloc(NULL, NULL, 0, SIP_INVITE))) {
 		ast_log(LOG_ERROR, "Unable to build sip pvt data for '%s' (Out of memory or socket error)\n", (char *)data);
@@ -14570,6 +14552,7 @@
 			*ext++ = '\0';
 		host = tmp;
 	}
+	ast_codec_pref_combine(&p->formats, formats, global_capability);
 
 	if (create_addr(p, host)) {
 		*cause = AST_CAUSE_UNREGISTERED;
@@ -14597,7 +14580,6 @@
 #if 0
 	printf("Setting up to call extension '%s' at '%s'\n", ext ? ext : "<none>", host);
 #endif
-	p->prefcodec = oldformat;				/* Format for this call */
 	ast_mutex_lock(&p->lock);
 	tmpc = sip_new(p, AST_STATE_DOWN, host);	/* Place the call */
 	ast_mutex_unlock(&p->lock);
@@ -15972,7 +15954,7 @@
 }
 
 /*! \brief Set the RTP peer for this call */
-static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
+static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, const struct ast_codec_pref *codecs, int nat_active)
 {
 	struct sip_pvt *p;
 	int changed = 0;
@@ -16003,8 +15985,15 @@
 		changed |= ast_rtp_get_peer(vrtp, &p->vredirip);
 	else
 		memset(&p->vredirip, 0, sizeof(p->vredirip));
-	if (codecs && (p->redircodecs != codecs)) {
-		p->redircodecs = codecs;
+	if (codecs != NULL) {
+		if (ast_codec_pref_bits(&p->redircodecs) != ast_codec_pref_bits(codecs))
+	       	{
+			memcpy(&p->redircodecs, codecs, sizeof(p->redircodecs));
+			changed = 1;
+		}
+	}
+	else if (ast_codec_pref_bits(&p->redircodecs)) {
+		ast_codec_pref_init(&p->redircodecs);
 		changed = 1;
 	}
 	if (changed && !ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
@@ -16190,13 +16179,6 @@
 
 	/* hangup here */
 	return -1;
-}
-
-/*! \brief Return SIP UA's codec (part of the RTP interface) */
-static int sip_get_codec(struct ast_channel *chan)
-{
-	struct sip_pvt *p = chan->tech_pvt;
-	return p->peercapability;	
 }
 
 /*! \brief Send a poke to all known peers */
Index: channels/chan_skinny.c
===================================================================
--- channels/chan_skinny.c	(revision 34061)
+++ channels/chan_skinny.c	(working copy)
@@ -905,7 +905,7 @@
 	struct skinnysession *next;
 } *sessions = NULL;
 
-static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause);
+static struct ast_channel *skinny_request(const char *type, const struct ast_codec_pref *format, void *data, int *cause);
 static int skinny_call(struct ast_channel *ast, char *dest, int timeout);
 static int skinny_hangup(struct ast_channel *ast);
 static int skinny_answer(struct ast_channel *ast);
@@ -1349,7 +1349,7 @@
 	return NULL;
 }
 
-static int skinny_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
+static int skinny_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, const struct ast_codec_pref *codecs, int nat_active)
 {
 	struct skinny_subchannel *sub;
 	sub = chan->tech_pvt;
@@ -2063,9 +2063,9 @@
 	if (sub->owner) {
 		/* We already hold the channel lock */
 		if (f->frametype == AST_FRAME_VOICE) {
-			if (f->subclass != sub->owner->nativeformats) {
+			if (!(f->subclass & ast_codec_pref_bits(&sub->owner->nativeformats))) {
 				ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
-				sub->owner->nativeformats = f->subclass;
+				ast_codec_pref_append(&sub->owner->nativeformats, f->subclass);
 				ast_set_read_format(sub->owner, sub->owner->readformat);
 				ast_set_write_format(sub->owner, sub->owner->writeformat);
 			}
@@ -2096,9 +2096,9 @@
 			return 0;
 		}
 	} else {
-		if (!(frame->subclass & ast->nativeformats)) {
+		if (!(frame->subclass & ast_codec_pref_bits(&ast->nativeformats))) {
 			ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
-				frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
+				frame->subclass, ast_codec_pref_bits(&ast->nativeformats), ast->readformat, ast->writeformat);
 			return -1;
 		}
 	}
@@ -2254,12 +2254,12 @@
 	tmp = ast_channel_alloc(1);
 	if (tmp) {
 		tmp->tech = &skinny_tech;
-		tmp->nativeformats = l->capability;
-		if (!tmp->nativeformats)
-			tmp->nativeformats = capability;
-		fmt = ast_best_codec(tmp->nativeformats);
+		ast_codec_pref_append_missing2(&tmp->nativeformats, l->capability);
+		if (!ast_codec_pref_bits(&tmp->nativeformats))
+			ast_codec_pref_append_missing2(&tmp->nativeformats, capability);
+		fmt = ast_best_codec(ast_codec_pref_bits(&tmp->nativeformats));
 		if (skinnydebug) {
-			ast_verbose("skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp->nativeformats, fmt);
+			ast_verbose("skinny_new: tmp->nativeformats=%d fmt=%d\n", ast_codec_pref_bits(&tmp->nativeformats), fmt);
 		}
 		ast_string_field_build(tmp, name, "Skinny/%s@%s-%d", l->name, l->parent->name, sub->callid);
 		if (sub->rtp) {
@@ -3049,20 +3049,13 @@
 	return 0;
 }
 
-static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause)
+static struct ast_channel *skinny_request(const char *type, const struct ast_codec_pref *formats, void *data, int *cause)
 {
-	int oldformat;
 	struct skinny_subchannel *sub;
 	struct ast_channel *tmpc = NULL;
 	char tmp[256];
 	char *dest = data;
 
-	oldformat = format;
-	format &= capability;
-	if (!format) {
-		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
-		return NULL;
-	}
 	ast_copy_string(tmp, dest, sizeof(tmp));
 	if (ast_strlen_zero(tmp)) {
 		ast_log(LOG_NOTICE, "Skinny channels require a device\n");
Index: channels/chan_zap.c
===================================================================
--- channels/chan_zap.c	(revision 34061)
+++ channels/chan_zap.c	(working copy)
@@ -694,7 +694,7 @@
 	int dsp_features;
 } *iflist = NULL, *ifend = NULL;
 
-static struct ast_channel *zt_request(const char *type, int format, void *data, int *cause);
+static struct ast_channel *zt_request(const char *type, const struct ast_codec_pref *format, void *data, int *cause);
 static int zt_digit(struct ast_channel *ast, char digit);
 static int zt_sendtext(struct ast_channel *c, const char *text);
 static int zt_call(struct ast_channel *ast, char *rdest, int timeout);
@@ -5076,7 +5076,7 @@
 			y++;
 		} while (x < 3);
 		tmp->fds[0] = i->subs[index].zfd;
-		tmp->nativeformats = AST_FORMAT_SLINEAR | deflaw;
+		ast_codec_pref_append_missing2(&tmp->nativeformats, AST_FORMAT_SLINEAR | deflaw);
 		/* Start out assuming ulaw since it's smaller :) */
 		tmp->rawreadformat = deflaw;
 		tmp->readformat = deflaw;
@@ -7558,7 +7558,7 @@
 }
 #endif
 
-static struct ast_channel *zt_request(const char *type, int format, void *data, int *cause)
+static struct ast_channel *zt_request(const char *type, const struct ast_codec_pref *format, void *data, int *cause)
 {
 	int groupmatch = 0;
 	int channelmatch = -1;
@@ -8227,9 +8227,12 @@
 #endif
 			if (nextidle > -1) {
 				if (ast_tvdiff_ms(ast_tvnow(), lastidle) > 1000) {
+					struct ast_codec_pref ulaw;
+					ast_codec_pref_init(&ulaw);
+					ast_codec_pref_append(&ulaw, AST_FORMAT_ULAW);
 					/* Don't create a new idle call more than once per second */
 					snprintf(idlen, sizeof(idlen), "%d/%s", pri->pvts[nextidle]->channel, pri->idledial);
-					idle = zt_request("Zap", AST_FORMAT_ULAW, idlen, &cause);
+					idle = zt_request("Zap", &ulaw, idlen, &cause);
 					if (idle) {
 						pri->pvts[nextidle]->isidlecall = 1;
 						if (ast_pthread_create(&p, NULL, do_idle_thread, idle)) {
Index: channels/iax2-parser.c
===================================================================
--- channels/iax2-parser.c	(revision 34061)
+++ channels/iax2-parser.c	(working copy)
@@ -95,7 +95,7 @@
 	strncpy(output, value, maxlen);
 	output[maxlen] = '\0';
 	
-	ast_codec_pref_convert(&pref, output, total_len, 0);
+	ast_codec_pref_convert_from_buf(&pref, output, total_len);
 	memset(output,0,total_len);
 	ast_codec_pref_string(&pref, output, total_len);
 }
Index: cli.c
===================================================================
--- cli.c	(revision 34061)
+++ cli.c	(working copy)
@@ -700,8 +700,6 @@
 		"  NativeFormats: %s\n"
 		"    WriteFormat: %s\n"
 		"     ReadFormat: %s\n"
-		" WriteTranscode: %s\n"
-		"  ReadTranscode: %s\n"
 		"1st File Descriptor: %d\n"
 		"      Frames in: %d%s\n"
 		"     Frames out: %d%s\n"
@@ -722,11 +720,9 @@
 		S_OR(c->cid.cid_num, "(N/A)"),
 		S_OR(c->cid.cid_name, "(N/A)"),
 		S_OR(c->cid.cid_dnid, "(N/A)"), ast_state2str(c->_state), c->_state, c->rings, 
-		ast_getformatname_multiple(nf, sizeof(nf), c->nativeformats), 
+		ast_codec_pref_dump(nf, sizeof(nf), &c->nativeformats), 
 		ast_getformatname_multiple(wf, sizeof(wf), c->writeformat), 
 		ast_getformatname_multiple(rf, sizeof(rf), c->readformat),
-		c->writetrans ? "Yes" : "No",
-		c->readtrans ? "Yes" : "No",
 		c->fds[0],
 		c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
 		c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
Index: file.c
===================================================================
--- file.c	(revision 34061)
+++ file.c	(working copy)
@@ -586,7 +586,7 @@
 		int fd;
 		const char *fmt;
 
-		if (!(chan->nativeformats & format))
+		if (!(ast_codec_pref_bits(&chan->nativeformats) & format))
 			continue;
 		fmt = ast_getformatname(format);
 		if ( fileexists_core(filename, fmt, preflang, buf, buflen) < 1)	/* no valid format */
@@ -807,7 +807,7 @@
 #endif
 		return 0;
 	}
-	ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname_multiple(fmt, sizeof(fmt), chan->nativeformats), strerror(errno));
+	ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_codec_pref_dump(fmt, sizeof(fmt), &chan->nativeformats), strerror(errno));
 	return -1;
 }
 
Index: frame.c
===================================================================
--- frame.c	(revision 34061)
+++ frame.c	(working copy)
@@ -895,33 +895,57 @@
 	return 0;	
 }
 
-void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right) 
+void ast_codec_pref_convert_to_buf(const struct ast_codec_pref *pref, char *buf, size_t size)
 {
-	int x, differential = (int) 'A', mem;
-	char *from, *to;
-
-	if(right) {
-		from = pref->order;
-		to = buf;
-		mem = size;
-	} else {
-		to = pref->order;
-		from = buf;
-		mem = 32;
+	int limit = size < 32 ? size : 32;
+	int i;
+	int x = 0;
+
+	memset(buf, 0, size);
+	for (i = 0; i < limit; ++i)
+	{
+		if (!pref->audio_order[i])
+			break;
+		buf[i] = pref->audio_order[i] + (int) 'A';
+	}
+	x = i;
+	for (i = 0; (i + x) < limit; ++i)
+	{
+		if (!pref->video_order[i])
+			break;
+		buf[i + x] = pref->video_order[i] + (int) 'A';
 	}
+}
 
-	memset(to, 0, mem);
-	for (x = 0; x < 32 ; x++) {
-		if(!from[x])
+void ast_codec_pref_convert_from_buf(struct ast_codec_pref *pref, char *buf, size_t size)
+{
+	int i;
+	int limit = size < 32 ? size : 32;
+	int slot;
+	static int max_slot = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
+
+	ast_codec_pref_init(pref);
+	for (i = 0; i < limit; ++i)
+	{
+		if (!buf[i])
 			break;
-		to[x] = right ? (from[x] + differential) : (from[x] - differential);
+		slot = buf[i] - 1 - (int) 'A';
+		if (slot >= 0 && slot < max_slot) {
+			ast_codec_pref_append(pref, AST_FORMAT_LIST[slot].bits);
+		}
 	}
 }
 
-int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size) 
+char *ast_codec_pref_dump(char *buf, size_t size, const struct ast_codec_pref *pref)
+{
+	ast_codec_pref_string(pref, buf, size);
+	return buf;
+}
+
+int ast_codec_pref_string(const struct ast_codec_pref *pref, char *buf, size_t size) 
 {
 	int x, codec; 
-	size_t total_len, slen;
+	size_t total_len, slen = 0;
 	char *formatname;
 	
 	memset(buf,0,size);
@@ -931,7 +955,7 @@
 	for(x = 0; x < 32 ; x++) {
 		if(total_len <= 0)
 			break;
-		if(!(codec = ast_codec_pref_index(pref,x)))
+		if(!(codec = ast_codec_pref_index_audio(pref,x)))
 			break;
 		if((formatname = ast_getformatname(codec))) {
 			slen = strlen(formatname);
@@ -940,7 +964,28 @@
 			strncat(buf,formatname,total_len);
 			total_len -= slen;
 		}
-		if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
+		if(total_len && x < 31 && ast_codec_pref_index_audio(pref , x + 1)) {
+			strncat(buf,"|",total_len);
+			total_len--;
+		}
+	}
+	if ((slen <= total_len) && pref->video_bits) {
+		strncat(buf,"|",total_len);
+		total_len--;
+	}
+	for(x = 0; x < 32 ; x++) {
+		if(total_len <= 0)
+			break;
+		if(!(codec = ast_codec_pref_index_video(pref,x)))
+			break;
+		if((formatname = ast_getformatname(codec))) {
+			slen = strlen(formatname);
+			if(slen > total_len)
+				break;
+			strncat(buf,formatname,total_len);
+			total_len -= slen;
+		}
+		if(total_len && x < 31 && ast_codec_pref_index_video(pref , x + 1)) {
 			strncat(buf,"|",total_len);
 			total_len--;
 		}
@@ -953,18 +998,34 @@
 	return size - total_len;
 }
 
-int ast_codec_pref_index(struct ast_codec_pref *pref, int index) 
+int ast_codec_pref_index_audio(const struct ast_codec_pref *pref, int index) 
 {
 	int slot = 0;
 
 	
-	if((index >= 0) && (index < sizeof(pref->order))) {
-		slot = pref->order[index];
+	if((index >= 0) && (index < sizeof(pref->audio_order))) {
+		slot = pref->audio_order[index];
 	}
 
 	return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
 }
 
+int ast_codec_pref_index_video(const struct ast_codec_pref *pref, int index) 
+{
+	int slot = 0;
+
+	
+	if((index >= 0) && (index < sizeof(pref->video_order))) {
+		slot = pref->video_order[index];
+	}
+
+	return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
+}
+
+int ast_codec_pref_bits(const struct ast_codec_pref *pref) {
+	return pref->audio_bits | pref->video_bits;
+}
+
 /*! \brief Remove codec from pref list */
 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
 {
@@ -972,26 +1033,46 @@
 	int x, y = 0;
 	int slot;
 
-	if(!pref->order[0])
+	if(!(pref->audio_order[0] + pref->video_order[0]) ||
+	   !(ast_codec_pref_bits(pref) & format))
+	{
 		return;
-
+	}
 	memcpy(&oldorder, pref, sizeof(oldorder));
 	memset(pref, 0, sizeof(*pref));
 
 	for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
-		slot = oldorder.order[x];
+		slot = oldorder.audio_order[x];
 		if(! slot)
 			break;
-		if(AST_FORMAT_LIST[slot-1].bits != format)
-			pref->order[y++] = slot;
+		if(AST_FORMAT_LIST[slot-1].bits != format) {
+			pref->audio_order[y++] = slot;
+			pref->audio_bits |= AST_FORMAT_LIST[slot - 1].bits;
+		}
+	}
+	for (y = 0, x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
+		slot = oldorder.video_order[x];
+		if(! slot)
+			break;
+		if(AST_FORMAT_LIST[slot-1].bits != format) {
+			pref->video_order[y++] = slot;
+			pref->video_bits |= AST_FORMAT_LIST[slot - 1].bits;
+		}
 	}
-	
 }
 
 /*! \brief Append codec to list */
 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
 {
-	int x, newindex = -1;
+	int x, newindex = 0;
+	char *order = format < AST_FORMAT_MAX_AUDIO ?
+				pref->audio_order :
+				pref->video_order;
+	int *bits = format < AST_FORMAT_MAX_AUDIO ?
+				&pref->audio_bits :
+				&pref->video_bits;
+	if (!format)
+		return 0;
 
 	ast_codec_pref_remove(pref, format);
 
@@ -1004,8 +1085,9 @@
 
 	if(newindex) {
 		for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
-			if(!pref->order[x]) {
-				pref->order[x] = newindex;
+			if(!order[x]) {
+				order[x] = newindex;
+				*bits |= format;
 				break;
 			}
 		}
@@ -1021,7 +1103,7 @@
 	int x, ret = 0, slot;
 
 	for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
-		slot = pref->order[x];
+		slot = pref->audio_order[x];
 
 		if (!slot)
 			break;
@@ -1032,6 +1114,18 @@
 	}
 	if(ret & AST_FORMAT_AUDIO_MASK)
 		return ret;
+	for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
+		slot = pref->video_order[x];
+
+		if(!slot)
+			break;
+		if ( formats & AST_FORMAT_LIST[slot-1].bits ) {
+			ret = AST_FORMAT_LIST[slot-1].bits;
+			break;
+		}
+	}
+	if(ret)
+		return ret;
 
 	if (option_debug > 3)
 		ast_log(LOG_DEBUG, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
@@ -1072,6 +1166,108 @@
 				memset(pref, 0, sizeof(*pref));
 			}
 		}
+	}
+}
+
+void ast_codec_pref_append_missing2(struct ast_codec_pref *pref, int newformats)
+{
+	int i;
+	int format;
+
+	for (i = 0; i < 32; ++i) {
+		format = (1 << i);
+		if (!(format & ast_codec_pref_bits(pref)) &&
+		    (format & newformats))
+		{
+			ast_codec_pref_append(pref, format);
+		}
+	}
+}
+
+void ast_codec_pref_append_missing(struct ast_codec_pref *pref, const struct ast_codec_pref *newformats)
+{
+	int i;
+	int format;
+	const int size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
+	int slot;
+
+	for (i = 0; i < size; i++) {
+		if (!(slot = newformats->audio_order[i]))
+			break;
+		format = AST_FORMAT_LIST[slot - 1].bits;
+		if (!(format & pref->audio_bits))
+			ast_codec_pref_append(pref, format);
+	}
+	for (i = 0; i < size; i++) {
+		if (!(slot = newformats->video_order[i]))
+			break;
+		format = AST_FORMAT_LIST[slot - 1].bits;
+		if (!(format & pref->video_bits))
+			ast_codec_pref_append(pref, format);
+	}
+}
+
+void ast_codec_pref_init(struct ast_codec_pref *pref)
+{
+	memset(pref, 0, sizeof(*pref));
+}
+
+void ast_codec_pref_set2(struct ast_codec_pref *pref, int formats)
+{
+	ast_codec_pref_init(pref);
+	ast_codec_pref_append_missing2(pref, formats);
+}
+
+int ast_codec_pref_intersect(const struct ast_codec_pref *pref1, const struct ast_codec_pref *pref2)
+{
+	return (pref1->video_bits | pref1->audio_bits) &
+		(pref2->video_bits | pref2->audio_bits);
+}
+
+int ast_codec_pref_eq_noorder(const struct ast_codec_pref *pref1, const struct ast_codec_pref *pref2)
+{
+	return (pref1->video_bits | pref1->audio_bits) ==
+		(pref2->video_bits | pref2->audio_bits);
+}
+
+void ast_codec_pref_combine(struct ast_codec_pref *dest, 
+			    const struct ast_codec_pref *main, 
+			    const int mask)
+{
+	const int size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
+	int i;
+	int slot;
+	int format;
+
+	ast_codec_pref_init(dest);
+	for (i = 0; i < size; ++i)
+	{
+		if (!(slot = main->audio_order[i]))
+			break;
+		format = AST_FORMAT_LIST[slot - 1].bits;
+		if (mask & format)
+			ast_codec_pref_append(dest, format);
+	}
+	for (i = 0; i < size; ++i)
+	{
+		if (!(slot = main->video_order[i]))
+			break;
+		format = AST_FORMAT_LIST[slot - 1].bits;
+		if (mask & format)
+			ast_codec_pref_append(dest, format);
+	}
+}
+
+void ast_codec_pref_remove2(struct ast_codec_pref *pref, int formats)
+{
+	int i;
+	int format;
+
+	for (i = 0; i < 32; ++i)
+	{
+		format = (1 << i);
+		if (format & formats & ast_codec_pref_bits(pref))
+			ast_codec_pref_remove(pref, format);
 	}
 }
 
Index: funcs/func_channel.c
===================================================================
--- funcs/func_channel.c	(revision 34061)
+++ funcs/func_channel.c	(working copy)
@@ -67,11 +67,11 @@
 	if (!strcasecmp(data, "audionativeformat"))
 		/* use the _multiple version when chan->nativeformats holds multiple formats */
 		/* ast_getformatname_multiple(buf, len, chan->nativeformats & AST_FORMAT_AUDIO_MASK); */
-		ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_AUDIO_MASK), len);
+		ast_copy_string(buf, ast_getformatname(ast_codec_pref_index_audio(&chan->nativeformats, 0)), len);
 	else if (!strcasecmp(data, "videonativeformat"))
 		/* use the _multiple version when chan->nativeformats holds multiple formats */
 		/* ast_getformatname_multiple(buf, len, chan->nativeformats & AST_FORMAT_VIDEO_MASK); */
-		ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_VIDEO_MASK), len);
+		ast_copy_string(buf, ast_getformatname(ast_codec_pref_index_video(&chan->nativeformats, 0)), len);
 	else if (!strcasecmp(data, "audioreadformat"))
 		ast_copy_string(buf, ast_getformatname(chan->readformat), len);
 	else if (!strcasecmp(data, "audiowriteformat"))
Index: include/asterisk/channel.h
===================================================================
--- include/asterisk/channel.h	(revision 34061)
+++ include/asterisk/channel.h	(working copy)
@@ -116,6 +116,7 @@
 #include "asterisk/utils.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/stringfields.h"
+#include "asterisk/translate.h"
 
 
 #define AST_MAX_FDS		8
@@ -195,7 +196,7 @@
 	int properties;			/*!< Technology Properties */
 
 	/*! \brief Requester - to set up call data structures (pvt's) */
-	struct ast_channel *(* const requester)(const char *type, int format, void *data, int *cause);
+	struct ast_channel *(* const requester)(const char *type, const struct ast_codec_pref *format, void *data, int *cause);
 
 	int (* const devicestate)(void *data);	/*!< Devicestate call back */
 
@@ -260,6 +261,9 @@
 	/*! \brief Find bridged channel */
 	struct ast_channel *(* const bridged_channel)(struct ast_channel *chan, struct ast_channel *bridge);
 
+	/*! Try to fixup codecs */
+	void (*fixup_codecs)(struct ast_channel *chan, const struct ast_codec_pref *peer_codecs);
+
 	/*! \brief Provide additional read items for CHANNEL() dialplan function */
 	int (* func_channel_read)(struct ast_channel *chan, char *function, char *data, char *buf, size_t len);
 
@@ -372,12 +376,13 @@
 	unsigned short transfercapability;		/*!< ISDN Transfer Capbility - AST_FLAG_DIGITAL is not enough */
 	struct ast_frame *readq;
 	int alertpipe[2];
+	struct ast_trans_pvt *writetrans_matrix[MAX_FORMAT][MAX_FORMAT]; /*!< Write translation path */
+	struct ast_trans_pvt *readtrans_matrix[MAX_FORMAT][MAX_FORMAT];  /*!< Read translation path */
 
-	int nativeformats;				/*!< Kinds of data this channel can natively handle */
+	struct ast_codec_pref nativeformats;		/*!< Kinds of data this channel can natively handle */
 	int readformat;					/*!< Requested read format */
 	int writeformat;				/*!< Requested write format */
-	struct ast_trans_pvt *writetrans;		/*!< Write translation path */
-	struct ast_trans_pvt *readtrans;		/*!< Read translation path */
+	int lastreadformat;				/*!< Format of last frame read */
 	int rawreadformat;				/*!< Raw read format */
 	int rawwriteformat;				/*!< Raw write format */
 
@@ -597,7 +602,7 @@
  * by the low level module
  * \return Returns an ast_channel on success, NULL on failure.
  */
-struct ast_channel *ast_request(const char *type, int format, void *data, int *status);
+struct ast_channel *ast_request(const char *type, const struct ast_codec_pref *formats, void *data, int *status);
 
 /*!
  * \brief Request a channel of a given type, with data as optional information used 
@@ -612,9 +617,9 @@
  * \return Returns an ast_channel on success or no answer, NULL on failure.  Check the value of chan->_state
  * to know if the call was answered or not.
  */
-struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname);
+struct ast_channel *ast_request_and_dial(const char *type, const struct ast_codec_pref *format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname);
 
-struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname, struct outgoing_helper *oh);
+struct ast_channel *__ast_request_and_dial(const char *type, const struct ast_codec_pref *format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname, struct outgoing_helper *oh);
 
 /*!\brief Register a channel technology (a new channel driver)
  * Called by a channel module to register the kind of channels it supports.
Index: include/asterisk/frame.h
===================================================================
--- include/asterisk/frame.h	(revision 34061)
+++ include/asterisk/frame.h	(working copy)
@@ -34,7 +34,10 @@
 #include "asterisk/endian.h"
 
 struct ast_codec_pref {
-	char order[32];
+	char audio_order[32];
+	char video_order[32];
+	int audio_bits;
+	int video_bits;
 };
 
 /*! \page Def_Frame AST Multimedia and signalling frames
@@ -228,6 +231,8 @@
 #define AST_FORMAT_SPEEX	(1 << 9)
 /*! iLBC Free Compression */
 #define AST_FORMAT_ILBC		(1 << 10)
+/*! ADPCM (G.726, 40kbps) */
+#define AST_FORMAT_G726_40	(1 << 11)
 /*! Maximum audio format */
 #define AST_FORMAT_MAX_AUDIO	(1 << 15)
 /*! Maximum audio mask */
@@ -469,14 +474,28 @@
 	can't be transcoded and we just have to pick whatever is supported
 */
 
+/*! \brief Return bitmap of common codecs of the two preferences */
+extern int ast_codec_pref_intersect(const struct ast_codec_pref *pref1, const struct ast_codec_pref *pref2);
 /*! \brief Initialize an audio codec preference to "no preference" See \ref AudioCodecPref */
 void ast_codec_pref_init(struct ast_codec_pref *pref);
 
+/*! \brief Returns true if both prefs consists of the same set of codecs disregarding their order */
+extern int ast_codec_pref_eq_noorder(const struct ast_codec_pref *pref1, const struct ast_codec_pref *pref2);
+
 /*! \brief Codec located at a particular place in the preference index See \ref AudioCodecPref */
-int ast_codec_pref_index(struct ast_codec_pref *pref, int index);
+extern int ast_codec_pref_index_audio(const struct ast_codec_pref *pref, int index);
+
+/*! \brief Video codec located at  a particular place in the preference index */
+extern int ast_codec_pref_index_video(const struct ast_codec_pref *pref, int index);
+
+/*! \brief Remove a codec from a preference list */
+extern void ast_codec_pref_remove(struct ast_codec_pref *pref, int format);
 
-/*! \brief Remove audio a codec from a preference list */
-void ast_codec_pref_remove(struct ast_codec_pref *pref, int format);
+/*! \brief Returns the full bitmap of all codecs */
+extern int ast_codec_pref_bits(const struct ast_codec_pref *pref);
+
+/*! \brief Append a codec to a preference list, removing it first if it was already there */
+extern int ast_codec_pref_append(struct ast_codec_pref *pref, int format);
 
 /*! \brief Append a audio codec to a preference list, removing it first if it was already there 
 */
@@ -493,11 +512,16 @@
  */
 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char *list, int allowing);
 
-/*! \brief Dump audio codec preference list into a string */
-int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size);
+/*! \brief Dump codec preference list into a string */
+extern int ast_codec_pref_string(const struct ast_codec_pref *pref, char *buf, size_t size);
+
+/*! \brief Dump codec preference list into a string */
+extern char *ast_codec_pref_dump(char *buf, size_t size, const struct ast_codec_pref *pref);
 
-/*! \brief Shift an audio codec preference list up or down 65 bytes so that it becomes an ASCII string */
-void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right);
+/*! \brief Shift a codec preference list up 65 bytes so that it becomes an ASCII string */
+extern void ast_codec_pref_convert_to_buf(const struct ast_codec_pref *pref, char *buf, size_t size);
+/*! \brief Shift a codec preference list down 65 bytes so that it becomes an codec set */
+extern void ast_codec_pref_convert_from_buf(struct ast_codec_pref *pref, char *buf, size_t size);
 
 /*! \brief Returns the number of samples contained in the frame */
 int ast_codec_get_samples(struct ast_frame *f);
@@ -514,6 +538,57 @@
 { 
 	return (format == AST_FORMAT_ILBC) ? 30 : 20;
 }
+
+/*!
+ * \brief Append codecs.
+ * \param pref Codec set to be modified.
+ * \param newformats Bitmap of codecs to be appended.
+ *
+ * Append codecs from newformats to pref but only those that are not
+ * already in the pref.
+ */
+void ast_codec_pref_append_missing2(struct ast_codec_pref *pref, int newformats);
+
+/*!
+ * \brief Append codecs.
+ * \param pref Codec set to be modified.
+ * \param newformats Codecs to be appended.
+ *
+ * Append codecs from newformats to pref but only those that are not 
+ * already in the pref. Codecs appended after last codec in pref using 
+ * order from newformats.
+ */
+void ast_codec_pref_append_missing(struct ast_codec_pref *pref, const struct ast_codec_pref *newformats);
+
+/*!
+ * \brief Clear the pref then append formats given.
+ * \param pref Codec set to be set.
+ * \param formats Bitmap of codecs to be put to pref.
+ *
+ * Clears pref and puts given formats into it. Codec order is not well
+ * predictable so avoid using this function if codec order is important.
+ */
+void ast_codec_pref_set2(struct ast_codec_pref *pref, int formats);
+
+/*!
+ * \brief Combine codecs from main and mask and put them to dest.
+ * \param dest Codec set to be modified.
+ * \param main Source codec set.
+ * \param mask Bitmap of formats.
+ *
+ * Set dest to all codecs from main (in that order) but only 
+ * those that exist in mask. Previous content of dest is destroyed.
+ */
+void ast_codec_pref_combine(struct ast_codec_pref *dest, const struct ast_codec_pref *main, const int mask);
+
+/*!
+ * \brief Remove codecs.
+ * \param pref Codec set to be modified.
+ * \param formats Bitmap of codecs to be removed.
+ *
+ * Removes codecs that passed in bitmap formats from codec set pref.
+ */
+void ast_codec_pref_remove2(struct ast_codec_pref *pref, int formats);
 
 /*!
   \brief Adjusts the volume of the audio samples contained in a frame.
Index: include/asterisk/options.h
===================================================================
--- include/asterisk/options.h	(revision 34061)
+++ include/asterisk/options.h	(working copy)
@@ -23,6 +23,9 @@
 #ifndef _ASTERISK_OPTIONS_H
 #define _ASTERISK_OPTIONS_H
 
+enum ast_trans_algorithm { AST_TRANS_ALG_STRICT, AST_TRANS_ALG_LOOSE };
+extern enum ast_trans_algorithm option_translation_algorithm;
+
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
Index: include/asterisk/pbx.h
===================================================================
--- include/asterisk/pbx.h	(revision 34061)
+++ include/asterisk/pbx.h	(working copy)
@@ -687,11 +687,11 @@
 
 /*! Synchronously or asynchronously make an outbound call and send it to a
    particular extension */
-int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel);
+int ast_pbx_outgoing_exten(const char *type, const struct ast_codec_pref *formats, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel);
 
 /*! Synchronously or asynchronously make an outbound call and send it to a
    particular application with given extension */
-int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel);
+int ast_pbx_outgoing_app(const char *type, const struct ast_codec_pref *formats, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel);
 
 /*!
  * \brief Evaluate a condition
Index: include/asterisk/rtp.h
===================================================================
--- include/asterisk/rtp.h	(revision 34061)
+++ include/asterisk/rtp.h	(working copy)
@@ -49,6 +49,17 @@
 #define AST_RTP_MAX             	AST_RTP_CISCO_DTMF
 
 #define MAX_RTP_PT			256
+/*
+ * RFC3551, Section 6:
+ *  "...payload type values in the range 96-127 MAY be defined dynamically..."
+ */
+#define MAX_RTP_STATIC_PT               95
+
+/*! \brief The value of each payload format mapping: */
+struct rtpPayloadType {
+	int isAstFormat; 	/*!< whether the following code is an AST_FORMAT */
+	int code;
+};
 
 struct ast_rtp_protocol {
 	/*! Get RTP struct, or NULL if unwilling to transfer */
@@ -56,8 +67,7 @@
 	/*! Get RTP struct, or NULL if unwilling to transfer */
 	struct ast_rtp *(* const get_vrtp_info)(struct ast_channel *chan);
 	/*! Set RTP peer */
-	int (* const set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer, struct ast_rtp *vpeer, int codecs, int nat_active);
-	int (* const get_codec)(struct ast_channel *chan);
+	int (* const set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer, struct ast_rtp *vpeer, const struct ast_codec_pref *codecs, int nat_active);
 	const char * const type;
 	AST_LIST_ENTRY(ast_rtp_protocol) list;
 };
Index: include/asterisk/translate.h
===================================================================
--- include/asterisk/translate.h	(revision 34061)
+++ include/asterisk/translate.h	(working copy)
@@ -38,6 +38,7 @@
 #endif
 
 struct ast_trans_pvt;	/* declared below */
+struct ast_channel;
 
 /*! \brief
  * Descriptor of a translator. Name, callbacks, and various options
@@ -191,6 +192,13 @@
  */
 void ast_translator_free_path(struct ast_trans_pvt *tr);
 
+/*! Frees a translation path matrix assosiated with channel */
+/*!
+ * \param chan channel to free translation path matrix
+ * Frees the translation matrix in the given channel
+ */
+extern void ast_translator_free_translations(struct ast_channel *chan);
+
 /*!
  * \brief translates one or more frames
  * Apply an input frame into the translator and receive zero or one output frames.  Consume
@@ -201,6 +209,35 @@
  * \return an ast_frame of the new translation format on success, NULL on failure
  */
 struct ast_frame *ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume);
+/*! translates read frames */
+/*!
+ * \param chan channel through which the frame comes in
+ * \param f frame to translate
+ * \param consume Whether or not to free the original frame
+ * Translate frame into the readformat of the channel from any format and receive
+ * zero or one output frames.  Consume determines whether the original frame 
+ * should be freed.
+ * Returns an ast_frame of the new translation format on success, NULL on failure
+ */
+extern struct ast_frame *ast_translate_read(struct ast_channel *chan, struct ast_frame *f, int consume);
+/*! translates frames for writing */
+/*!
+ * \param chan channel through which the frame comes out
+ * \param f frame to translate
+ * \param consume Whether or not to free the original frame
+ * Translate frame into the writeformat of the channel from any format and receive
+ * zero or one output frames.  Consume determines whether the original frame 
+ * should be freed.
+ * Returns an ast_frame of the new translation format on success, NULL on failure
+ */
+extern struct ast_frame *ast_translate_write(struct ast_channel *chan, struct ast_frame *f, int consume);
+
+/*!
+ * Returns all formats that can be converted by asterisk from/to supplied format
+ * plus the format itself.
+ * \param formats formats for which to search compatible formats
+ */
+extern int ast_compatible_audio_formats(int format);
 
 /*!
  * \brief Returns the number of steps required to convert from 'src' to 'dest'.
Index: manager.c
===================================================================
--- manager.c	(revision 34061)
+++ manager.c	(working copy)
@@ -1305,14 +1305,18 @@
 	int res;
 	int reason = 0;
 	struct ast_channel *chan = NULL;
+	struct ast_codec_pref slin;
+
+	ast_codec_pref_init(&slin);
+	ast_codec_pref_append(&slin, AST_FORMAT_SLINEAR);
 
 	if (!ast_strlen_zero(in->app)) {
-		res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, 
+		res = ast_pbx_outgoing_app(in->tech, &slin, in->data, in->timeout, in->app, in->appdata, &reason, 1, 
 			S_OR(in->cid_num, NULL), 
 			S_OR(in->cid_name, NULL),
 			in->vars, in->account, &chan);
 	} else {
-		res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, 
+		res = ast_pbx_outgoing_exten(in->tech, &slin, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, 
 			S_OR(in->cid_num, NULL), 
 			S_OR(in->cid_name, NULL),
 			in->vars, in->account, &chan);
@@ -1385,6 +1389,11 @@
 	
 	pthread_t th;
 	pthread_attr_t attr;
+	struct ast_codec_pref slin;
+	
+	memset(&slin, 0, sizeof(&slin));
+	ast_codec_pref_append(&slin, AST_FORMAT_SLINEAR);
+	
 	if (!name) {
 		astman_send_error(s, m, "Channel not specified");
 		return 0;
@@ -1449,10 +1458,10 @@
 			}
 		}
 	} else if (!ast_strlen_zero(app)) {
-        	res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
+        	res = ast_pbx_outgoing_app(tech, &slin, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
     	} else {
 		if (exten && context && pi)
-	        	res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
+	        	res = ast_pbx_outgoing_exten(tech, &slin, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
 		else {
 			astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
 			return 0;
Index: pbx.c
===================================================================
--- pbx.c	(revision 34061)
+++ pbx.c	(working copy)
@@ -4521,7 +4521,7 @@
 	return 0;  /* success */
 }
 
-int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
+int ast_pbx_outgoing_exten(const char *type, const struct ast_codec_pref *formats, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
 {
 	struct ast_channel *chan;
 	struct async_stat *as;
@@ -4531,7 +4531,7 @@
 
 	if (sync) {
 		LOAD_OH(oh);
-		chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
+		chan = __ast_request_and_dial(type, formats, data, timeout, reason, cid_num, cid_name, &oh);
 		if (channel) {
 			*channel = chan;
 			if (chan)
@@ -4628,7 +4628,7 @@
 			res = -1;
 			goto outgoing_exten_cleanup;
 		}
-		chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
+		chan = ast_request_and_dial(type, formats, data, timeout, reason, cid_num, cid_name);
 		if (channel) {
 			*channel = chan;
 			if (chan)
@@ -4690,7 +4690,7 @@
 	return NULL;
 }
 
-int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
+int ast_pbx_outgoing_app(const char *type, const struct ast_codec_pref *formats, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
 {
 	struct ast_channel *chan;
 	struct app_tmp *tmp;
@@ -4709,7 +4709,7 @@
 		goto outgoing_app_cleanup;
 	}
 	if (sync) {
-		chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
+		chan = __ast_request_and_dial(type, formats, data, timeout, reason, cid_num, cid_name, &oh);
 		if (chan) {
 			if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
 				ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
@@ -4792,7 +4792,7 @@
 			res = -1;
 			goto outgoing_app_cleanup;
 		}
-		chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
+		chan = __ast_request_and_dial(type, formats, data, timeout, reason, cid_num, cid_name, &oh);
 		if (!chan) {
 			free(as);
 			res = -1;
Index: pbx/pbx_spool.c
===================================================================
--- pbx/pbx_spool.c	(revision 34061)
+++ pbx/pbx_spool.c	(working copy)
@@ -328,14 +328,19 @@
 {
 	struct outgoing *o = data;
 	int res, reason;
+	struct ast_codec_pref slin;
+
+	ast_codec_pref_init(&slin);
+	ast_codec_pref_append(&slin, AST_FORMAT_SLINEAR);
+	
 	if (!ast_strlen_zero(o->app)) {
 		if (option_verbose > 2)
 			ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries);
-		res = ast_pbx_outgoing_app(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL);
+		res = ast_pbx_outgoing_app(o->tech, &slin, o->dest, o->waittime * 1000, o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL);
 	} else {
 		if (option_verbose > 2)
 			ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for %s@%s:%d (Retry %d)\n", o->tech, o->dest, o->exten, o->context,o->priority, o->retries);
-		res = ast_pbx_outgoing_exten(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->context, o->exten, o->priority, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL);
+		res = ast_pbx_outgoing_exten(o->tech, &slin, o->dest, o->waittime * 1000, o->context, o->exten, o->priority, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL);
 	}
 	if (res) {
 		ast_log(LOG_NOTICE, "Call failed to go through, reason %d\n", reason);
Index: res/res_clioriginate.c
===================================================================
--- res/res_clioriginate.c	(revision 34061)
+++ res/res_clioriginate.c	(working copy)
@@ -72,6 +72,8 @@
 	char *chantech;
 	char *chandata;
 	int reason = 0;
+	struct ast_codec_pref slin;
+	ast_codec_pref_set2(&slin, AST_FORMAT_SLINEAR);
 	
 	if (ast_strlen_zero(app))
 		return RESULT_SHOWUSAGE;
@@ -84,7 +86,7 @@
 		return RESULT_SHOWUSAGE;
 	}
 
-	ast_pbx_outgoing_app(chantech, AST_FORMAT_SLINEAR, chandata, TIMEOUT * 1000, app, appdata, &reason, 1, NULL, NULL, NULL, NULL, NULL);
+	ast_pbx_outgoing_app(chantech, &slin, chandata, TIMEOUT * 1000, app, appdata, &reason, 1, NULL, NULL, NULL, NULL, NULL);
 
 	return RESULT_SUCCESS;
 }
@@ -96,6 +98,8 @@
 	char *exten = NULL;
 	char *context = NULL;
 	int reason = 0;
+	struct ast_codec_pref slin;
+	ast_codec_pref_set2(&slin, AST_FORMAT_SLINEAR);
 
 	chandata = ast_strdupa(chan);
 	
@@ -115,7 +119,7 @@
 	if (ast_strlen_zero(context))
 		context = "default";
 	
-	ast_pbx_outgoing_exten(chantech, AST_FORMAT_SLINEAR, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 1, NULL, NULL, NULL, NULL, NULL);
+	ast_pbx_outgoing_exten(chantech, &slin, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 1, NULL, NULL, NULL, NULL, NULL);
 
 	return RESULT_SUCCESS;
 }
Index: res/res_features.c
===================================================================
--- res/res_features.c	(revision 34061)
+++ res/res_features.c	(working copy)
@@ -207,7 +207,7 @@
 	}
 }
 
-static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name);
+static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, const struct ast_codec_pref *formats, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name);
 
 
 static void *ast_bridge_call_thread(void *data) 
@@ -724,7 +724,7 @@
 
 	l = strlen(xferto);
 	snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);	/* append context */
-	newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
+	newchan = ast_feature_request_and_dial(transferer, "Local", &transferer->nativeformats,
 		xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name);
 	ast_indicate(transferer, -1);
 	if (!newchan) {
@@ -1026,7 +1026,7 @@
 }
 
 /*! \todo XXX Check - this is very similar to the code in channel.c */
-static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name)
+static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, const struct ast_codec_pref *formats, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name)
 {
 	int state = 0;
 	int cause = 0;
@@ -1036,7 +1036,7 @@
 	struct ast_channel *active_channel;
 	int res = 0, ready = 0;
 	
-	if ((chan = ast_request(type, format, data, &cause))) {
+	if ((chan = ast_request(type, formats, data, &cause))) {
 		ast_set_callerid(chan, cid_num, cid_name, cid_num);
 		ast_channel_inherit_variables(caller, chan);	
 		pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
@@ -1242,6 +1242,27 @@
 	set_config_flags(chan, peer, config);
 	config->firstpass = 1;
 
+	if (ast_codec_pref_intersect(&chan->nativeformats, &peer->nativeformats))
+       	{
+		if (chan->tech->fixup_codecs && 
+		    ast_codec_pref_intersect(&chan->nativeformats, &peer->nativeformats) != ast_codec_pref_bits(&chan->nativeformats))
+		{
+			struct ast_codec_pref tmp;
+			memcpy(&tmp, &peer->nativeformats, sizeof(tmp));
+			/* Provide all compatible formats also */
+			ast_codec_pref_append_missing2(&tmp, ast_compatible_audio_formats(tmp.audio_bits));
+			chan->tech->fixup_codecs(chan, &tmp);
+		}
+		if (peer->tech->fixup_codecs && 
+		    ast_codec_pref_intersect(&chan->nativeformats, &peer->nativeformats) != ast_codec_pref_bits(&peer->nativeformats))
+		{
+			struct ast_codec_pref tmp;
+			memcpy(&tmp, &peer->nativeformats, sizeof(tmp));
+			/* Provide all compatible formats also */
+			ast_codec_pref_append_missing2(&tmp, ast_compatible_audio_formats(tmp.audio_bits));
+			peer->tech->fixup_codecs(peer, &tmp);
+		}
+	}
 	/* Answer if need be */
 	if (ast_answer(chan))
 		return -1;
Index: rtp.c
===================================================================
--- rtp.c	(revision 34061)
+++ rtp.c	(working copy)
@@ -56,6 +56,7 @@
 #include "asterisk/cli.h"
 #include "asterisk/unaligned.h"
 #include "asterisk/utils.h"
+#include "asterisk/translate.h"
 
 #define MAX_TIMESTAMP_SKEW	640
 
@@ -96,11 +97,6 @@
  * RTP session is defined on page 9 of RFC 3550: "An association among a set of participants communicating with RTP.  A participant may be involved in multiple RTP sessions at the same time [...]"
  *
  */
-/*! \brief The value of each payload format mapping: */
-struct rtpPayloadType {
-	int isAstFormat; 	/*!< whether the following code is an AST_FORMAT */
-	int code;
-};
 
 
 /*! \brief RTP session description */
@@ -164,6 +160,7 @@
 static int ast_rtcp_write_rr(void *data);
 static unsigned int ast_rtcp_calc_interval(struct ast_rtp *rtp);
 
+
 #define FLAG_3389_WARNING		(1 << 0)
 #define FLAG_NAT_ACTIVE			(3 << 1)
 #define FLAG_NAT_INACTIVE		(0 << 1)
@@ -1292,7 +1289,7 @@
 	struct ast_rtp *destp, *srcp=NULL;		/* Audio RTP Channels */
 	struct ast_rtp *vdestp, *vsrcp=NULL;		/* Video RTP channels */
 	struct ast_rtp_protocol *destpr, *srcpr=NULL;
-	int srccodec;
+	struct ast_codec_pref srccodecs;
 
 	/* Lock channels */
 	ast_channel_lock(dest);
@@ -1341,15 +1338,12 @@
 			ast_channel_unlock(src);
 		return 0;
 	}
-	if (srcpr && srcpr->get_codec)
-		srccodec = srcpr->get_codec(src);
-	else
-		srccodec = 0;
+	memcpy(&srccodecs, &src->nativeformats, sizeof(srccodecs));
 	/* Consider empty media as non-existant */
 	if (srcp && !srcp->them.sin_addr.s_addr)
 		srcp = NULL;
 	/* Bridge media early */
-	if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, srcp ? ast_test_flag(srcp, FLAG_NAT_ACTIVE) : 0))
+	if (destpr->set_rtp_peer(dest, srcp, vsrcp, &srccodecs, srcp ? ast_test_flag(srcp, FLAG_NAT_ACTIVE) : 0))
 		ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", dest->name, src ? src->name : "<unspecified>");
 	ast_channel_unlock(dest);
 	if (src)
@@ -1364,7 +1358,7 @@
 	struct ast_rtp *destp, *srcp;		/* Audio RTP Channels */
 	struct ast_rtp *vdestp, *vsrcp;		/* Video RTP channels */
 	struct ast_rtp_protocol *destpr, *srcpr;
-	int srccodec;
+	struct ast_codec_pref srccodecs;
 	/* Lock channels */
 	ast_channel_lock(dest);
 	while(ast_channel_trylock(src)) {
@@ -1407,13 +1401,10 @@
 	ast_rtp_pt_copy(destp, srcp);
 	if (vdestp && vsrcp)
 		ast_rtp_pt_copy(vdestp, vsrcp);
-	if (srcpr->get_codec)
-		srccodec = srcpr->get_codec(src);
-	else
-		srccodec = 0;
+	memcpy(&srccodecs, &src->nativeformats, sizeof(srccodecs));
 	if (media) {
 		/* Bridge early */
-		if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
+		if (destpr->set_rtp_peer(dest, srcp, vsrcp, &srccodecs, ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
 			ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", dest->name, src->name);
 	}
 	ast_channel_unlock(dest);
@@ -1429,8 +1420,11 @@
  */
 void ast_rtp_set_m_type(struct ast_rtp* rtp, int pt) 
 {
-	if (pt < 0 || pt > MAX_RTP_PT) 
-		return; /* bogus payload type */
+	/*
+	 * Get only static payload types here
+	 */
+	if (pt < 0 || pt > MAX_RTP_STATIC_PT) 
+		return; /* non-static payload type */
 
 	if (static_RTP_PT[pt].code != 0) 
 		rtp->current_RTP_PT[pt] = static_RTP_PT[pt];
@@ -2490,11 +2484,15 @@
 	
 	void *pvt0, *pvt1;
 	int codec0,codec1, oldcodec0, oldcodec1;
+        struct ast_codec_pref codecs0;
+        struct ast_codec_pref codecs1;
 	
 	memset(&vt0, 0, sizeof(vt0));
 	memset(&vt1, 0, sizeof(vt1));
 	memset(&vac0, 0, sizeof(vac0));
 	memset(&vac1, 0, sizeof(vac1));
+        ast_codec_pref_init(&codecs0);
+        ast_codec_pref_init(&codecs1);
 
 	/* Lock channels */
 	ast_channel_lock(c0);
@@ -2557,24 +2555,24 @@
 	}
 
 	/* Get codecs from both sides */
-	codec0 = pr0->get_codec ? pr0->get_codec(c0) : 0;
-	codec1 = pr1->get_codec ? pr1->get_codec(c1) : 0;
-	if (pr0->get_codec && pr1->get_codec) {
-		/* Hey, we can't do reinvite if both parties speak different codecs */
-		if (!(codec0 & codec1)) {
-			if (option_debug)
-				ast_log(LOG_DEBUG, "Channel codec0 = %d is not codec1 = %d, cannot native bridge in RTP.\n", codec0, codec1);
-			ast_channel_unlock(c0);
-			ast_channel_unlock(c1);
-			return AST_BRIDGE_FAILED_NOWARN;
-		}
+	codec0 = ast_codec_pref_bits(&c0->nativeformats);
+	codec1 = ast_codec_pref_bits(&c1->nativeformats);
+	memcpy(&codecs0, &c0->nativeformats, sizeof(codecs0));
+	memcpy(&codecs1, &c1->nativeformats, sizeof(codecs1));
+	/* Hey, we can't do reinvite if both parties speak different codecs */
+	if (!(codec0 & codec1)) {
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Channel codec0 = %d is not codec1 = %d, cannot native bridge in RTP.\n", codec0, codec1);
+		ast_channel_unlock(c0);
+		ast_channel_unlock(c1);
+		return AST_BRIDGE_FAILED_NOWARN;
 	}
 
 	if (option_verbose > 2) 
 		ast_verbose(VERBOSE_PREFIX_3 "Native bridging %s and %s\n", c0->name, c1->name);
 
 	/* Ok, we should be able to redirect the media. Start with one channel */
-	if (pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE))) 
+	if (pr0->set_rtp_peer(c0, p1, vp1, &codecs1, ast_test_flag(p1, FLAG_NAT_ACTIVE))) 
 		ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
 	else {
 		/* Store RTP peer */
@@ -2583,7 +2581,7 @@
 			ast_rtp_get_peer(vp1, &vac1);
 	}
 	/* Then test the other channel */
-	if (pr1->set_rtp_peer(c1, p0, vp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
+	if (pr1->set_rtp_peer(c1, p0, vp0, &codecs0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
 		ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name);
 	else {
 		/* Store RTP peer */
@@ -2607,11 +2605,11 @@
 			(c0->masq || c0->masqr || c1->masq || c1->masqr)) {
 				ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n");
 				if (c0->tech_pvt == pvt0) {
-					if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0)) 
+					if (pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0)) 
 						ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
 				}
 				if (c1->tech_pvt == pvt1) {
-					if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0)) 
+					if (pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0)) 
 						ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
 				}
 				return AST_BRIDGE_RETRY;
@@ -2619,10 +2617,8 @@
 		/* Now check if they have changed address */
 		ast_rtp_get_peer(p1, &t1);
 		ast_rtp_get_peer(p0, &t0);
-		if (pr0->get_codec)
-			codec0 = pr0->get_codec(c0);
-		if (pr1->get_codec)
-			codec1 = pr1->get_codec(c1);
+		codec0 = ast_codec_pref_bits(&c0->nativeformats);
+		codec1 = ast_codec_pref_bits(&c1->nativeformats);
 		if (vp1)
 			ast_rtp_get_peer(vp1, &vt1);
 		if (vp0)
@@ -2638,7 +2634,9 @@
 				ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n", 
 					c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), vac1.sin_addr), ntohs(vac1.sin_port), oldcodec1);
 			}
-			if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE))) 
+                        memcpy(&codecs1, &c1->nativeformats, sizeof(codecs1));
+                        ast_codec_pref_append_missing2(&codecs1, ast_compatible_audio_formats(codecs1.audio_bits));
+			if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, &codecs1, ast_test_flag(p1, FLAG_NAT_ACTIVE))) 
 				ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
 			memcpy(&ac1, &t1, sizeof(ac1));
 			memcpy(&vac1, &vt1, sizeof(vac1));
@@ -2651,7 +2649,9 @@
 				ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n", 
 					c0->name, ast_inet_ntoa(iabuf, sizeof(iabuf), ac0.sin_addr), ntohs(ac0.sin_port), oldcodec0);
 			}
-			if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
+                        memcpy(&codecs0, &c0->nativeformats, sizeof(codecs0));
+                        ast_codec_pref_append_missing2(&codecs0, ast_compatible_audio_formats(codecs0.audio_bits));
+			if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, &codecs0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
 				ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
 			memcpy(&ac0, &t0, sizeof(ac0));
 			memcpy(&vac0, &vt0, sizeof(vac0));
Index: translate.c
===================================================================
--- translate.c	(revision 34061)
+++ translate.c	(working copy)
@@ -241,6 +241,23 @@
 
 /* end of callback wrappers and helpers */
 
+void ast_translator_free_translations(struct ast_channel *chan)
+{
+	int x, y;
+	for (x = 0; x < MAX_FORMAT; ++x) {
+		for (y = 0; y < MAX_FORMAT; ++y) {
+			if (chan->readtrans_matrix[x][y]) {
+				ast_translator_free_path(chan->readtrans_matrix[x][y]);
+				chan->readtrans_matrix[x][y] = NULL;
+			}
+			if (chan->writetrans_matrix[x][y]) {
+				ast_translator_free_path(chan->writetrans_matrix[x][y]);
+				chan->writetrans_matrix[x][y] = NULL;
+			}
+		}
+	}
+}
+
 void ast_translator_free_path(struct ast_trans_pvt *p)
 {
 	struct ast_trans_pvt *pn = p;
@@ -284,6 +301,66 @@
 	return head;
 }
 
+struct ast_frame *ast_translate_read(struct ast_channel *chan, struct ast_frame *f, int consume)
+{
+	int dest_codec;
+	int dest_codec_idx;
+	int src_codec_idx;
+	struct ast_trans_pvt *trans;
+
+	chan->lastreadformat = f->subclass;
+	/* If the user perspective is this codec then do not translate */
+	if (chan->readformat & f->subclass) {
+		return f;
+	}
+	/* Otherwise translate into the user perspective codec */
+	dest_codec = chan->readformat;
+	dest_codec_idx = powerof(dest_codec);
+	src_codec_idx = powerof(f->subclass);
+	ast_mutex_lock(&chan->lock);
+	trans = chan->readtrans_matrix[src_codec_idx][dest_codec_idx];
+	if (NULL == trans) {
+		trans = ast_translator_build_path(dest_codec, f->subclass);
+		chan->readtrans_matrix[src_codec_idx][dest_codec_idx] = trans;
+	}
+	ast_mutex_unlock(&chan->lock);
+	if (trans)
+		f = ast_translate(trans, f, consume);
+	return f;
+}
+
+struct ast_frame *ast_translate_write(struct ast_channel *chan, struct ast_frame *f, int consume)
+{
+	int dest_codec;
+	int dest_codec_idx;
+	int src_codec_idx;
+	struct ast_trans_pvt *trans;
+	/* If channel supports this codec then do not translate */
+	if ((chan->nativeformats.audio_bits & f->subclass) &&
+	    ((option_translation_algorithm == AST_TRANS_ALG_LOOSE) ||
+	     (f->subclass & chan->lastreadformat)))
+	{
+		return f;
+	}
+	/*
+	 * Use the codec that the UA is using currently
+	 * (faxing does not work without this for example)
+	 */
+	dest_codec = chan->lastreadformat;
+	dest_codec_idx = powerof(dest_codec);
+	src_codec_idx = powerof(f->subclass);
+	ast_mutex_lock(&chan->lock);
+	trans = chan->writetrans_matrix[src_codec_idx][dest_codec_idx];
+	if (NULL == trans) {
+		trans = ast_translator_build_path(dest_codec, f->subclass);
+		chan->writetrans_matrix[src_codec_idx][dest_codec_idx] = trans;
+	}
+	ast_mutex_unlock(&chan->lock);
+	if (trans)
+		f = ast_translate(trans, f, consume);
+	return f;
+}
+
 /*! \brief do the actual translation */
 struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume)
 {
@@ -686,4 +763,26 @@
 		return -1;
 	else
 		return tr_matrix[src][dest].multistep + 1;
+}
+
+int ast_compatible_audio_formats(int formats)
+{
+	int retval = formats;
+	int x, y;
+
+	for (x = 0; x < MAX_FORMAT; ++x)
+	{
+		if ((1 << x) & formats)
+		{
+			for (y = 0; y < MAX_FORMAT; ++y)
+			{
+				if (tr_matrix[x][y].step)
+				{
+					retval |= (1 << y);
+				}
+			}
+		}
+	}
+	return retval;
+
 }
