[Asterisk-code-review] rtp engine.c: Initial split of payload types into rx and tx ... (asterisk[master])

Matt Jordan asteriskteam at digium.com
Fri Aug 21 08:39:12 CDT 2015


Matt Jordan has submitted this change and it was merged.

Change subject: rtp_engine.c: Initial split of payload types into rx and tx mappings.
......................................................................


rtp_engine.c: Initial split of payload types into rx and tx mappings.

There are numerous problems with the current implementation of the RTP
payload type mapping in Asterisk.  It uses only one mapping structure to
associate payload types to codecs.  The single mapping is overkill if all
of the payload type values are well known values.  Dynamic payload type
mappings do not work as well with the single mapping because RFC3264
allows each side of the link to negotiate different dynamic mappings for
what they want to receive.  Not only could you have the same codec mapped
for sending and receiving on different payload types you could wind up
with the same payload type mapped to different codecs for each direction.

1) An independent payload type mapping is needed for sending and
receiving.

2) The receive mapping needs to keep track of previous mappings because of
the slack to when negotiation happens and current packets in flight using
the old mapping arrive.

3) The transmit mapping only needs to keep track of the current negotiated
values since we are sending the packets and know when the switchover takes
place.

* Needed to create ast_rtp_codecs_payload_code_tx() and make some callers
use the new function because ast_rtp_codecs_payload_code() was used for
mappings in both directions.

* Needed to create ast_rtp_codecs_payloads_xover() for cases where we need
to pass preferred codec mappings to the peer channel for early media
bridging or when we need to prefer the offered mapping that RFC3264 says
we SHOULD use.

* ast_rtp_codecs_payloads_xover() and ast_rtp_codecs_payload_code_tx() are
the only new public functions created.  All the others were only used for
the tx or rx mapping direction so the function doxygen now reflects which
direction the function operates.

* chan_mgcp.c: Removed call to ast_rtp_codecs_payloads_clear() as doing
that makes no sense when processing an incoming SDP.  We would be wiping
out any mappings that we set for the possible outgoing SDP we sent
earlier.

ASTERISK-25166
Reported by: Kevin Harwell

ASTERISK-17410
Reported by: Boris Fox

Change-Id: Iaf6c227bca68cb7c414cf2fd4108a8ac98bd45ac
---
M channels/chan_mgcp.c
M channels/chan_unistim.c
M include/asterisk/rtp_engine.h
M main/rtp_engine.c
M res/res_rtp_asterisk.c
M res/res_rtp_multicast.c
6 files changed, 495 insertions(+), 118 deletions(-)

Approvals:
  Anonymous Coward #1000019: Verified
  Matt Jordan: Looks good to me, approved
  Joshua Colp: Looks good to me, but someone else must approve



diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index d9e182c..0210e8a 100644
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -2018,7 +2018,6 @@
 	ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
 	ast_debug(3, "Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
 	/* Scan through the RTP payload types specified in a "m=" line: */
-	ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp);
 	codecs = ast_strdupa(m + len);
 	while (!ast_strlen_zero(codecs)) {
 		if (sscanf(codecs, "%30d%n", &codec, &len) != 1) {
@@ -4487,7 +4486,8 @@
 	if (!(sub = ast_channel_tech_pvt(chan)) || !(sub->rtp))
 		return AST_RTP_GLUE_RESULT_FORBID;
 
-	*instance = sub->rtp ? ao2_ref(sub->rtp, +1), sub->rtp : NULL;
+	ao2_ref(sub->rtp, +1);
+	*instance = sub->rtp;
 
 	if (sub->parent->directmedia)
 		return AST_RTP_GLUE_RESULT_REMOTE;
diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c
index a3c0ffd..874f6b2 100644
--- a/channels/chan_unistim.c
+++ b/channels/chan_unistim.c
@@ -2709,7 +2709,8 @@
 	}
 
 	pte = sub->parent->parent->session;
-	codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, ast_channel_readformat(sub->owner), 0);
+	codec = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(sub->rtp),
+		1, ast_channel_readformat(sub->owner), 0);
 	if ((ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) ||
 		(ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_alaw) == AST_FORMAT_CMP_EQUAL)) {
 		if (unistimdebug) {
diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h
index d6a9be5..a52567a 100644
--- a/include/asterisk/rtp_engine.h
+++ b/include/asterisk/rtp_engine.h
@@ -251,6 +251,8 @@
 	int rtp_code;
 	/*! Actual payload number */
 	int payload;
+	/*! TRUE if this is the primary mapping to the format. */
+	unsigned int primary_mapping:1;
 };
 
 /* Common RTCP report types */
@@ -577,16 +579,18 @@
 
 /*! Structure that represents codec and packetization information */
 struct ast_rtp_codecs {
-	/*! Payloads present */
-	AST_VECTOR(, struct ast_rtp_payload_type *) payloads;
-	/*! The framing for this media session */
-	unsigned int framing;
 	/*! RW lock that protects elements in this structure */
 	ast_rwlock_t codecs_lock;
+	/*! Rx payload type mapping exceptions */
+	AST_VECTOR(, struct ast_rtp_payload_type *) payload_mapping_rx;
+	/*! Tx payload type mapping */
+	AST_VECTOR(, struct ast_rtp_payload_type *) payload_mapping_tx;
+	/*! The framing for this media session */
+	unsigned int framing;
 };
 
 #define AST_RTP_CODECS_NULL_INIT \
-    { .payloads = { 0, }, .framing = 0, .codecs_lock = AST_RWLOCK_INIT_VALUE, }
+    { .codecs_lock = AST_RWLOCK_INIT_VALUE, .payload_mapping_rx = { 0, }, .payload_mapping_tx = { 0, }, .framing = 0, }
 
 /*! Structure that represents the glue that binds an RTP instance to a channel */
 struct ast_rtp_glue {
@@ -1192,7 +1196,7 @@
 void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs);
 
 /*!
- * \brief Clear payload information from an RTP instance
+ * \brief Clear rx and tx payload mapping information from an RTP instance
  *
  * \param codecs The codecs structure that payloads will be cleared from
  * \param instance Optionally the instance that the codecs structure belongs to
@@ -1230,7 +1234,19 @@
 void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance);
 
 /*!
- * \brief Record payload information that was seen in an m= SDP line
+ * \brief Crossover copy the tx payload mapping of src to the rx payload mapping of dest.
+ * \since 14.0.0
+ *
+ * \param src The source codecs structure
+ * \param dest The destination codecs structure that the values from src will be copied to
+ * \param instance Optionally the instance that the dst codecs structure belongs to
+ *
+ * \return Nothing
+ */
+void ast_rtp_codecs_payloads_xover(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance);
+
+/*!
+ * \brief Record tx payload type information that was seen in an m= SDP line
  *
  * \param codecs The codecs structure to muck with
  * \param instance Optionally the instance that the codecs structure belongs to
@@ -1249,7 +1265,7 @@
 void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload);
 
 /*!
- * \brief Record payload information that was seen in an a=rtpmap: SDP line
+ * \brief Record tx payload type information that was seen in an a=rtpmap: SDP line
  *
  * \param codecs The codecs structure to muck with
  * \param instance Optionally the instance that the codecs structure belongs to
@@ -1275,7 +1291,7 @@
 int ast_rtp_codecs_payloads_set_rtpmap_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload, char *mimetype, char *mimesubtype, enum ast_rtp_options options);
 
 /*!
- * \brief Set payload type to a known MIME media type for a codec with a specific sample rate
+ * \brief Set tx payload type to a known MIME media type for a codec with a specific sample rate
  *
  * \param codecs RTP structure to modify
  * \param instance Optionally the instance that the codecs structure belongs to
@@ -1300,7 +1316,7 @@
 				  unsigned int sample_rate);
 
 /*!
- * \brief Remove payload information
+ * \brief Remove tx payload type mapped information
  *
  * \param codecs The codecs structure to muck with
  * \param instance Optionally the instance that the codecs structure belongs to
@@ -1319,7 +1335,7 @@
 void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload);
 
 /*!
- * \brief Retrieve payload information by payload
+ * \brief Retrieve rx payload mapped information by payload type
  *
  * \param codecs Codecs structure to look in
  * \param payload Numerical payload to look up
@@ -1342,10 +1358,10 @@
 struct ast_rtp_payload_type *ast_rtp_codecs_get_payload(struct ast_rtp_codecs *codecs, int payload);
 
 /*!
- * \brief Update the format associated with a payload in a codecs structure
+ * \brief Update the format associated with a tx payload type in a codecs structure
  *
  * \param codecs Codecs structure to operate on
- * \param payload Numerical payload to look up
+ * \param payload Numerical payload type to look up
  * \param format The format to replace the existing one
  *
  * \retval 0 success
@@ -1356,10 +1372,10 @@
 int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int payload, struct ast_format *format);
 
 /*!
- * \brief Retrieve the actual ast_format stored on the codecs structure for a specific payload
+ * \brief Retrieve the actual ast_format stored on the codecs structure for a specific tx payload type
  *
  * \param codecs Codecs structure to look in
- * \param payload Numerical payload to look up
+ * \param payload Numerical payload type to look up
  *
  * \retval pointer to format structure on success
  * \retval NULL on failure
@@ -1428,14 +1444,15 @@
 void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_format_cap *astformats, int *nonastformats);
 
 /*!
- * \brief Retrieve a payload based on whether it is an Asterisk format and the code
+ * \brief Retrieve a rx mapped payload type based on whether it is an Asterisk format and the code
  *
  * \param codecs Codecs structure to look in
  * \param asterisk_format Non-zero if the given Asterisk format is present
  * \param format Asterisk format to look for
  * \param code The format to look for
  *
- * \retval Numerical payload
+ * \retval Numerical payload type
+ * \retval -1 if not found.
  *
  * Example usage:
  *
@@ -1450,12 +1467,26 @@
 int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code);
 
 /*!
- * \brief Search for a payload code in the ast_rtp_codecs structure
+ * \brief Retrieve a tx mapped payload type based on whether it is an Asterisk format and the code
+ * \since 14.0.0
  *
  * \param codecs Codecs structure to look in
+ * \param asterisk_format Non-zero if the given Asterisk format is present
+ * \param format Asterisk format to look for
  * \param code The format to look for
  *
- * \retval Numerical payload or -1 if unable to find payload in codecs
+ * \retval Numerical payload type
+ * \retval -1 if not found.
+ */
+int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code);
+
+/*!
+ * \brief Search for the tx payload type in the ast_rtp_codecs structure
+ *
+ * \param codecs Codecs structure to look in
+ * \param payload The payload type format to look for
+ *
+ * \retval Numerical payload type or -1 if unable to find payload in codecs
  *
  * Example usage:
  *
@@ -1464,9 +1495,8 @@
  * \endcode
  *
  * This looks for the numerical payload for ULAW in the codecs structure.
- *
  */
-int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int code);
+int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int payload);
 
 /*!
  * \brief Retrieve mime subtype information on a payload
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 1375897..229af8f 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -580,22 +580,32 @@
 
 	codecs->framing = 0;
 	ast_rwlock_init(&codecs->codecs_lock);
-	res = AST_VECTOR_INIT(&codecs->payloads, AST_RTP_MAX_PT);
+	res = AST_VECTOR_INIT(&codecs->payload_mapping_rx, AST_RTP_MAX_PT);
+	res |= AST_VECTOR_INIT(&codecs->payload_mapping_tx, AST_RTP_MAX_PT);
+	if (res) {
+		AST_VECTOR_FREE(&codecs->payload_mapping_rx);
+		AST_VECTOR_FREE(&codecs->payload_mapping_tx);
+	}
 
 	return res;
 }
 
 void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs)
 {
-	int i;
+	int idx;
+	struct ast_rtp_payload_type *type;
 
-	for (i = 0; i < AST_VECTOR_SIZE(&codecs->payloads); i++) {
-		struct ast_rtp_payload_type *type;
-
-		type = AST_VECTOR_GET(&codecs->payloads, i);
-		ao2_t_cleanup(type, "destroying ast_rtp_codec");
+	for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) {
+		type = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx);
+		ao2_t_cleanup(type, "destroying ast_rtp_codec rx mapping");
 	}
-	AST_VECTOR_FREE(&codecs->payloads);
+	AST_VECTOR_FREE(&codecs->payload_mapping_rx);
+
+	for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) {
+		type = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx);
+		ao2_t_cleanup(type, "destroying ast_rtp_codec tx mapping");
+	}
+	AST_VECTOR_FREE(&codecs->payload_mapping_tx);
 
 	ast_rwlock_destroy(&codecs->codecs_lock);
 }
@@ -613,34 +623,254 @@
 	}
 }
 
-void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
+/*!
+ * \internal
+ * \brief Clear the rx primary mapping flag on all other matching mappings.
+ * \since 14.0.0
+ *
+ * \param codecs Codecs that need rx clearing.
+ * \param to_match Payload type object to compare against.
+ *
+ * \note It is assumed that codecs is write locked before calling.
+ *
+ * \return Nothing
+ */
+static void payload_mapping_rx_clear_primary(struct ast_rtp_codecs *codecs, struct ast_rtp_payload_type *to_match)
 {
-	int i;
+	int idx;
+	struct ast_rtp_payload_type *current;
+	struct ast_rtp_payload_type *new_type;
 
-	ast_rwlock_rdlock(&src->codecs_lock);
-	ast_rwlock_wrlock(&dest->codecs_lock);
+	if (!to_match->primary_mapping) {
+		return;
+	}
 
-	for (i = 0; i < AST_VECTOR_SIZE(&src->payloads); i++) {
-		struct ast_rtp_payload_type *type;
+	for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) {
+		current = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx);
 
-		type = AST_VECTOR_GET(&src->payloads, i);
+		if (!current || current == to_match || !current->primary_mapping) {
+			continue;
+		}
+		if (current->asterisk_format && to_match->asterisk_format) {
+			if (ast_format_cmp(current->format, to_match->format) == AST_FORMAT_CMP_NOT_EQUAL) {
+				continue;
+			}
+		} else if (!current->asterisk_format && !to_match->asterisk_format) {
+			if (current->rtp_code != to_match->rtp_code) {
+				continue;
+			}
+		} else {
+			continue;
+		}
+
+		/* Replace current with non-primary marked version */
+		new_type = ast_rtp_engine_alloc_payload_type();
+		if (!new_type) {
+			continue;
+		}
+		*new_type = *current;
+		new_type->primary_mapping = 0;
+		ao2_bump(new_type->format);
+		AST_VECTOR_REPLACE(&codecs->payload_mapping_rx, idx, new_type);
+		ao2_ref(current, -1);
+	}
+}
+
+/*!
+ * \internal
+ * \brief Copy the rx payload type mapping to the destination.
+ * \since 14.0.0
+ *
+ * \param src The source codecs structure
+ * \param dest The destination codecs structure that the values from src will be copied to
+ * \param instance Optionally the instance that the dst codecs structure belongs to
+ *
+ * \note It is assumed that src is at least read locked before calling.
+ * \note It is assumed that dest is write locked before calling.
+ *
+ * \return Nothing
+ */
+static void rtp_codecs_payloads_copy_rx(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
+{
+	int idx;
+	struct ast_rtp_payload_type *type;
+
+	for (idx = 0; idx < AST_VECTOR_SIZE(&src->payload_mapping_rx); ++idx) {
+		type = AST_VECTOR_GET(&src->payload_mapping_rx, idx);
 		if (!type) {
 			continue;
 		}
-		if (i < AST_VECTOR_SIZE(&dest->payloads)) {
-			ao2_t_cleanup(AST_VECTOR_GET(&dest->payloads, i), "cleaning up vector element about to be replaced");
+
+		ast_debug(2, "Copying rx payload mapping %d (%p) from %p to %p\n",
+			idx, type, src, dest);
+		ao2_ref(type, +1);
+		if (idx < AST_VECTOR_SIZE(&dest->payload_mapping_rx)) {
+			ao2_t_cleanup(AST_VECTOR_GET(&dest->payload_mapping_rx, idx),
+				"cleaning up rx mapping vector element about to be replaced");
 		}
-		ast_debug(2, "Copying payload %d (%p) from %p to %p\n", i, type, src, dest);
-		ao2_bump(type);
-		AST_VECTOR_REPLACE(&dest->payloads, i, type);
+		AST_VECTOR_REPLACE(&dest->payload_mapping_rx, idx, type);
+
+		payload_mapping_rx_clear_primary(dest, type);
 
 		if (instance && instance->engine && instance->engine->payload_set) {
-			instance->engine->payload_set(instance, i, type->asterisk_format, type->format, type->rtp_code);
+			instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code);
 		}
 	}
+}
+
+/*!
+ * \internal
+ * \brief Remove other matching payload mappings.
+ * \since 14.0.0
+ *
+ * \param codecs Codecs that need tx mappings removed.
+ * \param instance RTP instance to notify of any payloads removed.
+ * \param to_match Payload type object to compare against.
+ *
+ * \note It is assumed that codecs is write locked before calling.
+ *
+ * \return Nothing
+ */
+static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_rtp_payload_type *to_match)
+{
+	int idx;
+	struct ast_rtp_payload_type *current;
+
+	for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) {
+		current = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx);
+
+		if (!current || current == to_match) {
+			continue;
+		}
+		if (current->asterisk_format && to_match->asterisk_format) {
+			if (ast_format_cmp(current->format, to_match->format) == AST_FORMAT_CMP_NOT_EQUAL) {
+				continue;
+			}
+		} else if (!current->asterisk_format && !to_match->asterisk_format) {
+			if (current->rtp_code != to_match->rtp_code) {
+				continue;
+			}
+		} else {
+			continue;
+		}
+
+		/* Remove other mapping */
+		AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, idx, NULL);
+		ao2_ref(current, -1);
+		if (instance && instance->engine && instance->engine->payload_set) {
+			instance->engine->payload_set(instance, idx, 0, NULL, 0);
+		}
+	}
+}
+
+/*!
+ * \internal
+ * \brief Copy the tx payload type mapping to the destination.
+ * \since 14.0.0
+ *
+ * \param src The source codecs structure
+ * \param dest The destination codecs structure that the values from src will be copied to
+ * \param instance Optionally the instance that the dst codecs structure belongs to
+ *
+ * \note It is assumed that src is at least read locked before calling.
+ * \note It is assumed that dest is write locked before calling.
+ *
+ * \return Nothing
+ */
+static void rtp_codecs_payloads_copy_tx(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
+{
+	int idx;
+	struct ast_rtp_payload_type *type;
+
+	for (idx = 0; idx < AST_VECTOR_SIZE(&src->payload_mapping_tx); ++idx) {
+		type = AST_VECTOR_GET(&src->payload_mapping_tx, idx);
+		if (!type) {
+			continue;
+		}
+
+		ast_debug(2, "Copying tx payload mapping %d (%p) from %p to %p\n",
+			idx, type, src, dest);
+		ao2_ref(type, +1);
+		if (idx < AST_VECTOR_SIZE(&dest->payload_mapping_tx)) {
+			ao2_t_cleanup(AST_VECTOR_GET(&dest->payload_mapping_tx, idx),
+				"cleaning up tx mapping vector element about to be replaced");
+		}
+		AST_VECTOR_REPLACE(&dest->payload_mapping_tx, idx, type);
+
+		if (instance && instance->engine && instance->engine->payload_set) {
+			instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code);
+		}
+
+		payload_mapping_tx_remove_other_mappings(dest, instance, type);
+	}
+}
+
+void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
+{
+	ast_rwlock_wrlock(&dest->codecs_lock);
+
+	/* Deadlock avoidance because of held write lock. */
+	while (ast_rwlock_tryrdlock(&src->codecs_lock)) {
+		ast_rwlock_unlock(&dest->codecs_lock);
+		sched_yield();
+		ast_rwlock_wrlock(&dest->codecs_lock);
+	}
+
+	rtp_codecs_payloads_copy_rx(src, dest, instance);
+	rtp_codecs_payloads_copy_tx(src, dest, instance);
 	dest->framing = src->framing;
-	ast_rwlock_unlock(&dest->codecs_lock);
+
 	ast_rwlock_unlock(&src->codecs_lock);
+	ast_rwlock_unlock(&dest->codecs_lock);
+}
+
+void ast_rtp_codecs_payloads_xover(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
+{
+	int idx;
+	struct ast_rtp_payload_type *type;
+
+	ast_rwlock_wrlock(&dest->codecs_lock);
+	if (src != dest) {
+		/* Deadlock avoidance because of held write lock. */
+		while (ast_rwlock_tryrdlock(&src->codecs_lock)) {
+			ast_rwlock_unlock(&dest->codecs_lock);
+			sched_yield();
+			ast_rwlock_wrlock(&dest->codecs_lock);
+		}
+	}
+
+	/* Crossover copy payload type tx mapping to rx mapping. */
+	for (idx = 0; idx < AST_VECTOR_SIZE(&src->payload_mapping_tx); ++idx) {
+		type = AST_VECTOR_GET(&src->payload_mapping_tx, idx);
+		if (!type) {
+			continue;
+		}
+
+		/* All tx mapping elements should have the primary flag set. */
+		ast_assert(type->primary_mapping);
+
+		ast_debug(2, "Crossover copying tx to rx payload mapping %d (%p) from %p to %p\n",
+			idx, type, src, dest);
+		ao2_ref(type, +1);
+		if (idx < AST_VECTOR_SIZE(&dest->payload_mapping_rx)) {
+			ao2_t_cleanup(AST_VECTOR_GET(&dest->payload_mapping_rx, idx),
+				"cleaning up rx mapping vector element about to be replaced");
+		}
+		AST_VECTOR_REPLACE(&dest->payload_mapping_rx, idx, type);
+
+		payload_mapping_rx_clear_primary(dest, type);
+
+		if (instance && instance->engine && instance->engine->payload_set) {
+			instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code);
+		}
+	}
+
+	dest->framing = src->framing;
+
+	if (src != dest) {
+		ast_rwlock_unlock(&src->codecs_lock);
+	}
+	ast_rwlock_unlock(&dest->codecs_lock);
 }
 
 void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
@@ -665,14 +895,17 @@
 
 	ast_rwlock_wrlock(&codecs->codecs_lock);
 
-	if (payload < AST_VECTOR_SIZE(&codecs->payloads)) {
-		ao2_t_cleanup(AST_VECTOR_GET(&codecs->payloads, payload), "cleaning up replaced payload type");
+	if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
+		ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload),
+			"cleaning up replaced tx payload type");
 	}
-	AST_VECTOR_REPLACE(&codecs->payloads, payload, new_type);
+	AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type);
 
 	if (instance && instance->engine && instance->engine->payload_set) {
 		instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code);
 	}
+
+	payload_mapping_tx_remove_other_mappings(codecs, instance, new_type);
 
 	ast_rwlock_unlock(&codecs->codecs_lock);
 }
@@ -682,7 +915,7 @@
 				 enum ast_rtp_options options,
 				 unsigned int sample_rate)
 {
-	unsigned int i;
+	unsigned int idx;
 	int found = 0;
 
 	if (pt < 0 || pt >= AST_RTP_MAX_PT) {
@@ -691,8 +924,9 @@
 
 	ast_rwlock_rdlock(&mime_types_lock);
 	ast_rwlock_wrlock(&codecs->codecs_lock);
-	for (i = 0; i < mime_types_len; ++i) {
-		const struct ast_rtp_mime_type *t = &ast_rtp_mime_types[i];
+
+	for (idx = 0; idx < mime_types_len; ++idx) {
+		const struct ast_rtp_mime_type *t = &ast_rtp_mime_types[idx];
 		struct ast_rtp_payload_type *new_type;
 
 		if (strcasecmp(mimesubtype, t->subtype)) {
@@ -718,27 +952,32 @@
 			continue;
 		}
 
-		if (pt < AST_VECTOR_SIZE(&codecs->payloads)) {
-			ao2_t_cleanup(AST_VECTOR_GET(&codecs->payloads, pt), "cleaning up replaced payload type");
-		}
-
-		new_type->payload = pt;
 		new_type->asterisk_format = t->payload_type.asterisk_format;
 		new_type->rtp_code = t->payload_type.rtp_code;
-		if ((ast_format_cmp(t->payload_type.format, ast_format_g726) == AST_FORMAT_CMP_EQUAL) &&
-				t->payload_type.asterisk_format && (options & AST_RTP_OPT_G726_NONSTANDARD)) {
+		new_type->payload = pt;
+		new_type->primary_mapping = 1;
+		if (t->payload_type.asterisk_format
+			&& ast_format_cmp(t->payload_type.format, ast_format_g726) == AST_FORMAT_CMP_EQUAL
+			&& (options & AST_RTP_OPT_G726_NONSTANDARD)) {
 			new_type->format = ao2_bump(ast_format_g726_aal2);
 		} else {
 			new_type->format = ao2_bump(t->payload_type.format);
 		}
-		AST_VECTOR_REPLACE(&codecs->payloads, pt, new_type);
+
+		if (pt < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
+			ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, pt),
+				"cleaning up replaced tx payload type");
+		}
+		AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type);
 
 		if (instance && instance->engine && instance->engine->payload_set) {
 			instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code);
 		}
 
+		payload_mapping_tx_remove_other_mappings(codecs, instance, new_type);
 		break;
 	}
+
 	ast_rwlock_unlock(&codecs->codecs_lock);
 	ast_rwlock_unlock(&mime_types_lock);
 
@@ -761,10 +1000,11 @@
 	ast_debug(2, "Unsetting payload %d on %p\n", payload, codecs);
 
 	ast_rwlock_wrlock(&codecs->codecs_lock);
-	if (payload < AST_VECTOR_SIZE(&codecs->payloads)) {
-		type = AST_VECTOR_GET(&codecs->payloads, payload);
+
+	if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
+		type = AST_VECTOR_GET(&codecs->payload_mapping_tx, payload);
 		ao2_cleanup(type);
-		AST_VECTOR_REPLACE(&codecs->payloads, payload, NULL);
+		AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, NULL);
 	}
 
 	if (instance && instance->engine && instance->engine->payload_set) {
@@ -783,8 +1023,8 @@
 	}
 
 	ast_rwlock_rdlock(&codecs->codecs_lock);
-	if (payload < AST_VECTOR_SIZE(&codecs->payloads)) {
-		type = AST_VECTOR_GET(&codecs->payloads, payload);
+	if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_rx)) {
+		type = AST_VECTOR_GET(&codecs->payload_mapping_rx, payload);
 		ao2_bump(type);
 	}
 	ast_rwlock_unlock(&codecs->codecs_lock);
@@ -814,12 +1054,14 @@
 	type->format = format;
 	type->asterisk_format = 1;
 	type->payload = payload;
+	type->primary_mapping = 1;
 
 	ast_rwlock_wrlock(&codecs->codecs_lock);
-	if (payload < AST_VECTOR_SIZE(&codecs->payloads)) {
-		ao2_cleanup(AST_VECTOR_GET(&codecs->payloads, payload));
+	if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
+		ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload));
 	}
-	AST_VECTOR_REPLACE(&codecs->payloads, payload, type);
+	AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type);
+	payload_mapping_tx_remove_other_mappings(codecs, NULL, type);
 	ast_rwlock_unlock(&codecs->codecs_lock);
 
 	return 0;
@@ -835,8 +1077,8 @@
 	}
 
 	ast_rwlock_rdlock(&codecs->codecs_lock);
-	if (payload < AST_VECTOR_SIZE(&codecs->payloads)) {
-		type = AST_VECTOR_GET(&codecs->payloads, payload);
+	if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
+		type = AST_VECTOR_GET(&codecs->payload_mapping_tx, payload);
 		if (type && type->asterisk_format) {
 			format = ao2_bump(type->format);
 		}
@@ -870,16 +1112,17 @@
 
 void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_format_cap *astformats, int *nonastformats)
 {
-	int i;
+	int idx;
 
 	ast_format_cap_remove_by_type(astformats, AST_MEDIA_TYPE_UNKNOWN);
 	*nonastformats = 0;
 
 	ast_rwlock_rdlock(&codecs->codecs_lock);
-	for (i = 0; i < AST_VECTOR_SIZE(&codecs->payloads); i++) {
+
+	for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) {
 		struct ast_rtp_payload_type *type;
 
-		type = AST_VECTOR_GET(&codecs->payloads, i);
+		type = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx);
 		if (!type) {
 			continue;
 		}
@@ -890,7 +1133,6 @@
 			*nonastformats |= type->rtp_code;
 		}
 	}
-
 	if (codecs->framing) {
 		ast_format_cap_set_framing(astformats, codecs->framing);
 	}
@@ -898,40 +1140,42 @@
 	ast_rwlock_unlock(&codecs->codecs_lock);
 }
 
-int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code)
+/*!
+ * \internal
+ * \brief Find the static payload type mapping for the format.
+ * \since 14.0.0
+ *
+ * \param asterisk_format Non-zero if the given Asterisk format is present
+ * \param format Asterisk format to look for
+ * \param code The non-Asterisk format code to look for
+ *
+ * \retval Numerical payload type
+ * \retval -1 if not found.
+ */
+static int find_static_payload_type(int asterisk_format, const struct ast_format *format, int code)
 {
-	struct ast_rtp_payload_type *type;
-	int i;
+	int idx;
 	int payload = -1;
 
-	ast_rwlock_rdlock(&codecs->codecs_lock);
-	for (i = 0; i < AST_VECTOR_SIZE(&codecs->payloads); i++) {
-		type = AST_VECTOR_GET(&codecs->payloads, i);
-		if (!type) {
-			continue;
-		}
-
-		if ((asterisk_format && format && ast_format_cmp(format, type->format) == AST_FORMAT_CMP_EQUAL)
-			|| (!asterisk_format && type->rtp_code == code)) {
-			payload = i;
-			break;
-		}
-	}
-	ast_rwlock_unlock(&codecs->codecs_lock);
-
-	if (payload < 0) {
+	if (!asterisk_format) {
 		ast_rwlock_rdlock(&static_RTP_PT_lock);
-		for (i = 0; i < AST_RTP_MAX_PT; i++) {
-			if (!static_RTP_PT[i]) {
-				continue;
-			}
-			if (static_RTP_PT[i]->asterisk_format && asterisk_format && format &&
-				(ast_format_cmp(format, static_RTP_PT[i]->format) != AST_FORMAT_CMP_NOT_EQUAL)) {
-				payload = i;
+		for (idx = 0; idx < AST_RTP_MAX_PT; ++idx) {
+			if (static_RTP_PT[idx]
+				&& !static_RTP_PT[idx]->asterisk_format
+				&& static_RTP_PT[idx]->rtp_code == code) {
+				payload = idx;
 				break;
-			} else if (!static_RTP_PT[i]->asterisk_format && !asterisk_format &&
-				(static_RTP_PT[i]->rtp_code == code)) {
-				payload = i;
+			}
+		}
+		ast_rwlock_unlock(&static_RTP_PT_lock);
+	} else if (format) {
+		ast_rwlock_rdlock(&static_RTP_PT_lock);
+		for (idx = 0; idx < AST_RTP_MAX_PT; ++idx) {
+			if (static_RTP_PT[idx]
+				&& static_RTP_PT[idx]->asterisk_format
+				&& ast_format_cmp(format, static_RTP_PT[idx]->format)
+					!= AST_FORMAT_CMP_NOT_EQUAL) {
+				payload = idx;
 				break;
 			}
 		}
@@ -941,16 +1185,116 @@
 	return payload;
 }
 
-int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int code)
+int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code)
+{
+	struct ast_rtp_payload_type *type;
+	int idx;
+	int payload = -1;
+
+	if (!asterisk_format) {
+		ast_rwlock_rdlock(&codecs->codecs_lock);
+		for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) {
+			type = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx);
+			if (!type) {
+				continue;
+			}
+
+			if (!type->asterisk_format
+				&& type->rtp_code == code) {
+				if (type->primary_mapping) {
+					payload = idx;
+					break;
+				}
+				if (payload == -1) {
+					payload = idx;
+				}
+			}
+		}
+		ast_rwlock_unlock(&codecs->codecs_lock);
+	} else if (format) {
+		ast_rwlock_rdlock(&codecs->codecs_lock);
+		for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) {
+			type = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx);
+			if (!type) {
+				continue;
+			}
+
+			if (type->asterisk_format
+				&& ast_format_cmp(format, type->format) == AST_FORMAT_CMP_EQUAL) {
+				if (type->primary_mapping) {
+					payload = idx;
+					break;
+				}
+				if (payload == -1) {
+					payload = idx;
+				}
+			}
+		}
+		ast_rwlock_unlock(&codecs->codecs_lock);
+	}
+
+	if (payload < 0) {
+		payload = find_static_payload_type(asterisk_format, format, code);
+	}
+
+	return payload;
+}
+
+int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code)
+{
+	struct ast_rtp_payload_type *type;
+	int idx;
+	int payload = -1;
+
+	if (!asterisk_format) {
+		ast_rwlock_rdlock(&codecs->codecs_lock);
+		for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) {
+			type = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx);
+			if (!type) {
+				continue;
+			}
+
+			if (!type->asterisk_format
+				&& type->rtp_code == code) {
+				payload = idx;
+				break;
+			}
+		}
+		ast_rwlock_unlock(&codecs->codecs_lock);
+	} else if (format) {
+		ast_rwlock_rdlock(&codecs->codecs_lock);
+		for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) {
+			type = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx);
+			if (!type) {
+				continue;
+			}
+
+			if (type->asterisk_format
+				&& ast_format_cmp(format, type->format) == AST_FORMAT_CMP_EQUAL) {
+				payload = idx;
+				break;
+			}
+		}
+		ast_rwlock_unlock(&codecs->codecs_lock);
+	}
+
+	if (payload < 0) {
+		payload = find_static_payload_type(asterisk_format, format, code);
+	}
+
+	return payload;
+}
+
+int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int payload)
 {
 	struct ast_rtp_payload_type *type;
 	int res = -1;
 
 	ast_rwlock_rdlock(&codecs->codecs_lock);
-	if (code < AST_VECTOR_SIZE(&codecs->payloads)) {
-		type = AST_VECTOR_GET(&codecs->payloads, code);
+	if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
+		type = AST_VECTOR_GET(&codecs->payload_mapping_tx, payload);
 		if (type) {
-			res = type->payload;
+			res = payload;
 		}
 	}
 	ast_rwlock_unlock(&codecs->codecs_lock);
@@ -1192,13 +1536,13 @@
 		goto done;
 	}
 
-	ast_rtp_codecs_payloads_copy(&instance_src->codecs, &instance_dst->codecs, instance_dst);
+	ast_rtp_codecs_payloads_xover(&instance_src->codecs, &instance_dst->codecs, instance_dst);
 
 	if (vinstance_dst && vinstance_src) {
-		ast_rtp_codecs_payloads_copy(&vinstance_src->codecs, &vinstance_dst->codecs, vinstance_dst);
+		ast_rtp_codecs_payloads_xover(&vinstance_src->codecs, &vinstance_dst->codecs, vinstance_dst);
 	}
 	if (tinstance_dst && tinstance_src) {
-		ast_rtp_codecs_payloads_copy(&tinstance_src->codecs, &tinstance_dst->codecs, tinstance_dst);
+		ast_rtp_codecs_payloads_xover(&tinstance_src->codecs, &tinstance_dst->codecs, tinstance_dst);
 	}
 
 	if (glue_dst->update_peer(c_dst, instance_src, vinstance_src, tinstance_src, cap_src, 0)) {
@@ -1772,6 +2116,7 @@
 			type->rtp_code = rtp_code;
 		}
 		type->payload = map;
+		type->primary_mapping = 1;
 		ao2_cleanup(static_RTP_PT[map]);
 		static_RTP_PT[map] = type;
 	}
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index cca1969..545e216 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -2690,7 +2690,7 @@
 	}
 
 	/* Grab the payload that they expect the RFC2833 packet to be received in */
-	payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_DTMF);
+	payload = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_DTMF);
 
 	rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
 	rtp->send_duration = 160;
@@ -3417,10 +3417,8 @@
 	}
 
 	/* Grab the subclass and look up the payload we are going to use */
-	codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance),
-	                                    1,
-	                                    frame->subclass.format,
-	                                    0);
+	codec = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance),
+		1, frame->subclass.format, 0);
 	if (codec < 0) {
 		ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n",
 			ast_format_get_name(frame->subclass.format));
@@ -4206,7 +4204,8 @@
 	}
 
 	/* Otherwise adjust bridged payload to match */
-	bridged_payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance1), payload_type->asterisk_format, payload_type->format, payload_type->rtp_code);
+	bridged_payload = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance1),
+		payload_type->asterisk_format, payload_type->format, payload_type->rtp_code);
 
 	/* If no codec could be matched between instance and instance1, then somehow things were made incompatible while we were still bridged.  Bail. */
 	if (bridged_payload < 0) {
@@ -5012,7 +5011,7 @@
 		return -1;
 	}
 
-	payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_CN);
+	payload = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_CN);
 
 	level = 127 - (level & 0x7f);
 
diff --git a/res/res_rtp_multicast.c b/res/res_rtp_multicast.c
index 887eed2..192f3d1 100644
--- a/res/res_rtp_multicast.c
+++ b/res/res_rtp_multicast.c
@@ -247,7 +247,9 @@
 	}
 
 	/* Grab the actual payload number for when we create the RTP packet */
-	if ((codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 1, frame->subclass.format, 0)) < 0) {
+	codec = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance),
+		1, frame->subclass.format, 0);
+	if (codec < 0) {
 		return -1;
 	}
 

-- 
To view, visit https://gerrit.asterisk.org/1018
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Iaf6c227bca68cb7c414cf2fd4108a8ac98bd45ac
Gerrit-PatchSet: 3
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Richard Mudgett <rmudgett at digium.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Matt Jordan <mjordan at digium.com>
Gerrit-Reviewer: Richard Mudgett <rmudgett at digium.com>



More information about the asterisk-code-review mailing list