Change in osmo-mgw[master]: AMR: Add function to convert between bw-effient and octet aligned mode

dexter gerrit-no-reply at lists.osmocom.org
Thu Mar 7 10:34:45 UTC 2019


dexter has uploaded this change for review. ( https://gerrit.osmocom.org/13159


Change subject: AMR: Add function to convert between bw-effient and octet aligned mode
......................................................................

AMR: Add function to convert between bw-effient and octet aligned mode

RFC3267 specifies two framing modes for AMR packets. An octet aligned
mode is specified where all fields of the AMR packets are aligned to
octet boundaries. The second framing mode is the bandwith efficient mode
where the fields are directly packed one after another.

- add paring/generation for related SDP fmtp parameters
- add conversion function to convert AMR payload

Depends: libosmo-netif I5b5a0fa644d8dbb1f04f9d7e35312683c7b3d196
Change-Id: I622c01874b25f5049d4f59eb8157e0ea3cbe16ba
Related: OS#3807
---
M include/osmocom/mgcp/mgcp_codec.h
M include/osmocom/mgcp/mgcp_internal.h
M src/libosmo-mgcp/mgcp_codec.c
M src/libosmo-mgcp/mgcp_network.c
M src/libosmo-mgcp/mgcp_protocol.c
M src/libosmo-mgcp/mgcp_sdp.c
M tests/mgcp/mgcp_test.c
M tests/mgcp/mgcp_test.ok
8 files changed, 348 insertions(+), 18 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-mgw refs/changes/59/13159/1

diff --git a/include/osmocom/mgcp/mgcp_codec.h b/include/osmocom/mgcp/mgcp_codec.h
index 334913b..2bbb86e 100644
--- a/include/osmocom/mgcp/mgcp_codec.h
+++ b/include/osmocom/mgcp/mgcp_codec.h
@@ -2,6 +2,6 @@
 
 void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
 void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
-int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name);
+int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, struct mgcp_codec_param *param);
 int mgcp_codec_decide(struct mgcp_conn_rtp *conn);
 int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
diff --git a/include/osmocom/mgcp/mgcp_internal.h b/include/osmocom/mgcp/mgcp_internal.h
index 35b535a..0a95236 100644
--- a/include/osmocom/mgcp/mgcp_internal.h
+++ b/include/osmocom/mgcp/mgcp_internal.h
@@ -86,6 +86,11 @@
 	bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
 };
 
+struct mgcp_codec_param {
+	bool amr_octet_aligned_present;
+	bool amr_octet_aligned;
+};
+
 struct mgcp_rtp_codec {
 	uint32_t rate;
 	int channels;
@@ -95,6 +100,9 @@
 	int payload_type;
 	char *audio_name;
 	char *subtype_name;
+
+	bool param_present;
+	struct mgcp_codec_param param;
 };
 
 /* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
diff --git a/src/libosmo-mgcp/mgcp_codec.c b/src/libosmo-mgcp/mgcp_codec.c
index 55be554..933284d 100644
--- a/src/libosmo-mgcp/mgcp_codec.c
+++ b/src/libosmo-mgcp/mgcp_codec.c
@@ -100,8 +100,8 @@
 }
 
 /* Set members of struct mgcp_rtp_codec, extrapolate in missing information */
-static int codec_set(void *ctx, struct mgcp_rtp_codec *codec,
-		     int payload_type, const char *audio_name, unsigned int pt_offset)
+static int codec_set(void *ctx, struct mgcp_rtp_codec *codec, int payload_type, const char *audio_name,
+		     unsigned int pt_offset, struct mgcp_codec_param *param)
 {
 	int rate;
 	int channels;
@@ -219,6 +219,13 @@
 		}
 	}
 
+	/* Copy over optional codec parameters */
+	if (param) {
+		codec->param = *param;
+		codec->param_present = true;
+	} else
+		codec->param_present = false;
+
 	return 0;
 error:
 	/* Make sure we leave a clean codec entry on error. */
@@ -233,8 +240,9 @@
  *  \param[out] conn related rtp-connection.
  *  \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined).
  *  \param[in] audio_name audio codec name (e.g. "GSM/8000/1").
+ *  \param[in] param optional codec parameters (set to NULL when unused).
  *  \returns 0 on success, -EINVAL on failure. */
-int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name)
+int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, struct mgcp_codec_param *param)
 {
 	int rc;
 
@@ -244,7 +252,7 @@
 		return -EINVAL;
 
 	rc = codec_set(conn->conn, &conn->end.codecs[conn->end.codecs_assigned], payload_type, audio_name,
-		       conn->end.codecs_assigned);
+		       conn->end.codecs_assigned, param);
 	if (rc != 0)
 		return -EINVAL;
 
diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c
index e4fd7c0..2c6c571 100644
--- a/src/libosmo-mgcp/mgcp_network.c
+++ b/src/libosmo-mgcp/mgcp_network.c
@@ -34,6 +34,7 @@
 #include <osmocom/core/socket.h>
 #include <osmocom/core/byteswap.h>
 #include <osmocom/netif/rtp.h>
+#include <osmocom/netif/amr.h>
 #include <osmocom/mgcp/mgcp.h>
 #include <osmocom/mgcp/mgcp_common.h>
 #include <osmocom/mgcp/mgcp_internal.h>
@@ -684,6 +685,86 @@
 	}
 }
 
+/* For AMR RTP two framing modes are defined RFC3267. There is a bandwith
+ * efficient encoding scheme where all fields are packed together one after
+ * another and an octet aligned mode where all fields are aligned to octet
+ * boundaries. This function is used to convert between the two modes */
+static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, char *data, int *len,
+			      bool target_is_oa)
+{
+	/* NOTE: *data has an overall length of RTP_BUF_SIZE, so there is
+	 * plenty of space available to store the slightly larger, converted
+	 * data */
+
+	struct rtp_hdr *rtp_hdr;
+	unsigned int payload_len;
+	int rc;
+
+	OSMO_ASSERT(*len >= sizeof(struct rtp_hdr));
+	rtp_hdr = (struct rtp_hdr *)data;
+
+	payload_len = *len - sizeof(struct rtp_hdr);
+
+	if (osmo_amr_is_oa(rtp_hdr->data, payload_len)) {
+		if (!target_is_oa)
+			/* Input data is oa an target format is bwe
+			 * ==> convert */
+			rc = osmo_amr_oa_to_bwe(rtp_hdr->data, payload_len);
+		else
+			/* Input data is already bew, but we accept it anyway
+			 * ==> no conversion needed */
+			rc = payload_len;
+	} else {
+		if (target_is_oa)
+			/* Input data is bwe an target format is oa
+			 * ==> convert */
+			rc = osmo_amr_bwe_to_oa(rtp_hdr->data, payload_len,
+						RTP_BUF_SIZE);
+		else
+			/* Input data is already oa, but we accept it anyway
+			 * ==> no conversion needed */
+			rc = payload_len;
+	}
+	if (rc < 0) {
+		LOGP(DRTP, LOGL_ERROR,
+		     "endpoint:0x%x AMR RTP packet conversion failed\n",
+		     ENDPOINT_NUMBER(endp));
+		return -EINVAL;
+	}
+
+	*len = rc + sizeof(struct rtp_hdr);
+
+	return 0;
+}
+
+/* Check if a conversion between octet-aligned and bandwith-efficient mode is
+ * indicated. */
+static bool amr_oa_bwe_convert_indicated(struct mgcp_rtp_codec *codec)
+{
+	if (codec->param_present == false)
+		return false;
+	if (!codec->param.amr_octet_aligned_present)
+		return false;
+	if (strcmp(codec->subtype_name, "AMR") != 0)
+		return false;
+	return true;
+}
+
+
+/* Check if a given RTP with AMR payload for octet-aligned mode */
+static bool amr_oa_check(char *data, int len)
+{
+	struct rtp_hdr *rtp_hdr;
+	unsigned int payload_len;
+
+	OSMO_ASSERT(len >= sizeof(struct rtp_hdr));
+	rtp_hdr = (struct rtp_hdr *)data;
+
+	payload_len = len - sizeof(struct rtp_hdr);
+
+	return osmo_amr_is_oa(rtp_hdr->data, payload_len);
+}
+
 /* Forward data to a debug tap. This is debug function that is intended for
  * debugging the voice traffic with tools like gstreamer */
 static void forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf,
@@ -792,7 +873,11 @@
 				mgcp_patch_and_count(endp, rtp_state, rtp_end,
 						     addr, buf, buflen);
 
-			if (rtp_end->rfc5993_hr_convert
+			if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
+				amr_oa_bwe_convert(endp, buf, &buflen,
+						   conn_dst->end.codec->param.amr_octet_aligned);
+			}
+			else if (rtp_end->rfc5993_hr_convert
 			    && strcmp(conn_src->end.codec->subtype_name,
 				      "GSM-HR-08") == 0)
 				rfc5993_hr_convert(endp, buf, &buflen);
@@ -1302,6 +1387,15 @@
 				     len, conn_src, conn_src);
 	}
 
+	/* If AMR is configured for the ingress connection a conversion of the
+	 * framing mode (octet-aligned vs. bandwith-efficient is explicitly
+	 * define, then we check if the incoming payload matches that
+	 * expectation. */
+	if (amr_oa_bwe_convert_indicated(conn_src->end.codec)) {
+		if (amr_oa_check(buf, len) != conn_src->end.codec->param.amr_octet_aligned)
+			return -1;
+	}
+
 	/* Execute endpoint specific implementation that handles the
 	 * dispatching of the RTP data */
 	return endp->type->dispatch_rtp_cb(proto, &addr, buf, len,
diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c
index 82db02f..4121b9f 100644
--- a/src/libosmo-mgcp/mgcp_protocol.c
+++ b/src/libosmo-mgcp/mgcp_protocol.c
@@ -724,7 +724,7 @@
 		/* When no SDP is available, we use the codec information from
 		 * the local connection options (if present) */
 		mgcp_codec_reset_all(conn);
-		rc = mgcp_codec_add(conn, PTYPE_UNDEFINED, endp->local_options.codec);
+		rc = mgcp_codec_add(conn, PTYPE_UNDEFINED, endp->local_options.codec, NULL);
 		if (rc != 0)
 			goto error;
 	}
@@ -735,7 +735,7 @@
 		 * than it makes sense to pick a sane default: (payload-type 0,
 		 * PCMU), see also: OS#2658 */
 		mgcp_codec_reset_all(conn);
-		rc = mgcp_codec_add(conn, 0, NULL);
+		rc = mgcp_codec_add(conn, 0, NULL, NULL);
 		if (rc != 0)
 			goto error;
 	}
diff --git a/src/libosmo-mgcp/mgcp_sdp.c b/src/libosmo-mgcp/mgcp_sdp.c
index f5b7bdd..1f8742a 100644
--- a/src/libosmo-mgcp/mgcp_sdp.c
+++ b/src/libosmo-mgcp/mgcp_sdp.c
@@ -30,9 +30,9 @@
 
 #include <errno.h>
 
-/* A struct to store intermediate parsing results. The function
- * mgcp_parse_sdp_data() is using it as temporary storage for parsing the SDP
- * codec information. */
+/* Two structs to store intermediate parsing results. The function
+ * mgcp_parse_sdp_data() is using the following two structs as temporary
+ * storage for parsing the SDP codec information. */
 struct sdp_rtp_map {
 	/* the type */
 	int payload_type;
@@ -44,6 +44,11 @@
 	int rate;
 	int channels;
 };
+struct sdp_fmtp_param {
+	int payload_type;
+	struct mgcp_codec_param param;
+};
+
 
 /* Helper function to extrapolate missing codec parameters in a codec mao from
  * an already filled in payload_type, called from: mgcp_parse_sdp_data() */
@@ -168,6 +173,92 @@
 	return -EINVAL;
 }
 
+/* Extract fmtp parameters from SDP, called from: mgcp_parse_sdp_data() */
+static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp)
+{
+	char *str;
+	char *str_ptr;
+	char *param_str;
+	unsigned int pt;
+	unsigned int count = 0;
+	char delimiter;
+	unsigned int amr_octet_aligned;
+
+	memset(fmtp_param, 0, sizeof(*fmtp_param));
+
+	str = talloc_zero_size(ctx, strlen(sdp) + 1);
+	str_ptr = str;
+	strcpy(str_ptr, sdp);
+
+	/* Check if the input string begins with an fmtp token */
+	str_ptr = strstr(str_ptr, "fmtp:");
+	if (!str_ptr)
+		goto exit;
+	str_ptr += 5;
+
+	/* Extract payload type */
+	if (sscanf(str_ptr, "%u ", &pt) != 1)
+		goto error;
+	fmtp_param->payload_type = pt;
+
+	/* Advance pointer to the beginning of the parameter section and
+	 * tokenize string */
+	str_ptr = strstr(str_ptr, " ");
+	if (!str_ptr)
+		goto error;
+	str_ptr++;
+
+	param_str = strtok(str_ptr, " ");
+	if (!param_str)
+		goto exit;
+
+	while (1) {
+		/* Make sure that we don't get trapped in an endless loop */
+		if (count > 256)
+			goto error;
+
+		/* Chop off delimiters ';' at the end */
+		delimiter = str_ptr[strlen(str_ptr) - 1];
+		if (delimiter == ';' || delimiter == ',')
+			str_ptr[strlen(str_ptr) - 1] = '\0';
+
+		/* AMR octet aligned parameter */
+		if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
+			fmtp_param->param.amr_octet_aligned_present = true;
+			fmtp_param->param.amr_octet_aligned = false;
+			if (amr_octet_aligned == 1)
+				fmtp_param->param.amr_octet_aligned = true;
+
+		}
+
+		param_str = strtok(NULL, " ");
+		if (!param_str)
+			break;
+		count++;
+	}
+
+exit:
+	talloc_free(str);
+	return 0;
+error:
+	talloc_free(str);
+	return -EINVAL;
+}
+
+/* Pick optional fmtp parameters by payload type, if there are no fmtp
+ * parameters, a nullpointer is returned */
+static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
+{
+	unsigned int i;
+
+	for (i = 0; i < fmtp_params_len; i++) {
+		if (fmtp_params[i].payload_type == pt)
+			return &fmtp_params[i].param;
+	}
+
+	return NULL;
+}
+
 /*! Analyze SDP input string.
  *  \param[in] endp trunk endpoint.
  *  \param[out] conn associated rtp connection.
@@ -181,6 +272,9 @@
 {
 	struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
 	unsigned int codecs_used = 0;
+	struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
+	unsigned int fmtp_used = 0;
+	struct mgcp_codec_param *codec_param;
 	char *line;
 	unsigned int i;
 	void *tmp_ctx = talloc_new(NULL);
@@ -225,6 +319,14 @@
 				rtp->maximum_packet_time = ptime2;
 				break;
 			}
+
+			else if (strncmp("a=fmtp:", line, 6) == 0) {
+				rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
+				if (rc >= 0)
+					fmtp_used++;
+				break;
+			}
+
 			break;
 		case 'm':
 			rc = sscanf(line, "m=audio %d RTP/AVP", &port);
@@ -266,7 +368,8 @@
 
 	/* Store parsed codec information */
 	for (i = 0; i < codecs_used; i++) {
-		rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line);
+		codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
+		rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
 		if (rc < 0)
 			LOGP(DLMGCP, LOGL_NOTICE, "endpoint:0x%x, failed to add codec\n", ENDPOINT_NUMBER(p->endp));
 	}
@@ -334,6 +437,64 @@
 	return 0;
 }
 
+/* Add fmtp strings to sdp payload */
+static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len,
+		    const char *fmtp_extra)
+{
+	unsigned int i;
+	int rc;
+	int fmtp_extra_pt = -1;
+	char *fmtp_extra_pars = "";
+
+	/* When no fmtp parameters ara available but an fmtp extra string
+	 * is configured, just add the fmtp extra string */
+	if (fmtp_params_len == 0 && fmtp_extra) {
+		return msgb_printf(sdp, "%s\r\n", fmtp_extra);
+	}
+
+	/* When there is fmtp extra configured we dissect it in order to drop
+	 * in the configured extra parameters at the right place when
+	 * generating the fmtp strings. */
+	if (fmtp_extra) {
+		if (sscanf(fmtp_extra, "a=fmtp:%d ", &fmtp_extra_pt) != 1)
+			fmtp_extra_pt = -1;
+
+		fmtp_extra_pars = strstr(fmtp_extra, " ");
+
+		if (!fmtp_extra_pars)
+			fmtp_extra_pars = "";
+		else
+			fmtp_extra_pars++;
+	}
+
+	for (i = 0; i < fmtp_params_len; i++) {
+		rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
+
+		/* Add amr octet align parameter */
+		if (fmtp_params[i].param.amr_octet_aligned_present) {
+			if (fmtp_params[i].param.amr_octet_aligned)
+				rc = msgb_printf(sdp, " octet-align=1");
+			else
+				rc = msgb_printf(sdp, " octet-align=0");
+			if (rc < 0)
+				return -EINVAL;
+		}
+
+		/* Append extra parameters from fmtp extra */
+		if (fmtp_params[i].payload_type == fmtp_extra_pt) {
+			rc = msgb_printf(sdp, " %s", fmtp_extra_pars);
+			if (rc < 0)
+				return -EINVAL;
+		}
+
+		rc = msgb_printf(sdp, "\r\n", fmtp_params[i].payload_type);
+		if (rc < 0)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
 /*! Generate SDP response string.
  *  \param[in] endp trunk endpoint.
  *  \param[in] conn associated rtp connection.
@@ -348,8 +509,11 @@
 	const char *fmtp_extra;
 	const char *audio_name;
 	int payload_type;
+	struct sdp_fmtp_param fmtp_param;
 	int rc;
 	int payload_types[1];
+	struct sdp_fmtp_param fmtp_params[1];
+        unsigned int fmtp_params_len = 0;
 
 	OSMO_ASSERT(endp);
 	OSMO_ASSERT(conn);
@@ -387,12 +551,15 @@
 				goto buffer_too_small;
 		}
 
-		if (fmtp_extra) {
-			rc = msgb_printf(sdp, "%s\r\n", fmtp_extra);
-
-			if (rc < 0)
-				goto buffer_too_small;
+		if (codec->param_present) {
+			fmtp_param.payload_type = payload_type;
+			fmtp_param.param = codec->param;
+			fmtp_params[0] = fmtp_param;
+			fmtp_params_len = 1;
 		}
+		rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra);
+		if (rc < 0)
+			goto buffer_too_small;
 	}
 	if (conn->end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
 		rc = msgb_printf(sdp, "a=ptime:%u\r\n",
diff --git a/tests/mgcp/mgcp_test.c b/tests/mgcp/mgcp_test.c
index 78ddcdc..be45598 100644
--- a/tests/mgcp/mgcp_test.c
+++ b/tests/mgcp/mgcp_test.c
@@ -467,6 +467,34 @@
 	"M: recvonly\r\n" \
 	"C: 2\r\n"
 
+#define CRCX_AMR_WITH_FMTP \
+	"CRCX 2 7 at mgw MGCP 1.0\r\n" \
+	"M: recvonly\r\n" \
+	"C: 2\r\n" \
+	"X\r\n" \
+	"L: p:20\r\n" \
+	"\r\n" \
+	"v=0\r\n" \
+	"c=IN IP4 123.12.12.123\r\n" \
+	"m=audio 5904 RTP/AVP 111\r\n" \
+	"a=rtpmap:111 AMR/8000/1\r\n" \
+	"a=ptime:20\r\n" \
+	"a=fmtp:111 mode-change-capability=2; octet-align=1\r\n" \
+
+#define CRCX_AMR_WITH_FMTP_RET \
+	"200 2 OK\r\n" \
+	"I: %s\r\n" \
+	"\r\n" \
+	"v=0\r\n" \
+	"o=- %s 23 IN IP4 0.0.0.0\r\n" \
+	"s=-\r\n" \
+	"c=IN IP4 0.0.0.0\r\n" \
+	"t=0 0\r\n" \
+	"m=audio 16012 RTP/AVP 111\r\n" \
+	"a=rtpmap:111 AMR/8000/1\r\n" \
+	"a=fmtp:111 octet-align=1\r\n" \
+	"a=ptime:20\r\n"
+
 #define CRCX_NO_LCO_NO_SDP_RET \
 	"200 2 OK\r\n" \
 	"I: %s\r\n" \
@@ -517,6 +545,7 @@
 	{"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
 	{"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
 	{"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
+	{"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},
 };
 
 static const struct mgcp_test retransmit[] = {
@@ -1246,7 +1275,7 @@
 
 	rtp = &conn->end;
 
-	OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1") == 0);
+	OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
 	rtp->codec = &rtp->codecs[0];
 
 	for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
diff --git a/tests/mgcp/mgcp_test.ok b/tests/mgcp/mgcp_test.ok
index 28e9aad..d21eaa1 100644
--- a/tests/mgcp/mgcp_test.ok
+++ b/tests/mgcp/mgcp_test.ok
@@ -459,6 +459,30 @@
 Testing CRCX
 creating message from statically defined input:
 ---------8<---------
+CRCX 2 7 at mgw MGCP 1.0
+M: recvonly
+C: 2
+X
+L: p:20
+
+v=0
+c=IN IP4 123.12.12.123
+m=audio 5904 RTP/AVP 111
+a=rtpmap:111 AMR/8000/1
+a=ptime:20
+a=fmtp:111 mode-change-capability=2; octet-align=1
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+(response contains a connection id)
+Dummy packets: 2
+
+================================================
+Testing CRCX
+creating message from statically defined input:
+---------8<---------
 CRCX 2 1 at mgw MGCP 1.0
 M: recvonly
 C: 2

-- 
To view, visit https://gerrit.osmocom.org/13159
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-mgw
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I622c01874b25f5049d4f59eb8157e0ea3cbe16ba
Gerrit-Change-Number: 13159
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier at sysmocom.de>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20190307/b17527f1/attachment.html>


More information about the gerrit-log mailing list