[asterisk-commits] mmichelson: branch group/rls r420366 - in /team/group/rls: ./ channels/ chann...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Aug 7 14:01:24 CDT 2014


Author: mmichelson
Date: Thu Aug  7 14:01:20 2014
New Revision: 420366

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=420366
Log:
Get this branch ready to merge.


Modified:
    team/group/rls/   (props changed)
    team/group/rls/channels/chan_iax2.c
    team/group/rls/channels/iax2/codec_pref.c
    team/group/rls/channels/iax2/format_compatibility.c
    team/group/rls/channels/iax2/include/codec_pref.h
    team/group/rls/channels/iax2/include/format_compatibility.h
    team/group/rls/include/asterisk/format_compatibility.h
    team/group/rls/main/format_compatibility.c

Propchange: team/group/rls/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Thu Aug  7 14:01:20 2014
@@ -1,1 +1,1 @@
-/trunk:1-420358
+/trunk:1-420365

Modified: team/group/rls/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/team/group/rls/channels/chan_iax2.c?view=diff&rev=420366&r1=420365&r2=420366
==============================================================================
--- team/group/rls/channels/chan_iax2.c (original)
+++ team/group/rls/channels/chan_iax2.c Thu Aug  7 14:01:20 2014
@@ -285,7 +285,7 @@
 /* Sample over last 100 units to determine historic jitter */
 #define GAMMA (0.01)
 
-static struct iax2_codec_pref prefs;
+static struct iax2_codec_pref prefs_global;
 
 static const char tdesc[] = "Inter Asterisk eXchange Driver (Ver 2)";
 
@@ -353,22 +353,22 @@
 #define IAX_CAPABILITY_FULLBANDWIDTH	0xFFFF
 /* T1, maybe ISDN */
 #define IAX_CAPABILITY_MEDBANDWIDTH (IAX_CAPABILITY_FULLBANDWIDTH & \
-                     ~ast_format_compatibility_format2bitfield(ast_format_slin) &      \
-                     ~ast_format_compatibility_format2bitfield(ast_format_slin16) &    \
-                     ~ast_format_compatibility_format2bitfield(ast_format_siren7) &       \
-                     ~ast_format_compatibility_format2bitfield(ast_format_siren14) &      \
-                     ~ast_format_compatibility_format2bitfield(ast_format_g719) &         \
-                     ~ast_format_compatibility_format2bitfield(ast_format_ulaw) &         \
-                     ~ast_format_compatibility_format2bitfield(ast_format_alaw) &         \
-                     ~ast_format_compatibility_format2bitfield(ast_format_g722))
+                     ~AST_FORMAT_SLIN &      \
+                     ~AST_FORMAT_SLIN16 &    \
+                     ~AST_FORMAT_SIREN7 &       \
+                     ~AST_FORMAT_SIREN14 &      \
+                     ~AST_FORMAT_G719 &         \
+                     ~AST_FORMAT_ULAW &         \
+                     ~AST_FORMAT_ALAW &         \
+                     ~AST_FORMAT_G722)
 /* A modem */
 #define IAX_CAPABILITY_LOWBANDWIDTH (IAX_CAPABILITY_MEDBANDWIDTH & \
-                     ~ast_format_compatibility_format2bitfield(ast_format_g726) &         \
-                     ~ast_format_compatibility_format2bitfield(ast_format_g726_aal2) &    \
-                     ~ast_format_compatibility_format2bitfield(ast_format_adpcm))
+                     ~AST_FORMAT_G726 &         \
+                     ~AST_FORMAT_G726_AAL2 &    \
+                     ~AST_FORMAT_ADPCM)
 
 #define IAX_CAPABILITY_LOWFREE      (IAX_CAPABILITY_LOWBANDWIDTH & \
-                     ~ast_format_compatibility_format2bitfield(ast_format_g723))
+                     ~AST_FORMAT_G723)
 
 
 #define DEFAULT_MAXMS		2000		/* Must be faster than 2 seconds by default */
@@ -1820,16 +1820,20 @@
 	int x;
 	struct ast_format *found_format = NULL;
 
-	for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) {
+	for (x = 0; x < ARRAY_LEN(pref->order); ++x) {
 		struct ast_format *pref_format;
-		uint64_t pref_as_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[x]);
-
-		if (!pref_as_bitfield) {
+		uint64_t pref_bitfield;
+
+		pref_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[x]);
+		if (!pref_bitfield) {
 			break;
 		}
 
-		pref_format = ast_format_compatibility_bitfield2format(pref_as_bitfield);
-
+		pref_format = ast_format_compatibility_bitfield2format(pref_bitfield);
+		if (!pref_format) {
+			/* The bitfield is not associated with any format. */
+			continue;
+		}
 		found_format = ast_format_cap_get_compatible_format(cap, pref_format);
 		if (found_format) {
 			break;
@@ -1867,61 +1871,6 @@
 	return format;
 }
 
-static iax2_format iax2_best_codec(iax2_format formats)
-{
-	/* This just our opinion, expressed in code.  We are asked to choose
-	   the best codec to use, given no information */
-	static const iax2_format prefs[] =
-	{
-		/*! Okay, ulaw is used by all telephony equipment, so start with it */
-		AST_FORMAT_ULAW,
-		/*! Unless of course, you're a silly European, so then prefer ALAW */
-		AST_FORMAT_ALAW,
-		AST_FORMAT_G719,
-		AST_FORMAT_SIREN14,
-		AST_FORMAT_SIREN7,
-		AST_FORMAT_TESTLAW,
-		/*! G.722 is better then all below, but not as common as the above... so give ulaw and alaw priority */
-		AST_FORMAT_G722,
-		/*! Okay, well, signed linear is easy to translate into other stuff */
-		AST_FORMAT_SLIN16,
-		AST_FORMAT_SLIN,
-		/*! G.726 is standard ADPCM, in RFC3551 packing order */
-		AST_FORMAT_G726,
-		/*! G.726 is standard ADPCM, in AAL2 packing order */
-		AST_FORMAT_G726_AAL2,
-		/*! ADPCM has great sound quality and is still pretty easy to translate */
-		AST_FORMAT_ADPCM,
-		/*! Okay, we're down to vocoders now, so pick GSM because it's small and easier to
-		    translate and sounds pretty good */
-		AST_FORMAT_GSM,
-		/*! iLBC is not too bad */
-		AST_FORMAT_ILBC,
-		/*! Speex is free, but computationally more expensive than GSM */
-		AST_FORMAT_SPEEX16,
-		AST_FORMAT_SPEEX,
-		/*! Opus */
-		AST_FORMAT_OPUS,
-		/*! Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough
-		    to use it */
-		AST_FORMAT_LPC10,
-		/*! G.729a is faster than 723 and slightly less expensive */
-		AST_FORMAT_G729,
-		/*! Down to G.723.1 which is proprietary but at least designed for voice */
-		AST_FORMAT_G723,
-	};
-	int x;
-
-	/* Find the first preferred codec in the format given */
-	for (x = 0; x < ARRAY_LEN(prefs); x++) {
-		if (formats & prefs[x]) {
-			return prefs[x];
-		}
-	}
-
-	return 0;
-}
-
 const char *iax2_getformatname(iax2_format format)
 {
 	struct ast_format *tmpfmt;
@@ -1951,33 +1900,24 @@
 static int iax2_parse_allow_disallow(struct iax2_codec_pref *pref, iax2_format *formats, const char *list, int allowing)
 {
 	int res, i;
-	struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-
-	if (!cap) {
+	struct ast_format_cap *cap;
+
+	/* We want to add the formats to the cap in the preferred order */
+	cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	if (!cap || iax2_codec_pref_to_cap(pref, cap)) {
+		ao2_cleanup(cap);
 		return 1;
 	}
 
-	/* We want to add the formats to the cap in the preferred order */
-	for (i = 0; i < IAX2_CODEC_PREF_SIZE; i++) {
-		uint64_t pref_as_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[i]);
-
-		if (!pref_as_bitfield) {
-			break;
-		}
-
-		if (iax2_format_compatibility_bitfield2cap(pref_as_bitfield, cap)) {
-			ao2_ref(cap, -1);
-			return 1;
-		}
-	}
-
 	res = ast_format_cap_update_by_allow_disallow(cap, list, allowing);
+
+	/* Adjust formats bitfield and pref list to match. */
 	*formats = iax2_format_compatibility_cap2bitfield(cap);
-
 	iax2_codec_pref_remove_missing(pref, *formats);
 
 	for (i = 0; i < ast_format_cap_count(cap); i++) {
 		struct ast_format *fmt = ast_format_cap_get_format(cap, i);
+
 		iax2_codec_pref_append(pref, fmt, ast_format_cap_get_format_framing(cap, fmt));
 		ao2_ref(fmt, -1);
 	}
@@ -2283,7 +2223,7 @@
 		return NULL;
 	}
 
-	tmp->prefs = prefs;
+	tmp->prefs = prefs_global;
 	tmp->pingid = -1;
 	tmp->lagid = -1;
 	tmp->autoid = -1;
@@ -3844,7 +3784,7 @@
 	char status[30];
 	char cbuf[256];
 	struct iax2_peer *peer;
-	struct ast_str *codec_buf = ast_str_alloca(64);
+	struct ast_str *codec_buf = ast_str_alloca(256);
 	struct ast_str *encmethods = ast_str_alloca(256);
 	int load_realtime = 0;
 
@@ -3895,17 +3835,15 @@
 		ast_cli(a->fd, "  Addr->IP     : %s Port %s\n",  str_addr ? str_addr : "(Unspecified)", str_port);
 		ast_cli(a->fd, "  Defaddr->IP  : %s Port %s\n", str_defaddr, str_defport);
 		ast_cli(a->fd, "  Username     : %s\n", peer->username);
-		ast_cli(a->fd, "  Codecs       : ");
-		ast_cli(a->fd, "%s\n", iax2_getformatname_multiple(peer->capability, &codec_buf));
-
-		ast_cli(a->fd, "  Codec Order  : ");
-		if (iax2_codec_pref_string(&peer->prefs, cbuf, sizeof(cbuf)) != -1) {
-			ast_cli(a->fd, "%s\n", cbuf);
-		}
-
-		ast_cli(a->fd, "  Status       : ");
+		ast_cli(a->fd, "  Codecs       : %s\n", iax2_getformatname_multiple(peer->capability, &codec_buf));
+
+		if (iax2_codec_pref_string(&peer->prefs, cbuf, sizeof(cbuf)) < 0) {
+			strcpy(cbuf, "Error"); /* Safe */
+		}
+		ast_cli(a->fd, "  Codec Order  : %s\n", cbuf);
+
 		peer_status(peer, status, sizeof(status));
-		ast_cli(a->fd, "%s\n",status);
+		ast_cli(a->fd, "  Status       : %s\n", status);
 		ast_cli(a->fd, "  Qualify      : every %dms when OK, every %dms when UNREACHABLE (sample smoothing %s)\n", peer->pokefreqok, peer->pokefreqnotok, peer->smoothing ? "On" : "Off");
 		ast_cli(a->fd, "\n");
 		peer_unref(peer);
@@ -4654,6 +4592,7 @@
 struct create_addr_info {
 	iax2_format capability;
 	uint64_t flags;
+	struct iax2_codec_pref prefs;
 	int maxtime;
 	int encmethods;
 	int found;
@@ -4663,7 +4602,6 @@
 	char secret[80];
 	char outkey[80];
 	char timezone[80];
-	char prefs[32];
 	char cid_num[80];
 	char cid_name[80];
 	char context[AST_MAX_CONTEXT];
@@ -4676,7 +4614,6 @@
 {
 	struct iax2_peer *peer;
 	int res = -1;
-	struct iax2_codec_pref ourprefs;
 
 	ast_clear_flag64(cai, IAX_SENDANI | IAX_TRUNK);
 	cai->sockfd = defaultsockfd;
@@ -4697,20 +4634,24 @@
 		}
 
 		ast_sockaddr_copy(addr, &peer_addr);
-		/* use global iax prefs for unknown peer/user */
-		/* But move the calling channel's native codec to the top of the preference list */
-		memcpy(&ourprefs, &prefs, sizeof(ourprefs));
+		/*
+		 * Use The global iax prefs for unknown peer/user.
+		 * However, move the calling channel's native codec to
+		 * the top of the preference list.
+		 */
+		cai->prefs = prefs_global;
 		if (c) {
 			int i;
 
 			for (i = 0; i < ast_format_cap_count(ast_channel_nativeformats(c)); i++) {
 				struct ast_format *format = ast_format_cap_get_format(
 					ast_channel_nativeformats(c), i);
-				iax2_codec_pref_prepend(&ourprefs, format, ast_format_cap_get_format_framing(ast_channel_nativeformats(c), format), 1);
+				iax2_codec_pref_prepend(&cai->prefs, format,
+					ast_format_cap_get_format_framing(ast_channel_nativeformats(c), format),
+					1);
 				ao2_ref(format, -1);
 			}
 		}
-		iax2_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1);
 		return 0;
 	}
 
@@ -4731,7 +4672,7 @@
 	cai->encmethods = peer->encmethods;
 	cai->sockfd = peer->sockfd;
 	cai->adsi = peer->adsi;
-	memcpy(&ourprefs, &peer->prefs, sizeof(ourprefs));
+	cai->prefs = peer->prefs;
 	/* Move the calling channel's native codec to the top of the preference list */
 	if (c) {
 		int i;
@@ -4739,11 +4680,12 @@
 		for (i = 0; i < ast_format_cap_count(ast_channel_nativeformats(c)); i++) {
 			struct ast_format *tmpfmt = ast_format_cap_get_format(
 				ast_channel_nativeformats(c), i);
-			iax2_codec_pref_prepend(&ourprefs, tmpfmt, ast_format_cap_get_format_framing(ast_channel_nativeformats(c), tmpfmt), 1);
+			iax2_codec_pref_prepend(&cai->prefs, tmpfmt,
+				ast_format_cap_get_format_framing(ast_channel_nativeformats(c), tmpfmt),
+				1);
 			ao2_ref(tmpfmt, -1);
 		}
 	}
-	iax2_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1);
 	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));
@@ -5150,6 +5092,7 @@
 	unsigned char osp_block_index;
 	unsigned int osp_block_length;
 	unsigned char osp_buffer[256];
+	char encoded_prefs[32];
 	iax2_format iax2_tmpfmt;
 
 	if ((ast_channel_state(c) != AST_STATE_DOWN) && (ast_channel_state(c) != AST_STATE_RESERVED)) {
@@ -5218,7 +5161,8 @@
 	}
 
 	/* WARNING: this breaks down at 190 bits! */
-	iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, cai.prefs);
+	iax2_codec_pref_convert(&cai.prefs, encoded_prefs, sizeof(encoded_prefs), 1);
+	iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, encoded_prefs);
 
 	if (l) {
 		iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l);
@@ -5877,7 +5821,9 @@
 }
 
 /*! \brief  Create new call, interface with the PBX core */
-static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capability, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, unsigned int cachable)
+static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capability,
+	struct iax2_codec_pref *prefs, const struct ast_assigned_ids *assignedids,
+	const struct ast_channel *requestor, unsigned int cachable)
 {
 	struct ast_channel *tmp = NULL;
 	struct chan_iax2_pvt *i;
@@ -5893,8 +5839,20 @@
 		return NULL;
 	}
 
+	if (!capability) {
+		ast_log(LOG_WARNING, "No formats specified for call to: IAX2/%s-%d\n",
+			i->host, i->callno);
+		return NULL;
+	}
 	native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
 	if (!native) {
+		return NULL;
+	}
+	if (iax2_codec_pref_best_bitfield2cap(capability, prefs, native)
+		|| !ast_format_cap_count(native)) {
+		ast_log(LOG_WARNING, "No requested formats available for call to: IAX2/%s-%d\n",
+			i->host, i->callno);
+		ao2_ref(native, -1);
 		return NULL;
 	}
 
@@ -5910,13 +5868,17 @@
 	if (!ast_strlen_zero(peer_name)) {
 		peer = find_peer(peer_name, 1);
 		if (peer && peer->endpoint) {
-			tmp = ast_channel_alloc_with_endpoint(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, assignedids, requestor, i->amaflags, peer->endpoint, "IAX2/%s-%d", i->host, i->callno);
+			tmp = ast_channel_alloc_with_endpoint(1, state, i->cid_num, i->cid_name,
+				i->accountcode, i->exten, i->context, assignedids, requestor,
+				i->amaflags, peer->endpoint, "IAX2/%s-%d", i->host, i->callno);
 		}
 		ao2_cleanup(peer);
 	}
 
 	if (!tmp) {
-		tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, assignedids, requestor, i->amaflags, "IAX2/%s-%d", i->host, i->callno);
+		tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode,
+			i->exten, i->context, assignedids, requestor, i->amaflags, "IAX2/%s-%d",
+			i->host, i->callno);
 	}
 
 	ast_mutex_lock(&iaxsl[callno]);
@@ -5945,9 +5907,8 @@
 	ast_channel_tech_set(tmp, &iax2_tech);
 
 	/* We can support any format by default, until we get restricted */
-	iax2_format_compatibility_bitfield2cap(capability, native);
 	ast_channel_nativeformats_set(tmp, native);
-	tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(tmp), 0);
+	tmpfmt = ast_format_cap_get_format(native, 0);
 
 	ast_channel_set_readformat(tmp, tmpfmt);
 	ast_channel_set_rawreadformat(tmp, tmpfmt);
@@ -6046,8 +6007,10 @@
 	if (state != AST_STATE_DOWN) {
 		if (ast_pbx_start(tmp)) {
 			ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
+			/* unlock and relock iaxsl[callno] to preserve locking order */
+			ast_mutex_unlock(&iaxsl[callno]);
 			ast_hangup(tmp);
-			i->owner = NULL;
+			ast_mutex_lock(&iaxsl[callno]);
 			return NULL;
 		}
 	}
@@ -7907,8 +7870,10 @@
 	/* Use provided preferences until told otherwise for actual preferences */
 	if (ies->codec_prefs) {
 		iax2_codec_pref_convert(&iaxs[callno]->rprefs, ies->codec_prefs, 32, 0);
-		iax2_codec_pref_convert(&iaxs[callno]->prefs, ies->codec_prefs, 32, 0);
-	}
+	} else {
+		memset(&iaxs[callno]->rprefs, 0, sizeof(iaxs[callno]->rprefs));
+	}
+	iaxs[callno]->prefs = iaxs[callno]->rprefs;
 
 	if (!gotcapability) {
 		iaxs[callno]->peercapability = iaxs[callno]->peerformat;
@@ -10556,8 +10521,9 @@
 		    (f.frametype == AST_FRAME_IAX)) {
 			if (ast_test_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
 				ast_clear_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART);
-				if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL, NULL,
-						  ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED))) {
+				if (!ast_iax2_new(fr->callno, AST_STATE_RING,
+					iaxs[fr->callno]->chosenformat, &iaxs[fr->callno]->rprefs, NULL, NULL,
+					ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED))) {
 					ast_variables_destroy(ies.vars);
 					ast_mutex_unlock(&iaxsl[fr->callno]);
 					return 1;
@@ -10893,7 +10859,7 @@
 									if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
 										using_prefs = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
 										memset(&pref, 0, sizeof(pref));
-										format = iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+										format = iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
 										strcpy(caller_pref_buf,"disabled");
 										strcpy(host_pref_buf,"disabled");
 									} else {
@@ -10909,7 +10875,7 @@
 											}
 											format = iax2_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
 										} else /* if no codec_prefs IE do it the old way */
-											format = iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+											format = iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
 									}
 								}
 
@@ -11111,7 +11077,9 @@
 						struct ast_str *cap_buf = ast_str_alloca(64);
 
 						/* Switch us to use a compatible format */
-						iax2_format_compatibility_bitfield2cap(iaxs[fr->callno]->peerformat, native);
+						iax2_codec_pref_best_bitfield2cap(
+							iaxs[fr->callno]->peerformat, &iaxs[fr->callno]->rprefs,
+							native);
 						ast_channel_nativeformats_set(iaxs[fr->callno]->owner, native);
 						ast_verb(3, "Format for call is %s\n", ast_format_cap_get_names(ast_channel_nativeformats(iaxs[fr->callno]->owner), &cap_buf));
 
@@ -11351,8 +11319,9 @@
 								if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
 									using_prefs = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
 									memset(&pref, 0, sizeof(pref));
-									format = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ?
-										iaxs[fr->callno]->peerformat : iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+									format = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)
+										? iaxs[fr->callno]->peerformat
+										: iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
 									strcpy(caller_pref_buf,"disabled");
 									strcpy(host_pref_buf,"disabled");
 								} else {
@@ -11368,7 +11337,7 @@
 										}
 										format = iax2_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
 									} else /* if no codec_prefs IE do it the old way */
-										format = iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+										format = iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
 								}
 							}
 							if (!format) {
@@ -11429,9 +11398,11 @@
 											using_prefs);
 
 							ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
-							if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format, NULL, NULL, 1)))
+							c = ast_iax2_new(fr->callno, AST_STATE_RING, format,
+								&iaxs[fr->callno]->rprefs, NULL, NULL, 1);
+							if (!c) {
 								iax2_destroy(fr->callno);
-							else if (ies.vars) {
+							} else if (ies.vars) {
 								struct ast_datastore *variablestore;
 								struct ast_variable *var, *prev = NULL;
 								AST_LIST_HEAD(, ast_var_t) *varlist;
@@ -11503,9 +11474,12 @@
 								iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &cap_buf));
 						ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
 						send_command(iaxs[fr->callno], AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, 0, NULL, 0, -1);
-						if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, NULL, NULL, 1)))
+						c = ast_iax2_new(fr->callno, AST_STATE_RING,
+							iaxs[fr->callno]->peerformat, &iaxs[fr->callno]->rprefs,
+							NULL, NULL, 1);
+						if (!c) {
 							iax2_destroy(fr->callno);
-						else if (ies.vars) {
+						} else if (ies.vars) {
 							struct ast_datastore *variablestore;
 							struct ast_variable *var, *prev = NULL;
 							AST_LIST_HEAD(, ast_var_t) *varlist;
@@ -12528,7 +12502,8 @@
 		ast_string_field_set(iaxs[callno], host, pds.peer);
 	}
 
-	c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, assignedids, requestor, cai.found);
+	c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, &cai.prefs, assignedids,
+		requestor, cai.found);
 
 	ast_mutex_unlock(&iaxsl[callno]);
 
@@ -12840,7 +12815,7 @@
 				ast_sockaddr_set_port(&peer->addr, IAX_DEFAULT_PORTNO);
 				peer->expiry = min_reg_expire;
 			}
-			peer->prefs = prefs;
+			peer->prefs = prefs_global;
 			peer->capability = iax2_capability;
 			peer->smoothing = 0;
 			peer->pokefreqok = DEFAULT_FREQ_OK;
@@ -13157,7 +13132,7 @@
 			}
 			user->maxauthreq = maxauthreq;
 			user->curauthreq = oldcurauthreq;
-			user->prefs = prefs;
+			user->prefs = prefs_global;
 			user->capability = iax2_capability;
 			user->encmethods = iax2_encryption;
 			user->adsi = adsi;
@@ -13470,7 +13445,7 @@
 static int set_config(const char *config_file, int reload, int forced)
 {
 	struct ast_config *cfg, *ucfg;
-	iax2_format capability = iax2_capability;
+	iax2_format capability;
 	struct ast_variable *v;
 	char *cat;
 	const char *utype;
@@ -13485,9 +13460,7 @@
 	struct ast_netsock *ns;
 	struct ast_flags config_flags = { (reload && !forced) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
 	struct ast_sockaddr bindaddr;
-#if 0
-	static unsigned short int last_port=0;
-#endif
+	struct iax2_codec_pref prefs_new;
 
 	cfg = ast_config_load(config_file, config_flags);
 
@@ -13528,8 +13501,8 @@
 
 	ast_sockaddr_parse(&bindaddr, "0.0.0.0:0", 0);
 
-	/* Reset global codec prefs */
-	memset(&prefs, 0 , sizeof(struct iax2_codec_pref));
+	/* Setup new codec prefs */
+	capability = iax2_codec_pref_from_bitfield(&prefs_new, IAX_CAPABILITY_FULLBANDWIDTH);
 
 	/* Reset Global Flags */
 	memset(&globalflags, 0, sizeof(globalflags));
@@ -13754,17 +13727,21 @@
 			}
 		} else if (!strcasecmp(v->name, "bandwidth")) {
 			if (!strcasecmp(v->value, "low")) {
-				capability = IAX_CAPABILITY_LOWBANDWIDTH;
+				capability = iax2_codec_pref_from_bitfield(&prefs_new,
+					IAX_CAPABILITY_LOWBANDWIDTH);
 			} else if (!strcasecmp(v->value, "medium")) {
-				capability = IAX_CAPABILITY_MEDBANDWIDTH;
+				capability = iax2_codec_pref_from_bitfield(&prefs_new,
+					IAX_CAPABILITY_MEDBANDWIDTH);
 			} else if (!strcasecmp(v->value, "high")) {
-				capability = IAX_CAPABILITY_FULLBANDWIDTH;
-			} else
+				capability = iax2_codec_pref_from_bitfield(&prefs_new,
+					IAX_CAPABILITY_FULLBANDWIDTH);
+			} else {
 				ast_log(LOG_WARNING, "bandwidth must be either low, medium, or high\n");
+			}
 		} else if (!strcasecmp(v->name, "allow")) {
-			iax2_parse_allow_disallow(&prefs, &capability, v->value, 1);
+			iax2_parse_allow_disallow(&prefs_new, &capability, v->value, 1);
 		} else if (!strcasecmp(v->name, "disallow")) {
-			iax2_parse_allow_disallow(&prefs, &capability, v->value, 0);
+			iax2_parse_allow_disallow(&prefs_new, &capability, v->value, 0);
 		} else if (!strcasecmp(v->name, "register")) {
 			iax2_register(v->value, v->lineno);
 		} else if (!strcasecmp(v->name, "iaxcompat")) {
@@ -13882,6 +13859,7 @@
 			min_reg_expire, max_reg_expire, max_reg_expire);
 		min_reg_expire = max_reg_expire;
 	}
+	prefs_global = prefs_new;
 	iax2_capability = capability;
 
 	if (ucfg) {
@@ -14408,7 +14386,7 @@
 	} else  if (!strcasecmp(colname, "callerid_num")) {
 		ast_copy_string(buf, peer->cid_num, len);
 	} else  if (!strcasecmp(colname, "codecs")) {
-		struct ast_str *codec_buf;
+		struct ast_str *codec_buf = ast_str_alloca(256);
 
 		iax2_getformatname_multiple(peer->capability, &codec_buf);
 		ast_copy_string(buf, ast_str_buffer(codec_buf), len);

Modified: team/group/rls/channels/iax2/codec_pref.c
URL: http://svnview.digium.com/svn/asterisk/team/group/rls/channels/iax2/codec_pref.c?view=diff&rev=420366&r1=420365&r2=420366
==============================================================================
--- team/group/rls/channels/iax2/codec_pref.c (original)
+++ team/group/rls/channels/iax2/codec_pref.c Thu Aug  7 14:01:20 2014
@@ -38,6 +38,7 @@
 #include "asterisk/format_compatibility.h"
 #include "asterisk/format_cache.h"
 #include "asterisk/format_cap.h"
+#include "asterisk/utils.h"
 
 #include "include/codec_pref.h"
 #include "include/format_compatibility.h"
@@ -48,7 +49,8 @@
 	int x;
 
 	if (right) {
-		for (x = 0; x < IAX2_CODEC_PREF_SIZE && x < size; x++) {
+		--size;/* Save room for the nul string terminator. */
+		for (x = 0; x < ARRAY_LEN(pref->order) && x < size; ++x) {
 			if (!pref->order[x]) {
 				break;
 			}
@@ -58,24 +60,29 @@
 
 		buf[x] = '\0';
 	} else {
-		for (x = 0; x < IAX2_CODEC_PREF_SIZE && x < size; x++) {
+		for (x = 0; x < ARRAY_LEN(pref->order) && x < size; ++x) {
 			if (buf[x] == '\0') {
 				break;
 			}
 
 			pref->order[x] = buf[x] - differential;
-		}
-
-		if (x < size) {
+			pref->framing[x] = 0;
+		}
+
+		if (x < ARRAY_LEN(pref->order)) {
 			pref->order[x] = 0;
+			pref->framing[x] = 0;
 		}
 	}
 }
 
 struct ast_format *iax2_codec_pref_index(struct iax2_codec_pref *pref, int idx, struct ast_format **result)
 {
-	if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->order[idx]) {
-		*result = ast_format_compatibility_bitfield2format(pref->order[idx]);
+	if (0 <= idx && idx < ARRAY_LEN(pref->order) && pref->order[idx]) {
+		uint64_t pref_bitfield;
+
+		pref_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[idx]);
+		*result = ast_format_compatibility_bitfield2format(pref_bitfield);
 	} else {
 		*result = NULL;
 	}
@@ -83,28 +90,99 @@
 	return *result;
 }
 
-void iax2_codec_pref_to_cap(struct iax2_codec_pref *pref, struct ast_format_cap *cap)
+int iax2_codec_pref_to_cap(struct iax2_codec_pref *pref, struct ast_format_cap *cap)
 {
 	int idx;
 
-	for (idx = 0; idx < sizeof(pref->order); idx++) {
-		if (!pref->order[idx]) {
-			break;
-		}
-		ast_format_cap_append(cap, ast_format_compatibility_bitfield2format(pref->order[idx]), pref->framing[idx]);
-	}
+	for (idx = 0; idx < ARRAY_LEN(pref->order); ++idx) {
+		uint64_t pref_bitfield;
+		struct ast_format *pref_format;
+
+		pref_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[idx]);
+		if (!pref_bitfield) {
+			break;
+		}
+
+		pref_format = ast_format_compatibility_bitfield2format(pref_bitfield);
+		if (pref_format && ast_format_cap_append(cap, pref_format, pref->framing[idx])) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+int iax2_codec_pref_best_bitfield2cap(uint64_t bitfield, struct iax2_codec_pref *prefs, struct ast_format_cap *cap)
+{
+	uint64_t best_bitfield;
+	struct ast_format *format;
+
+	/* Add any user preferred codecs first. */
+	if (prefs) {
+		int idx;
+
+		for (idx = 0; bitfield && idx < ARRAY_LEN(prefs->order); ++idx) {
+			best_bitfield = iax2_codec_pref_order_value_to_format_bitfield(prefs->order[idx]);
+			if (!best_bitfield) {
+				break;
+			}
+
+			if (best_bitfield & bitfield) {
+				format = ast_format_compatibility_bitfield2format(best_bitfield);
+				if (format && ast_format_cap_append(cap, format, prefs->framing[idx])) {
+					return -1;
+				}
+
+				/* Remove just added codec. */
+				bitfield &= ~best_bitfield;
+			}
+		}
+	}
+
+	/* Add the hard coded "best" codecs. */
+	while (bitfield) {
+		best_bitfield = iax2_format_compatibility_best(bitfield);
+		if (!best_bitfield) {
+			/* No more codecs considered best. */
+			break;
+		}
+
+		format = ast_format_compatibility_bitfield2format(best_bitfield);
+		/* The best_bitfield should always be convertible to a format. */
+		ast_assert(format != NULL);
+
+		if (ast_format_cap_append(cap, format, 0)) {
+			return -1;
+		}
+
+		/* Remove just added "best" codec to find the next "best". */
+		bitfield &= ~best_bitfield;
+	}
+
+	/* Add any remaining codecs. */
+	if (bitfield) {
+		int bit;
+
+		for (bit = 0; bit < 64; ++bit) {
+			uint64_t mask = (1ULL << bit);
+
+			if (mask & bitfield) {
+				format = ast_format_compatibility_bitfield2format(mask);
+				if (format && ast_format_cap_append(cap, format, 0)) {
+					return -1;
+				}
+			}
+		}
+	}
+
+	return 0;
 }
 
 int iax2_codec_pref_string(struct iax2_codec_pref *pref, char *buf, size_t size)
 {
 	int x;
-	struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	struct ast_format_cap *cap;
 	size_t total_len;
 	char *cur;
-
-	if (!cap) {
-		return -1;
-	}
 
 	/* This function is useless if you have less than a 6 character buffer.
 	 * '(...)' is six characters. */
@@ -112,20 +190,16 @@
 		return -1;
 	}
 
-	/* Convert the preferences into a format cap so that we can read the formst names */
-	for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) {
-		uint64_t bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[x]);
-		if (!bitfield) {
-			break;
-		}
-
-		iax2_format_compatibility_bitfield2cap(bitfield, cap);
+	/* Convert the preferences into a format cap so that we can read the format names */
+	cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+	if (!cap || iax2_codec_pref_to_cap(pref, cap)) {
+		strcpy(buf, "(...)"); /* Safe */
+		ao2_cleanup(cap);
+		return -1;
 	}
 
 	/* We know that at a minimum, 3 characters are used - (, ), and \0 */
 	total_len = size - 3;
-
-	memset(buf, 0, size);
 
 	/* This character has already been accounted for total_len purposes */
 	buf[0] = '(';
@@ -173,12 +247,20 @@
 
 static void codec_pref_remove_index(struct iax2_codec_pref *pref, int codec_pref_index)
 {
-	int x;
-
-	for (x = codec_pref_index; x < IAX2_CODEC_PREF_SIZE; x++) {
-		pref->order[x] = pref->order[x + 1];
-		pref->framing[x] = pref->framing[x + 1];
-		if (!pref->order[x]) {
+	int idx;
+
+	idx = codec_pref_index;
+	if (idx == ARRAY_LEN(pref->order) - 1) {
+		/* Remove from last array entry. */
+		pref->order[idx] = 0;
+		pref->framing[idx] = 0;
+		return;
+	}
+
+	for (; idx < ARRAY_LEN(pref->order); ++idx) {
+		pref->order[idx] = pref->order[idx + 1];
+		pref->framing[idx] = pref->framing[idx + 1];
+		if (!pref->order[idx]) {
 			return;
 		}
 	}
@@ -193,7 +275,7 @@
 		return;
 	}
 
-	for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) {
+	for (x = 0; x < ARRAY_LEN(pref->order); ++x) {
 		if (!pref->order[x]) {
 			break;
 		}
@@ -207,86 +289,181 @@
 
 void iax2_codec_pref_remove_missing(struct iax2_codec_pref *pref, uint64_t bitfield)
 {
+	int idx;
+
+	if (!pref->order[0]) {
+		return;
+	}
+
+	/*
+	 * Work from the end of the list so we always deal with
+	 * unmodified entries in case we have to remove a pref.
+	 */
+	for (idx = ARRAY_LEN(pref->order); idx--;) {
+		uint64_t pref_bitfield;
+
+		pref_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[idx]);
+		if (!pref_bitfield) {
+			continue;
+		}
+
+		/* If this format isn't in the bitfield, remove it from the prefs. */
+		if (!(pref_bitfield & bitfield)) {
+			codec_pref_remove_index(pref, idx);
+		}
+	}
+}
+
+/*!
+ * \brief Formats supported by IAX2.
+ *
+ * \note All AST_FORMAT_xxx compatibility bit defines must be
+ *  represented here.
+ *
+ * \note The order is important because the array index+1 values
+ * go out over the wire.
+ */
+static const uint64_t iax2_supported_formats[] = {
+	AST_FORMAT_G723,
+	AST_FORMAT_GSM,
+	AST_FORMAT_ULAW,
+	AST_FORMAT_ALAW,
+	AST_FORMAT_G726,
+	AST_FORMAT_ADPCM,
+	AST_FORMAT_SLIN,
+	AST_FORMAT_LPC10,
+	AST_FORMAT_G729,
+	AST_FORMAT_SPEEX,
+	AST_FORMAT_SPEEX16,
+	AST_FORMAT_ILBC,
+	AST_FORMAT_G726_AAL2,
+	AST_FORMAT_G722,
+	AST_FORMAT_SLIN16,
+	AST_FORMAT_JPEG,
+	AST_FORMAT_PNG,
+	AST_FORMAT_H261,
+	AST_FORMAT_H263,
+	AST_FORMAT_H263P,
+	AST_FORMAT_H264,
+	AST_FORMAT_MP4,
+	AST_FORMAT_T140_RED,
+	AST_FORMAT_T140,
+	AST_FORMAT_SIREN7,
+	AST_FORMAT_SIREN14,
+	AST_FORMAT_TESTLAW,
+	AST_FORMAT_G719,
+	0, /* Place holder */
+	0, /* Place holder */
+	0, /* Place holder */
+	0, /* Place holder */
+	0, /* Place holder */
+	0, /* Place holder */
+	0, /* Place holder */
+	0, /* Place holder */
+	AST_FORMAT_OPUS,
+	AST_FORMAT_VP8,
+	/* ONLY ADD TO THE END OF THIS LIST */
+	/* XXX Use up the place holder slots first. */
+};
+
+uint64_t iax2_codec_pref_order_value_to_format_bitfield(int order_value)
+{
+	if (order_value < 1 || ARRAY_LEN(iax2_supported_formats) < order_value) {
+		return 0;
+	}
+
+	return iax2_supported_formats[order_value - 1];
+}
+
+int iax2_codec_pref_format_bitfield_to_order_value(uint64_t bitfield)
+{
+	int idx;
+
+	if (bitfield) {
+		for (idx = 0; idx < ARRAY_LEN(iax2_supported_formats); ++idx) {
+			if (iax2_supported_formats[idx] == bitfield) {
+				return idx + 1;
+			}
+		}
+	}
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Append the bitfield format to the codec preference list.
+ * \since 13.0.0
+ *
+ * \param pref Codec preference list to append the given bitfield.
+ * \param bitfield Format bitfield to append.
+ * \param framing Framing size of the codec.
+ *
+ * \return Nothing
+ */
+static void iax2_codec_pref_append_bitfield(struct iax2_codec_pref *pref, uint64_t bitfield, unsigned int framing)
+{
+	int format_index;
 	int x;
 
-	if (!pref->order[0]) {
-		return;
-	}
-
-	for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) {
-		uint64_t format_as_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[x]);
-		if (!pref->order[x]) {
-			break;
-		}
-
-		/* If this format isn't in the bitfield, remove it from the prefs. */
-		if (!(format_as_bitfield & bitfield)) {
-			codec_pref_remove_index(pref, x);
-		}
-	}
-}
-
-uint64_t iax2_codec_pref_order_value_to_format_bitfield(uint64_t order_value)
-{
-	if (!order_value) {
-		return 0;
-	}
-
-	return 1 << (order_value - 1);
-}
-
-uint64_t iax2_codec_pref_format_bitfield_to_order_value(uint64_t bitfield)
-{
-	int format_index = 1;
-
-	if (!bitfield) {
-		return 0;
-	}
-
-	while (bitfield > 1) {
-		bitfield = bitfield >> 1;
-		format_index++;
-	}
-
-	return format_index;
-}
-
-/*! \brief Append codec to list */
-int iax2_codec_pref_append(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing)
-{
-	uint64_t bitfield = ast_format_compatibility_format2bitfield(format);
-	int format_index = iax2_codec_pref_format_bitfield_to_order_value(bitfield);
-	int x;
+	format_index = iax2_codec_pref_format_bitfield_to_order_value(bitfield);
+	if (!format_index) {
+		return;
+	}
 
 	codec_pref_remove(pref, format_index);
 
-	for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) {
+	for (x = 0; x < ARRAY_LEN(pref->order); ++x) {
 		if (!pref->order[x]) {
 			pref->order[x] = format_index;
 			pref->framing[x] = framing;
 			break;
 		}
 	}
-
-	return x;
-}
-
-/*! \brief Prepend codec to list */
+}
+
+void iax2_codec_pref_append(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing)
+{
+	uint64_t bitfield;
+
+	bitfield = ast_format_compatibility_format2bitfield(format);
+	if (!bitfield) {
+		return;
+	}
+
+	iax2_codec_pref_append_bitfield(pref, bitfield, framing);
+}
+
 void iax2_codec_pref_prepend(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing,
 	int only_if_existing)
 {
-	uint64_t bitfield = ast_format_compatibility_format2bitfield(format);
+	uint64_t bitfield;
+	int format_index;
 	int x;
 
+	bitfield = ast_format_compatibility_format2bitfield(format);
+	if (!bitfield) {
+		return;
+	}
+	format_index = iax2_codec_pref_format_bitfield_to_order_value(bitfield);
+	if (!format_index) {
+		return;
+	}
+
 	/* Now find any existing occurrence, or the end */
-	for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) {
-		if (!pref->order[x] || pref->order[x] == bitfield)
-			break;
-	}
-
-	/* If we failed to find any occurrence, set to the end */
-	if (x == IAX2_CODEC_PREF_SIZE) {
-		--x;
+	for (x = 0; x < ARRAY_LEN(pref->order); ++x) {
+		if (!pref->order[x] || pref->order[x] == format_index)
+			break;
+	}
+
+	/*
+	 * The array can never be full without format_index
+	 * also being in the array.
+	 */
+	ast_assert(x < ARRAY_LEN(pref->order));
+
+	/* If we failed to find any occurrence, set to the end for safety. */
+	if (ARRAY_LEN(pref->order) <= x) {
+		x = ARRAY_LEN(pref->order) - 1;
 	}
 
 	if (only_if_existing && !pref->order[x]) {
@@ -295,39 +472,63 @@
 
 	/* Move down to make space to insert - either all the way to the end,
 	   or as far as the existing location (which will be overwritten) */
-	for (; x > 0; x--) {
+	for (; x > 0; --x) {
 		pref->order[x] = pref->order[x - 1];
 		pref->framing[x] = pref->framing[x - 1];
 	}
 
 	/* And insert the new entry */
-	pref->order[0] = bitfield;
+	pref->order[0] = format_index;
 	pref->framing[0] = framing;
 }
 
-unsigned int iax2_codec_pref_getsize(struct iax2_codec_pref *pref, int idx)
-{
-	if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->order[idx]) {
-		return pref->framing[idx];
-	} else {
-		return 0;
-	}
-}
-
-int iax2_codec_pref_setsize(struct iax2_codec_pref *pref, struct ast_format *format, int framems)
-{
-	int idx;
-
-	for (idx = 0; idx < sizeof(pref->order); idx++) {
-		if (!pref->order[idx]) {
-			break;
-		} else if (ast_format_cmp(ast_format_compatibility_bitfield2format(pref->order[idx]),
-			format) != AST_FORMAT_CMP_EQUAL) {
-			continue;
-		}
-		pref->framing[idx] = framems;
-		return 0;
-	}
-
-	return -1;
-}
+uint64_t iax2_codec_pref_from_bitfield(struct iax2_codec_pref *pref, uint64_t bitfield)
+{
+	int bit;
+	uint64_t working_bitfield;
+	uint64_t best_bitfield;
+	struct ast_format *format;
+
+	/* Init the preference list. */
+	memset(pref, 0, sizeof(*pref));
+
+	working_bitfield = bitfield;
+
+	/* Add the "best" codecs first. */
+	while (working_bitfield) {
+		best_bitfield = iax2_format_compatibility_best(working_bitfield);
+		if (!best_bitfield) {
+			/* No more codecs considered best. */
+			break;
+		}
+
+		/* Remove current "best" codec to find the next "best". */
+		working_bitfield &= ~best_bitfield;
+
+		format = ast_format_compatibility_bitfield2format(best_bitfield);
+		/* The best_bitfield should always be convertible to a format. */
+		ast_assert(format != NULL);
+
+		iax2_codec_pref_append_bitfield(pref, best_bitfield, 0);
+	}
+
+	/* Add any remaining codecs. */
+	if (working_bitfield) {
+		for (bit = 0; bit < 64; ++bit) {
+			uint64_t mask = (1ULL << bit);
+
+			if (mask & working_bitfield) {
+				format = ast_format_compatibility_bitfield2format(mask);
+				if (!format) {
+					/* The bit is not associated with any format. */
+					bitfield &= ~mask;
+					continue;
+				}
+
+				iax2_codec_pref_append_bitfield(pref, mask, 0);
+			}
+		}
+	}
+
+	return bitfield;
+}

Modified: team/group/rls/channels/iax2/format_compatibility.c
URL: http://svnview.digium.com/svn/asterisk/team/group/rls/channels/iax2/format_compatibility.c?view=diff&rev=420366&r1=420365&r2=420366
==============================================================================
--- team/group/rls/channels/iax2/format_compatibility.c (original)
+++ team/group/rls/channels/iax2/format_compatibility.c Thu Aug  7 14:01:20 2014
@@ -38,6 +38,7 @@
 #include "asterisk/format_compatibility.h"
 #include "asterisk/format_cache.h"
 #include "asterisk/format_cap.h"
+#include "asterisk/utils.h"
 
 #include "include/format_compatibility.h"
 
@@ -59,15 +60,77 @@
 
 int iax2_format_compatibility_bitfield2cap(uint64_t bitfield, struct ast_format_cap *cap)
 {
-	int x;
+	int bit;
 
-	for (x = 0; x < 64; x++) {

[... 243 lines stripped ...]



More information about the asterisk-commits mailing list