<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/13159">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Jenkins Builder: Verified
Harald Welte: Looks good to me, approved
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">AMR: Add function to convert between bw-effient and octet aligned mode<br><br>RFC3267 specifies two framing modes for AMR packets. An octet aligned<br>mode is specified where all fields of the AMR packets are aligned to<br>octet boundaries. The second framing mode is the bandwith efficient mode<br>where the fields are directly packed one after another.<br><br>- add paring/generation functions for related SDP fmtp parameters<br>- add conversion function to convert AMR payload<br><br>Depends: libosmo-netif I5b5a0fa644d8dbb1f04f9d7e35312683c7b3d196<br>Change-Id: I622c01874b25f5049d4f59eb8157e0ea3cbe16ba<br>Related: OS#3807<br>---<br>M TODO-RELEASE<br>M include/osmocom/mgcp/mgcp_codec.h<br>M include/osmocom/mgcp/mgcp_common.h<br>M include/osmocom/mgcp/mgcp_internal.h<br>M include/osmocom/mgcp_client/mgcp_client.h<br>M include/osmocom/mgcp_client/mgcp_client_fsm.h<br>M src/libosmo-mgcp-client/mgcp_client.c<br>M src/libosmo-mgcp-client/mgcp_client_fsm.c<br>M src/libosmo-mgcp/mgcp_codec.c<br>M src/libosmo-mgcp/mgcp_network.c<br>M src/libosmo-mgcp/mgcp_protocol.c<br>M src/libosmo-mgcp/mgcp_sdp.c<br>M tests/mgcp/mgcp_test.c<br>M tests/mgcp/mgcp_test.ok<br>14 files changed, 378 insertions(+), 21 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/TODO-RELEASE b/TODO-RELEASE</span><br><span>index c5a3b36..67a1b21 100644</span><br><span>--- a/TODO-RELEASE</span><br><span>+++ b/TODO-RELEASE</span><br><span>@@ -24,3 +24,4 @@</span><br><span> # If any interfaces have been removed or changed since the last public release, a=0.</span><br><span> #</span><br><span> #library what description / commit summary line</span><br><span style="color: hsl(120, 100%, 40%);">+libosmo-mgcp-client add struct members AMR SDP/fmtp parameter generation</span><br><span>\ No newline at end of file</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_codec.h b/include/osmocom/mgcp/mgcp_codec.h</span><br><span>index 334913b..2bbb86e 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_codec.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_codec.h</span><br><span>@@ -2,6 +2,6 @@</span><br><span> </span><br><span> void mgcp_codec_summary(struct mgcp_conn_rtp *conn);</span><br><span> void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);</span><br><span style="color: hsl(0, 100%, 40%);">-int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name);</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, struct mgcp_codec_param *param);</span><br><span> int mgcp_codec_decide(struct mgcp_conn_rtp *conn);</span><br><span> int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_common.h b/include/osmocom/mgcp/mgcp_common.h</span><br><span>index a658f1c..75d5a37 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_common.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_common.h</span><br><span>@@ -57,6 +57,12 @@</span><br><span> MGCP_X_OSMO_IGN_CALLID = 1,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Codec parameters (communicated via SDP/fmtp) */</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_codec_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ bool amr_octet_aligned_present;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool amr_octet_aligned;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Ensure that the msg->l2h is NUL terminated. */</span><br><span> static inline int mgcp_msg_terminate_nul(struct msgb *msg)</span><br><span> {</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_internal.h b/include/osmocom/mgcp/mgcp_internal.h</span><br><span>index 35b535a..ec94584 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_internal.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_internal.h</span><br><span>@@ -95,6 +95,9 @@</span><br><span> int payload_type;</span><br><span> char *audio_name;</span><br><span> char *subtype_name;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ bool param_present;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_codec_param param;</span><br><span> };</span><br><span> </span><br><span> /* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */</span><br><span>diff --git a/include/osmocom/mgcp_client/mgcp_client.h b/include/osmocom/mgcp_client/mgcp_client.h</span><br><span>index 5650fc2..ac3e2b1 100644</span><br><span>--- a/include/osmocom/mgcp_client/mgcp_client.h</span><br><span>+++ b/include/osmocom/mgcp_client/mgcp_client.h</span><br><span>@@ -78,7 +78,7 @@</span><br><span> enum mgcp_codecs codecs[MGCP_MAX_CODECS];</span><br><span> unsigned int codecs_len;</span><br><span> struct ptmap ptmap[MGCP_MAX_CODECS];</span><br><span style="color: hsl(0, 100%, 40%);">- unsigned int ptmap_len; </span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int ptmap_len;</span><br><span> };</span><br><span> </span><br><span> enum mgcp_verb {</span><br><span>@@ -113,6 +113,8 @@</span><br><span> struct ptmap ptmap[MGCP_MAX_CODECS];</span><br><span> unsigned int ptmap_len;</span><br><span> uint32_t x_osmo_ign;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool param_present;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_codec_param param;</span><br><span> };</span><br><span> </span><br><span> void mgcp_client_conf_init(struct mgcp_client_conf *conf);</span><br><span>diff --git a/include/osmocom/mgcp_client/mgcp_client_fsm.h b/include/osmocom/mgcp_client/mgcp_client_fsm.h</span><br><span>index 716a6d4..dabfcca 100644</span><br><span>--- a/include/osmocom/mgcp_client/mgcp_client_fsm.h</span><br><span>+++ b/include/osmocom/mgcp_client/mgcp_client_fsm.h</span><br><span>@@ -51,6 +51,11 @@</span><br><span> /*! If left MGCP_CONN_NONE, use MGCP_CONN_RECV_ONLY or MGCP_CONN_RECV_SEND, depending on whether an audio RTP</span><br><span> * address is set. If != MGCP_CONN_NONE, force this conn mode. */</span><br><span> enum mgcp_connection_mode conn_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! If the codec requires additional format parameters (fmtp), those cann be set here, see also</span><br><span style="color: hsl(120, 100%, 40%);">+ * mgcp_common.h */</span><br><span style="color: hsl(120, 100%, 40%);">+ bool param_present;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_codec_param param;</span><br><span> };</span><br><span> </span><br><span> struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,</span><br><span>diff --git a/src/libosmo-mgcp-client/mgcp_client.c b/src/libosmo-mgcp-client/mgcp_client.c</span><br><span>index ead3512..88e5dab 100644</span><br><span>--- a/src/libosmo-mgcp-client/mgcp_client.c</span><br><span>+++ b/src/libosmo-mgcp-client/mgcp_client.c</span><br><span>@@ -1051,6 +1051,20 @@</span><br><span> }</span><br><span> rc += msgb_printf(msg, "\r\n");</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add optional codec parameters (fmtp) */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (mgcp_msg->param_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < mgcp_msg->codecs_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The following is only applicable for AMR */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (mgcp_msg->codecs[i] != CODEC_AMR_8000_1 && mgcp_msg->codecs[i] != CODEC_AMRWB_16000_1)</span><br><span style="color: hsl(120, 100%, 40%);">+ continue;</span><br><span style="color: hsl(120, 100%, 40%);">+ pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned)</span><br><span style="color: hsl(120, 100%, 40%);">+ rc += msgb_printf(msg, "a=fmtp:%u octet-align=1\r\n", pt);</span><br><span style="color: hsl(120, 100%, 40%);">+ else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned)</span><br><span style="color: hsl(120, 100%, 40%);">+ rc += msgb_printf(msg, "a=fmtp:%u octet-align=0\r\n", pt);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> for (i = 0; i < mgcp_msg->codecs_len; i++) {</span><br><span> pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);</span><br><span> </span><br><span>diff --git a/src/libosmo-mgcp-client/mgcp_client_fsm.c b/src/libosmo-mgcp-client/mgcp_client_fsm.c</span><br><span>index 7c4e081..71f4310 100644</span><br><span>--- a/src/libosmo-mgcp-client/mgcp_client_fsm.c</span><br><span>+++ b/src/libosmo-mgcp-client/mgcp_client_fsm.c</span><br><span>@@ -114,11 +114,13 @@</span><br><span> .conn_mode = MGCP_CONN_RECV_ONLY,</span><br><span> .ptime = info->ptime,</span><br><span> .codecs_len = info->codecs_len,</span><br><span style="color: hsl(0, 100%, 40%);">- .ptmap_len = info->ptmap_len</span><br><span style="color: hsl(120, 100%, 40%);">+ .ptmap_len = info->ptmap_len,</span><br><span style="color: hsl(120, 100%, 40%);">+ .param_present = info->param_present</span><br><span> };</span><br><span> osmo_strlcpy(mgcp_msg->endpoint, info->endpoint, MGCP_ENDPOINT_MAXLEN);</span><br><span> memcpy(mgcp_msg->codecs, info->codecs, sizeof(mgcp_msg->codecs));</span><br><span> memcpy(mgcp_msg->ptmap, info->ptmap, sizeof(mgcp_msg->ptmap));</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(&mgcp_msg->param, &info->param, sizeof(mgcp_msg->param));</span><br><span> </span><br><span> if (info->x_osmo_ign) {</span><br><span> mgcp_msg->x_osmo_ign = info->x_osmo_ign;</span><br><span>@@ -156,11 +158,13 @@</span><br><span> .audio_port = mgcp_ctx->conn_peer_local.port,</span><br><span> .ptime = mgcp_ctx->conn_peer_local.ptime,</span><br><span> .codecs_len = mgcp_ctx->conn_peer_local.codecs_len,</span><br><span style="color: hsl(0, 100%, 40%);">- .ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len</span><br><span style="color: hsl(120, 100%, 40%);">+ .ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len,</span><br><span style="color: hsl(120, 100%, 40%);">+ .param_present = mgcp_ctx->conn_peer_local.param_present</span><br><span> };</span><br><span> osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);</span><br><span> memcpy(mgcp_msg.codecs, mgcp_ctx->conn_peer_local.codecs, sizeof(mgcp_msg.codecs));</span><br><span> memcpy(mgcp_msg.ptmap, mgcp_ctx->conn_peer_local.ptmap, sizeof(mgcp_msg.ptmap));</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(&mgcp_msg.param, &mgcp_ctx->conn_peer_local.param, sizeof(mgcp_ctx->conn_peer_local.param));</span><br><span> </span><br><span> set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);</span><br><span> </span><br><span>diff --git a/src/libosmo-mgcp/mgcp_codec.c b/src/libosmo-mgcp/mgcp_codec.c</span><br><span>index 55be554..933284d 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_codec.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_codec.c</span><br><span>@@ -100,8 +100,8 @@</span><br><span> }</span><br><span> </span><br><span> /* Set members of struct mgcp_rtp_codec, extrapolate in missing information */</span><br><span style="color: hsl(0, 100%, 40%);">-static int codec_set(void *ctx, struct mgcp_rtp_codec *codec,</span><br><span style="color: hsl(0, 100%, 40%);">- int payload_type, const char *audio_name, unsigned int pt_offset)</span><br><span style="color: hsl(120, 100%, 40%);">+static int codec_set(void *ctx, struct mgcp_rtp_codec *codec, int payload_type, const char *audio_name,</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int pt_offset, struct mgcp_codec_param *param)</span><br><span> {</span><br><span> int rate;</span><br><span> int channels;</span><br><span>@@ -219,6 +219,13 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Copy over optional codec parameters */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (param) {</span><br><span style="color: hsl(120, 100%, 40%);">+ codec->param = *param;</span><br><span style="color: hsl(120, 100%, 40%);">+ codec->param_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else</span><br><span style="color: hsl(120, 100%, 40%);">+ codec->param_present = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> return 0;</span><br><span> error:</span><br><span> /* Make sure we leave a clean codec entry on error. */</span><br><span>@@ -233,8 +240,9 @@</span><br><span> * \param[out] conn related rtp-connection.</span><br><span> * \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined).</span><br><span> * \param[in] audio_name audio codec name (e.g. "GSM/8000/1").</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] param optional codec parameters (set to NULL when unused).</span><br><span> * \returns 0 on success, -EINVAL on failure. */</span><br><span style="color: hsl(0, 100%, 40%);">-int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name)</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, struct mgcp_codec_param *param)</span><br><span> {</span><br><span> int rc;</span><br><span> </span><br><span>@@ -244,7 +252,7 @@</span><br><span> return -EINVAL;</span><br><span> </span><br><span> rc = codec_set(conn->conn, &conn->end.codecs[conn->end.codecs_assigned], payload_type, audio_name,</span><br><span style="color: hsl(0, 100%, 40%);">- conn->end.codecs_assigned);</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->end.codecs_assigned, param);</span><br><span> if (rc != 0)</span><br><span> return -EINVAL;</span><br><span> </span><br><span>diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c</span><br><span>index e4fd7c0..2c6c571 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_network.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_network.c</span><br><span>@@ -34,6 +34,7 @@</span><br><span> #include <osmocom/core/socket.h></span><br><span> #include <osmocom/core/byteswap.h></span><br><span> #include <osmocom/netif/rtp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/netif/amr.h></span><br><span> #include <osmocom/mgcp/mgcp.h></span><br><span> #include <osmocom/mgcp/mgcp_common.h></span><br><span> #include <osmocom/mgcp/mgcp_internal.h></span><br><span>@@ -684,6 +685,86 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* For AMR RTP two framing modes are defined RFC3267. There is a bandwith</span><br><span style="color: hsl(120, 100%, 40%);">+ * efficient encoding scheme where all fields are packed together one after</span><br><span style="color: hsl(120, 100%, 40%);">+ * another and an octet aligned mode where all fields are aligned to octet</span><br><span style="color: hsl(120, 100%, 40%);">+ * boundaries. This function is used to convert between the two modes */</span><br><span style="color: hsl(120, 100%, 40%);">+static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, char *data, int *len,</span><br><span style="color: hsl(120, 100%, 40%);">+ bool target_is_oa)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* NOTE: *data has an overall length of RTP_BUF_SIZE, so there is</span><br><span style="color: hsl(120, 100%, 40%);">+ * plenty of space available to store the slightly larger, converted</span><br><span style="color: hsl(120, 100%, 40%);">+ * data */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct rtp_hdr *rtp_hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int payload_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(*len >= sizeof(struct rtp_hdr));</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp_hdr = (struct rtp_hdr *)data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ payload_len = *len - sizeof(struct rtp_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (osmo_amr_is_oa(rtp_hdr->data, payload_len)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!target_is_oa)</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Input data is oa an target format is bwe</span><br><span style="color: hsl(120, 100%, 40%);">+ * ==> convert */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_amr_oa_to_bwe(rtp_hdr->data, payload_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Input data is already bew, but we accept it anyway</span><br><span style="color: hsl(120, 100%, 40%);">+ * ==> no conversion needed */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = payload_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (target_is_oa)</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Input data is bwe an target format is oa</span><br><span style="color: hsl(120, 100%, 40%);">+ * ==> convert */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_amr_bwe_to_oa(rtp_hdr->data, payload_len,</span><br><span style="color: hsl(120, 100%, 40%);">+ RTP_BUF_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Input data is already oa, but we accept it anyway</span><br><span style="color: hsl(120, 100%, 40%);">+ * ==> no conversion needed */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = payload_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DRTP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+ "endpoint:0x%x AMR RTP packet conversion failed\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ENDPOINT_NUMBER(endp));</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ *len = rc + sizeof(struct rtp_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Check if a conversion between octet-aligned and bandwith-efficient mode is</span><br><span style="color: hsl(120, 100%, 40%);">+ * indicated. */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool amr_oa_bwe_convert_indicated(struct mgcp_rtp_codec *codec)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (codec->param_present == false)</span><br><span style="color: hsl(120, 100%, 40%);">+ return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!codec->param.amr_octet_aligned_present)</span><br><span style="color: hsl(120, 100%, 40%);">+ return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (strcmp(codec->subtype_name, "AMR") != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Check if a given RTP with AMR payload for octet-aligned mode */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool amr_oa_check(char *data, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct rtp_hdr *rtp_hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int payload_len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(len >= sizeof(struct rtp_hdr));</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp_hdr = (struct rtp_hdr *)data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ payload_len = len - sizeof(struct rtp_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return osmo_amr_is_oa(rtp_hdr->data, payload_len);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Forward data to a debug tap. This is debug function that is intended for</span><br><span> * debugging the voice traffic with tools like gstreamer */</span><br><span> static void forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf,</span><br><span>@@ -792,7 +873,11 @@</span><br><span> mgcp_patch_and_count(endp, rtp_state, rtp_end,</span><br><span> addr, buf, buflen);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (rtp_end->rfc5993_hr_convert</span><br><span style="color: hsl(120, 100%, 40%);">+ if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ amr_oa_bwe_convert(endp, buf, &buflen,</span><br><span style="color: hsl(120, 100%, 40%);">+ conn_dst->end.codec->param.amr_octet_aligned);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ else if (rtp_end->rfc5993_hr_convert</span><br><span> && strcmp(conn_src->end.codec->subtype_name,</span><br><span> "GSM-HR-08") == 0)</span><br><span> rfc5993_hr_convert(endp, buf, &buflen);</span><br><span>@@ -1302,6 +1387,15 @@</span><br><span> len, conn_src, conn_src);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* If AMR is configured for the ingress connection a conversion of the</span><br><span style="color: hsl(120, 100%, 40%);">+ * framing mode (octet-aligned vs. bandwith-efficient is explicitly</span><br><span style="color: hsl(120, 100%, 40%);">+ * define, then we check if the incoming payload matches that</span><br><span style="color: hsl(120, 100%, 40%);">+ * expectation. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (amr_oa_bwe_convert_indicated(conn_src->end.codec)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (amr_oa_check(buf, len) != conn_src->end.codec->param.amr_octet_aligned)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Execute endpoint specific implementation that handles the</span><br><span> * dispatching of the RTP data */</span><br><span> return endp->type->dispatch_rtp_cb(proto, &addr, buf, len,</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c</span><br><span>index 82db02f..4121b9f 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_protocol.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_protocol.c</span><br><span>@@ -724,7 +724,7 @@</span><br><span> /* When no SDP is available, we use the codec information from</span><br><span> * the local connection options (if present) */</span><br><span> mgcp_codec_reset_all(conn);</span><br><span style="color: hsl(0, 100%, 40%);">- rc = mgcp_codec_add(conn, PTYPE_UNDEFINED, endp->local_options.codec);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = mgcp_codec_add(conn, PTYPE_UNDEFINED, endp->local_options.codec, NULL);</span><br><span> if (rc != 0)</span><br><span> goto error;</span><br><span> }</span><br><span>@@ -735,7 +735,7 @@</span><br><span> * than it makes sense to pick a sane default: (payload-type 0,</span><br><span> * PCMU), see also: OS#2658 */</span><br><span> mgcp_codec_reset_all(conn);</span><br><span style="color: hsl(0, 100%, 40%);">- rc = mgcp_codec_add(conn, 0, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = mgcp_codec_add(conn, 0, NULL, NULL);</span><br><span> if (rc != 0)</span><br><span> goto error;</span><br><span> }</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_sdp.c b/src/libosmo-mgcp/mgcp_sdp.c</span><br><span>index 3287cd1..02b9695 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_sdp.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_sdp.c</span><br><span>@@ -30,9 +30,9 @@</span><br><span> </span><br><span> #include <errno.h></span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* A struct to store intermediate parsing results. The function</span><br><span style="color: hsl(0, 100%, 40%);">- * mgcp_parse_sdp_data() is using it as temporary storage for parsing the SDP</span><br><span style="color: hsl(0, 100%, 40%);">- * codec information. */</span><br><span style="color: hsl(120, 100%, 40%);">+/* Two structs to store intermediate parsing results. The function</span><br><span style="color: hsl(120, 100%, 40%);">+ * mgcp_parse_sdp_data() is using the following two structs as temporary</span><br><span style="color: hsl(120, 100%, 40%);">+ * storage for parsing the SDP codec information. */</span><br><span> struct sdp_rtp_map {</span><br><span> /* the type */</span><br><span> int payload_type;</span><br><span>@@ -44,6 +44,11 @@</span><br><span> int rate;</span><br><span> int channels;</span><br><span> };</span><br><span style="color: hsl(120, 100%, 40%);">+struct sdp_fmtp_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ int payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_codec_param param;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> </span><br><span> /* Helper function to extrapolate missing codec parameters in a codec mao from</span><br><span> * an already filled in payload_type, called from: mgcp_parse_sdp_data() */</span><br><span>@@ -168,6 +173,92 @@</span><br><span> return -EINVAL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Extract fmtp parameters from SDP, called from: mgcp_parse_sdp_data() */</span><br><span style="color: hsl(120, 100%, 40%);">+static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ char *str;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *str_ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *param_str;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int pt;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ char delimiter;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int amr_octet_aligned;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(fmtp_param, 0, sizeof(*fmtp_param));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ str = talloc_zero_size(ctx, strlen(sdp) + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ str_ptr = str;</span><br><span style="color: hsl(120, 100%, 40%);">+ strcpy(str_ptr, sdp);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check if the input string begins with an fmtp token */</span><br><span style="color: hsl(120, 100%, 40%);">+ str_ptr = strstr(str_ptr, "fmtp:");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!str_ptr)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto exit;</span><br><span style="color: hsl(120, 100%, 40%);">+ str_ptr += 5;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Extract payload type */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sscanf(str_ptr, "%u ", &pt) != 1)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto error;</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_param->payload_type = pt;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Advance pointer to the beginning of the parameter section and</span><br><span style="color: hsl(120, 100%, 40%);">+ * tokenize string */</span><br><span style="color: hsl(120, 100%, 40%);">+ str_ptr = strstr(str_ptr, " ");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!str_ptr)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto error;</span><br><span style="color: hsl(120, 100%, 40%);">+ str_ptr++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ param_str = strtok(str_ptr, " ");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!param_str)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto exit;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while (1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Make sure that we don't get trapped in an endless loop */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (count > 256)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto error;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Chop off delimiters ';' at the end */</span><br><span style="color: hsl(120, 100%, 40%);">+ delimiter = str_ptr[strlen(str_ptr) - 1];</span><br><span style="color: hsl(120, 100%, 40%);">+ if (delimiter == ';' || delimiter == ',')</span><br><span style="color: hsl(120, 100%, 40%);">+ str_ptr[strlen(str_ptr) - 1] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* AMR octet aligned parameter */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_param->param.amr_octet_aligned_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_param->param.amr_octet_aligned = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (amr_octet_aligned == 1)</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_param->param.amr_octet_aligned = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ param_str = strtok(NULL, " ");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!param_str)</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ count++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+exit:</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(str);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+error:</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(str);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Pick optional fmtp parameters by payload type, if there are no fmtp</span><br><span style="color: hsl(120, 100%, 40%);">+ * parameters, a nullpointer is returned */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < fmtp_params_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (fmtp_params[i].payload_type == pt)</span><br><span style="color: hsl(120, 100%, 40%);">+ return &fmtp_params[i].param;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Analyze SDP input string.</span><br><span> * \param[in] endp trunk endpoint.</span><br><span> * \param[out] conn associated rtp connection.</span><br><span>@@ -181,6 +272,9 @@</span><br><span> {</span><br><span> struct sdp_rtp_map codecs[MGCP_MAX_CODECS];</span><br><span> unsigned int codecs_used = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int fmtp_used = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_codec_param *codec_param;</span><br><span> char *line;</span><br><span> unsigned int i;</span><br><span> void *tmp_ctx = talloc_new(NULL);</span><br><span>@@ -225,6 +319,14 @@</span><br><span> rtp->maximum_packet_time = ptime2;</span><br><span> break;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (strncmp("a=fmtp:", line, 6) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc >= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_used++;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> break;</span><br><span> case 'm':</span><br><span> rc = sscanf(line, "m=audio %d RTP/AVP", &port);</span><br><span>@@ -266,7 +368,8 @@</span><br><span> </span><br><span> /* Store parsed codec information */</span><br><span> for (i = 0; i < codecs_used; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">- rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line);</span><br><span style="color: hsl(120, 100%, 40%);">+ codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);</span><br><span> if (rc < 0)</span><br><span> LOGP(DLMGCP, LOGL_NOTICE, "endpoint:0x%x, failed to add codec\n", ENDPOINT_NUMBER(p->endp));</span><br><span> }</span><br><span>@@ -334,6 +437,64 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Add fmtp strings to sdp payload */</span><br><span style="color: hsl(120, 100%, 40%);">+static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *fmtp_extra)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ int fmtp_extra_pt = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *fmtp_extra_pars = "";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* When no fmtp parameters ara available but an fmtp extra string</span><br><span style="color: hsl(120, 100%, 40%);">+ * is configured, just add the fmtp extra string */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (fmtp_params_len == 0 && fmtp_extra) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return msgb_printf(sdp, "%s\r\n", fmtp_extra);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* When there is fmtp extra configured we dissect it in order to drop</span><br><span style="color: hsl(120, 100%, 40%);">+ * in the configured extra parameters at the right place when</span><br><span style="color: hsl(120, 100%, 40%);">+ * generating the fmtp strings. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (fmtp_extra) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sscanf(fmtp_extra, "a=fmtp:%d ", &fmtp_extra_pt) != 1)</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_extra_pt = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_extra_pars = strstr(fmtp_extra, " ");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!fmtp_extra_pars)</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_extra_pars = "";</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_extra_pars++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < fmtp_params_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add amr octet align parameter */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (fmtp_params[i].param.amr_octet_aligned_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (fmtp_params[i].param.amr_octet_aligned)</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = msgb_printf(sdp, " octet-align=1");</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = msgb_printf(sdp, " octet-align=0");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Append extra parameters from fmtp extra */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (fmtp_params[i].payload_type == fmtp_extra_pt) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = msgb_printf(sdp, " %s", fmtp_extra_pars);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = msgb_printf(sdp, "\r\n", fmtp_params[i].payload_type);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Generate SDP response string.</span><br><span> * \param[in] endp trunk endpoint.</span><br><span> * \param[in] conn associated rtp connection.</span><br><span>@@ -348,8 +509,11 @@</span><br><span> const char *fmtp_extra;</span><br><span> const char *audio_name;</span><br><span> int payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sdp_fmtp_param fmtp_param;</span><br><span> int rc;</span><br><span> int payload_types[1];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sdp_fmtp_param fmtp_params[1];</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int fmtp_params_len = 0;</span><br><span> </span><br><span> OSMO_ASSERT(endp);</span><br><span> OSMO_ASSERT(conn);</span><br><span>@@ -387,12 +551,15 @@</span><br><span> goto buffer_too_small;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (fmtp_extra) {</span><br><span style="color: hsl(0, 100%, 40%);">- rc = msgb_printf(sdp, "%s\r\n", fmtp_extra);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc < 0)</span><br><span style="color: hsl(0, 100%, 40%);">- goto buffer_too_small;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (codec->param_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_param.payload_type = payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_param.param = codec->param;</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_params[0] = fmtp_param;</span><br><span style="color: hsl(120, 100%, 40%);">+ fmtp_params_len = 1;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto buffer_too_small;</span><br><span> }</span><br><span> if (conn->end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {</span><br><span> rc = msgb_printf(sdp, "a=ptime:%u\r\n",</span><br><span>diff --git a/tests/mgcp/mgcp_test.c b/tests/mgcp/mgcp_test.c</span><br><span>index 78ddcdc..be45598 100644</span><br><span>--- a/tests/mgcp/mgcp_test.c</span><br><span>+++ b/tests/mgcp/mgcp_test.c</span><br><span>@@ -467,6 +467,34 @@</span><br><span> "M: recvonly\r\n" \</span><br><span> "C: 2\r\n"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define CRCX_AMR_WITH_FMTP \</span><br><span style="color: hsl(120, 100%, 40%);">+ "CRCX 2 7@mgw MGCP 1.0\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "M: recvonly\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "C: 2\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "X\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "L: p:20\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "v=0\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "c=IN IP4 123.12.12.123\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "m=audio 5904 RTP/AVP 111\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "a=rtpmap:111 AMR/8000/1\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "a=ptime:20\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "a=fmtp:111 mode-change-capability=2; octet-align=1\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CRCX_AMR_WITH_FMTP_RET \</span><br><span style="color: hsl(120, 100%, 40%);">+ "200 2 OK\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "I: %s\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "v=0\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "s=-\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "c=IN IP4 0.0.0.0\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "t=0 0\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "m=audio 16012 RTP/AVP 111\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "a=rtpmap:111 AMR/8000/1\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "a=fmtp:111 octet-align=1\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+ "a=ptime:20\r\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #define CRCX_NO_LCO_NO_SDP_RET \</span><br><span> "200 2 OK\r\n" \</span><br><span> "I: %s\r\n" \</span><br><span>@@ -517,6 +545,7 @@</span><br><span> {"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},</span><br><span> {"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},</span><br><span> {"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},</span><br><span style="color: hsl(120, 100%, 40%);">+ {"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},</span><br><span> };</span><br><span> </span><br><span> static const struct mgcp_test retransmit[] = {</span><br><span>@@ -1246,7 +1275,7 @@</span><br><span> </span><br><span> rtp = &conn->end;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1") == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);</span><br><span> rtp->codec = &rtp->codecs[0];</span><br><span> </span><br><span> for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {</span><br><span>diff --git a/tests/mgcp/mgcp_test.ok b/tests/mgcp/mgcp_test.ok</span><br><span>index 28e9aad..d21eaa1 100644</span><br><span>--- a/tests/mgcp/mgcp_test.ok</span><br><span>+++ b/tests/mgcp/mgcp_test.ok</span><br><span>@@ -459,6 +459,30 @@</span><br><span> Testing CRCX</span><br><span> creating message from statically defined input:</span><br><span> ---------8<---------</span><br><span style="color: hsl(120, 100%, 40%);">+CRCX 2 7@mgw MGCP 1.0
</span><br><span style="color: hsl(120, 100%, 40%);">+M: recvonly
</span><br><span style="color: hsl(120, 100%, 40%);">+C: 2
</span><br><span style="color: hsl(120, 100%, 40%);">+X
</span><br><span style="color: hsl(120, 100%, 40%);">+L: p:20
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+v=0
</span><br><span style="color: hsl(120, 100%, 40%);">+c=IN IP4 123.12.12.123
</span><br><span style="color: hsl(120, 100%, 40%);">+m=audio 5904 RTP/AVP 111
</span><br><span style="color: hsl(120, 100%, 40%);">+a=rtpmap:111 AMR/8000/1
</span><br><span style="color: hsl(120, 100%, 40%);">+a=ptime:20
</span><br><span style="color: hsl(120, 100%, 40%);">+a=fmtp:111 mode-change-capability=2; octet-align=1
</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+---------8<---------</span><br><span style="color: hsl(120, 100%, 40%);">+checking response:</span><br><span style="color: hsl(120, 100%, 40%);">+using message with patched conn_id for comparison</span><br><span style="color: hsl(120, 100%, 40%);">+Response matches our expectations.</span><br><span style="color: hsl(120, 100%, 40%);">+(response contains a connection id)</span><br><span style="color: hsl(120, 100%, 40%);">+Dummy packets: 2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+================================================</span><br><span style="color: hsl(120, 100%, 40%);">+Testing CRCX</span><br><span style="color: hsl(120, 100%, 40%);">+creating message from statically defined input:</span><br><span style="color: hsl(120, 100%, 40%);">+---------8<---------</span><br><span> CRCX 2 1@mgw MGCP 1.0
</span><br><span> M: recvonly
</span><br><span> C: 2
</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/13159">change 13159</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/13159"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmo-mgw </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I622c01874b25f5049d4f59eb8157e0ea3cbe16ba </div>
<div style="display:none"> Gerrit-Change-Number: 13159 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>