<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>