mgcp_codec: refactor payload type converstion

in mgcp_codec.c we have a function mgcp_codec_pt_translate that is used
to find the equivalent payload type number on an opposite connection.
This is quite specific and the resulting payload type number may still
belong to a codec that might require some form of conversion.

Lets refactor this so that the function just finds a convertible codec
for a given connection. This also opens up other usecases. The payload
type conversion like we did it before can then be done with a few lines
in mgcp_network.c

Related: OS#5461
Change-Id: I085260a2ca8cfecdb58656b7a046c536189e238d
diff --git a/src/libosmo-mgcp/mgcp_codec.c b/src/libosmo-mgcp/mgcp_codec.c
index ccb5d77..9086047 100644
--- a/src/libosmo-mgcp/mgcp_codec.c
+++ b/src/libosmo-mgcp/mgcp_codec.c
@@ -425,63 +425,42 @@
 	return true;
 }
 
-/*! Translate a given payload type number that belongs to the packet of a
- *  source connection to the equivalent payload type number that matches the
- *  configuration of a destination connection.
- *  \param[in] conn_src related source rtp-connection.
- *  \param[in] conn_dst related destination rtp-connection.
- *  \param[in] payload_type number from the source packet or source connection.
- *  \returns translated payload type number on success, -EINVAL on failure. */
-int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type)
+/*! For a given codec, find a convertible codec in the given connection.
+ *  \param[in] conn connection to search for a convertible codec
+ *  \param[in] codec for which a convertible codec shall be found.
+ *  \returns codec on success, -NULL on failure. */
+struct mgcp_rtp_codec *mgcp_codec_find_convertible(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
 {
-	struct mgcp_rtp_end *rtp_src;
-	struct mgcp_rtp_end *rtp_dst;
-	struct mgcp_rtp_codec *codec_src = NULL;
-	struct mgcp_rtp_codec *codec_dst = NULL;
+	struct mgcp_rtp_end *rtp_end;
 	unsigned int i;
 	unsigned int codecs_assigned;
+	struct mgcp_rtp_codec *codec_convertible = NULL;
 
-	rtp_src = &conn_src->end;
-	rtp_dst = &conn_dst->end;
-
-	/* Find the codec information that is used on the source side */
-	codecs_assigned = rtp_src->codecs_assigned;
-	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
-	for (i = 0; i < codecs_assigned; i++) {
-		if (payload_type == rtp_src->codecs[i].payload_type) {
-			codec_src = &rtp_src->codecs[i];
-			break;
-		}
-	}
-	if (!codec_src)
-		return -EINVAL;
+	rtp_end = &conn->end;
 
 	/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
 	 * the first run we will look for an exact match. */
-	codecs_assigned = rtp_dst->codecs_assigned;
+	codecs_assigned = rtp_end->codecs_assigned;
 	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 	for (i = 0; i < codecs_assigned; i++) {
-		if (codecs_same(codec_src, &rtp_dst->codecs[i])) {
-			codec_dst = &rtp_dst->codecs[i];
+		if (codecs_same(codec, &rtp_end->codecs[i])) {
+			codec_convertible = &rtp_end->codecs[i];
 			break;
 		}
 	}
 
 	/* In case we weren't able to find an exact match, we will try to find a match that is the same codec, but the
 	 * payload format may be different. This alternative will require a frame format conversion (i.e. AMR bwe->oe) */
-	if (!codec_dst) {
+	if (!codec_convertible) {
 		for (i = 0; i < codecs_assigned; i++) {
-			if (codecs_convertible(codec_src, &rtp_dst->codecs[i])) {
-				codec_dst = &rtp_dst->codecs[i];
+			if (codecs_convertible(codec, &rtp_end->codecs[i])) {
+				codec_convertible = &rtp_end->codecs[i];
 				break;
 			}
 		}
 	}
 
-	if (!codec_dst)
-		return -EINVAL;
-
-	return codec_dst->payload_type;
+	return codec_convertible;
 }
 
 /* Find the payload type number configured for a specific codec by SDP.
@@ -508,3 +487,26 @@
 	}
 	return NULL;
 }
+
+/*! Lookup a codec that is assigned to a connection by its payload type number.
+ *  \param[in] conn related rtp-connection.
+ *  \param[in] payload_type number of the codec to look up.
+ *  \returns pointer to codec struct on success, NULL on failure. */
+struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type)
+{
+	struct mgcp_rtp_end *rtp_end = &conn->end;
+	unsigned int codecs_assigned = rtp_end->codecs_assigned;
+	struct mgcp_rtp_codec *codec = NULL;
+	size_t i;
+
+	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
+
+	for (i = 0; i < codecs_assigned; i++) {
+		if (payload_type == rtp_end->codecs[i].payload_type) {
+			codec = &rtp_end->codecs[i];
+			break;
+		}
+	}
+
+	return codec;
+}
diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c
index af9ae99..ce08dd4 100644
--- a/src/libosmo-mgcp/mgcp_network.c
+++ b/src/libosmo-mgcp/mgcp_network.c
@@ -493,27 +493,31 @@
 /* There may be different payload type numbers negotiated for two connections.
  * Patch the payload type of an RTP packet so that it uses the payload type
  * that is valid for the destination connection (conn_dst) */
-static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_src,
-			 struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
+static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
 {
 	struct rtp_hdr *rtp_hdr;
-	uint8_t pt_in;
-	int pt_out;
+	struct mgcp_rtp_codec *codec_src;
+	struct mgcp_rtp_codec *codec_dst;
 
 	if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
 		LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTP packet too short (%u < %zu)\n",
 			     msgb_length(msg), sizeof(struct rtp_hdr));
 		return -EINVAL;
 	}
-
 	rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 
-	pt_in = rtp_hdr->payload_type;
-	pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);
-	if (pt_out < 0)
+	/* Find the codec information that is used on the source side */
+	codec_src = mgcp_codec_from_pt(conn_src, rtp_hdr->payload_type);
+	if (!codec_src)
 		return -EINVAL;
 
-	rtp_hdr->payload_type = (uint8_t) pt_out;
+	/* Lookup a suitable codec in the destination connection. (The codec must be of the same type or at least
+	 * convertible) */
+	codec_dst = mgcp_codec_find_convertible(conn_dst, codec_src);
+	if (!codec_dst)
+		return -EINVAL;
+
+	rtp_hdr->payload_type = (uint8_t) codec_dst->payload_type;
 	return 0;
 }