<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/9648">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">mgw: clean up codec negotiation (sdp)<br><br>The codec negotiation via SDP is currently in a neglected state. Also<br>osmo-mgw does some kind of codec decision wile the SDP is parsed, the<br>result is information for one codec, even when there are multiple codecs<br>negotiated. This is problematic because we loose all information about<br>alternate codecs while we parse. This should be untangled and the<br>information should be presevered. Also we are not really capable<br>picking a default. Wehen we do not supply any codec information (not<br>even LCO), then we should pick a sane default codec.<br><br>- separate the codec decision from the sdp parser and concentrate<br>  codec related code in a separate c file<br>- add support for multiple codecs in one SDP negotiation<br>- do not initalize "magic" codec defaults during conn allocation<br>- do not allow invalid payload types, especially not 255. When<br>  someone tries to select an invalid payload type, do not fail<br>  hard, just pick a sane default.<br>- handle the codec decision in protocol.c, pick a sane default<br>  codec when no (valid) codec has been negotiated (no LCO, no SDP)<br><br>Change-Id: If730d022ba6bdb217ad4e20b3fbbd1114dbb4b8f<br>Closes: OS#2658<br>Related: OS#3114<br>Related: OS#2728<br>---<br>M include/osmocom/mgcp/Makefile.am<br>A 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/mgcp_sdp.h<br>M src/libosmo-mgcp/Makefile.am<br>A src/libosmo-mgcp/mgcp_codec.c<br>M src/libosmo-mgcp/mgcp_conn.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 src/libosmo-mgcp/mgcp_vty.c<br>M tests/mgcp/mgcp_test.c<br>M tests/mgcp/mgcp_test.ok<br>14 files changed, 655 insertions(+), 247 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/mgcp/Makefile.am b/include/osmocom/mgcp/Makefile.am</span><br><span>index 7e297e4..65ca670 100644</span><br><span>--- a/include/osmocom/mgcp/Makefile.am</span><br><span>+++ b/include/osmocom/mgcp/Makefile.am</span><br><span>@@ -5,5 +5,6 @@</span><br><span>  mgcp_stat.h \</span><br><span>        mgcp_endp.h \</span><br><span>        mgcp_sdp.h \</span><br><span style="color: hsl(120, 100%, 40%);">+  mgcp_codec.h \</span><br><span>       debug.h \</span><br><span>    $(NULL)</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_codec.h b/include/osmocom/mgcp/mgcp_codec.h</span><br><span>new file mode 100644</span><br><span>index 0000000..f8d5e70</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/mgcp/mgcp_codec.h</span><br><span>@@ -0,0 +1,6 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_codec_summary(struct mgcp_conn_rtp *conn);</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);</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);</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_codec_decide(struct mgcp_conn_rtp *conn);</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_common.h b/include/osmocom/mgcp/mgcp_common.h</span><br><span>index d23339f..eb6564f 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_common.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_common.h</span><br><span>@@ -82,4 +82,8 @@</span><br><span> /* A prefix to denote the virtual trunk (RTP on both ends) */</span><br><span> #define MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK "rtpbridge/"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Maximal number of payload types / codecs that can be negotiated via SDP at</span><br><span style="color: hsl(120, 100%, 40%);">+ * at once. */</span><br><span style="color: hsl(120, 100%, 40%);">+#define MGCP_MAX_CODECS 10</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #endif</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_internal.h b/include/osmocom/mgcp/mgcp_internal.h</span><br><span>index bff7da0..b564905 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_internal.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_internal.h</span><br><span>@@ -114,12 +114,19 @@</span><br><span>         /* in network byte order */</span><br><span>  int rtp_port, rtcp_port;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    /* audio codec information */</span><br><span style="color: hsl(0, 100%, 40%);">-   struct mgcp_rtp_codec codec;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* currently selected audio codec */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_rtp_codec *codec;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* array with assigned audio codecs to choose from (SDP) */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* number of assigned audio codecs (SDP) */</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int codecs_assigned;</span><br><span> </span><br><span>    /* per endpoint data */</span><br><span>      int  frames_per_packet;</span><br><span>      uint32_t packet_duration_ms;</span><br><span style="color: hsl(120, 100%, 40%);">+  int maximum_packet_time; /* -1: not set */</span><br><span>   char *fmtp_extra;</span><br><span>    /* are we transmitting packets (1) or dropping (0) outbound packets */</span><br><span>       int output_enabled;</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_sdp.h b/include/osmocom/mgcp/mgcp_sdp.h</span><br><span>index 240f8cf..950092e 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_sdp.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_sdp.h</span><br><span>@@ -26,9 +26,6 @@</span><br><span>                     struct mgcp_conn_rtp *conn,</span><br><span>                  struct mgcp_parse_data *p);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,</span><br><span style="color: hsl(0, 100%, 40%);">-                 int payload_type, const char *audio_name);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,</span><br><span>                      const struct mgcp_conn_rtp *conn, struct msgb *sdp,</span><br><span>                          const char *addr);</span><br><span>diff --git a/src/libosmo-mgcp/Makefile.am b/src/libosmo-mgcp/Makefile.am</span><br><span>index a98c391..587bdd4 100644</span><br><span>--- a/src/libosmo-mgcp/Makefile.am</span><br><span>+++ b/src/libosmo-mgcp/Makefile.am</span><br><span>@@ -35,6 +35,7 @@</span><br><span>      mgcp_vty.c \</span><br><span>         mgcp_osmux.c \</span><br><span>       mgcp_sdp.c \</span><br><span style="color: hsl(120, 100%, 40%);">+  mgcp_codec.c \</span><br><span>       mgcp_msg.c \</span><br><span>         mgcp_conn.c \</span><br><span>        mgcp_stat.c \</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_codec.c b/src/libosmo-mgcp/mgcp_codec.c</span><br><span>new file mode 100644</span><br><span>index 0000000..2ce90dd</span><br><span>--- /dev/null</span><br><span>+++ b/src/libosmo-mgcp/mgcp_codec.c</span><br><span>@@ -0,0 +1,343 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2009-2015 by Holger Hans Peter Freyther <zecke@selfish.org></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2009-2014 by On-Waves</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</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%);">+#include <osmocom/mgcp/mgcp_internal.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_endp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Helper function to dump codec information of a specified codec to a printable</span><br><span style="color: hsl(120, 100%, 40%);">+ * string, used by dump_codec_summary() */</span><br><span style="color: hsl(120, 100%, 40%);">+static char *dump_codec(struct mgcp_rtp_codec *codec)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      static char str[256];</span><br><span style="color: hsl(120, 100%, 40%);">+ char *pt_str;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (codec->payload_type > 76)</span><br><span style="color: hsl(120, 100%, 40%);">+           pt_str = "DYNAMIC";</span><br><span style="color: hsl(120, 100%, 40%);">+ else if (codec->payload_type > 72)</span><br><span style="color: hsl(120, 100%, 40%);">+              pt_str = "RESERVED <!>";</span><br><span style="color: hsl(120, 100%, 40%);">+      else if (codec->payload_type != PTYPE_UNDEFINED)</span><br><span style="color: hsl(120, 100%, 40%);">+           pt_str = codec->subtype_name;</span><br><span style="color: hsl(120, 100%, 40%);">+      else</span><br><span style="color: hsl(120, 100%, 40%);">+          pt_str = "INVALID <!>";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     snprintf(str, sizeof(str), "(pt:%i=%s, audio:%s subt=%s, rate=%u, ch=%i, t=%u/%u)", codec->payload_type, pt_str,</span><br><span style="color: hsl(120, 100%, 40%);">+          codec->audio_name, codec->subtype_name, codec->rate, codec->channels, codec->frame_duration_num,</span><br><span style="color: hsl(120, 100%, 40%);">+               codec->frame_duration_den);</span><br><span style="color: hsl(120, 100%, 40%);">+       return str;</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%);">+/*! Dump a summary of all negotiated codecs to debug log</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] conn related rtp-connection. */</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_codec_summary(struct mgcp_conn_rtp *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct mgcp_rtp_end *rtp;</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_rtp_codec *codec;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_endpoint *endp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp = &conn->end;</span><br><span style="color: hsl(120, 100%, 40%);">+      endp = conn->conn->endp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rtp->codecs_assigned == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DLMGCP, LOGL_ERROR, "endpoint:0x%x conn:%s no codecs available\n", ENDPOINT_NUMBER(endp),</span><br><span style="color: hsl(120, 100%, 40%);">+                   mgcp_conn_dump(conn->conn));</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</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%);">+   /* Store parsed codec information */</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < rtp->codecs_assigned; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+            codec = &rtp->codecs[i];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DLMGCP, LOGL_DEBUG, "endpoint:0x%x conn:%s codecs[%u]:%s", ENDPOINT_NUMBER(endp),</span><br><span style="color: hsl(120, 100%, 40%);">+                   mgcp_conn_dump(conn->conn), i, dump_codec(codec));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          if (codec == rtp->codec)</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOGPC(DLMGCP, LOGL_DEBUG, " [selected]");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGPC(DLMGCP, LOGL_DEBUG, "\n");</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%);">+/* Initalize or reset codec information with default data. */</span><br><span style="color: hsl(120, 100%, 40%);">+void codec_init(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->subtype_name)</span><br><span style="color: hsl(120, 100%, 40%);">+           talloc_free(codec->subtype_name);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (codec->audio_name)</span><br><span style="color: hsl(120, 100%, 40%);">+             talloc_free(codec->audio_name);</span><br><span style="color: hsl(120, 100%, 40%);">+    memset(codec, 0, sizeof(*codec));</span><br><span style="color: hsl(120, 100%, 40%);">+     codec->payload_type = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+  codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;</span><br><span style="color: hsl(120, 100%, 40%);">+       codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;</span><br><span style="color: hsl(120, 100%, 40%);">+       codec->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;</span><br><span style="color: hsl(120, 100%, 40%);">+      codec->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;</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%);">+/*! Initalize or reset codec information with default data.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] conn related rtp-connection. */</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(conn->end.codecs, 0, sizeof(conn->end.codecs));</span><br><span style="color: hsl(120, 100%, 40%);">+  conn->end.codecs_assigned = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     conn->end.codec = NULL;</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%);">+/* Set members of struct mgcp_rtp_codec, extrapolate in missing information */</span><br><span style="color: hsl(120, 100%, 40%);">+static int codec_set(void *ctx, struct mgcp_rtp_codec *codec,</span><br><span style="color: hsl(120, 100%, 40%);">+                     int payload_type, const char *audio_name, unsigned int pt_offset)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int rate;</span><br><span style="color: hsl(120, 100%, 40%);">+     int channels;</span><br><span style="color: hsl(120, 100%, 40%);">+ char audio_codec[64];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Initalize the codec struct with some default data to begin with */</span><br><span style="color: hsl(120, 100%, 40%);">+ codec_init(codec);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (payload_type != PTYPE_UNDEFINED) {</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Make sure we do not get any reserved or undefined type numbers */</span><br><span style="color: hsl(120, 100%, 40%);">+          /* See also: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (payload_type == 1 || payload_type == 2 || payload_type == 19)</span><br><span style="color: hsl(120, 100%, 40%);">+                     goto error;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (payload_type >= 72 && payload_type <= 76)</span><br><span style="color: hsl(120, 100%, 40%);">+                   goto error;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (payload_type >= 127)</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%);">+         codec->payload_type = payload_type;</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 no audio name is given, we are forced to use the payload</span><br><span style="color: hsl(120, 100%, 40%);">+       * type to generate the audio name. This is only possible for</span><br><span style="color: hsl(120, 100%, 40%);">+  * non dynamic payload types, which are statically defined */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!audio_name) {</span><br><span style="color: hsl(120, 100%, 40%);">+            switch (payload_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+               case 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                       audio_name = talloc_strdup(ctx, "PCMU/8000/1");</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 3:</span><br><span style="color: hsl(120, 100%, 40%);">+                       audio_name = talloc_strdup(ctx, "GSM/8000/1");</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 8:</span><br><span style="color: hsl(120, 100%, 40%);">+                       audio_name = talloc_strdup(ctx, "PCMA/8000/1");</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 18:</span><br><span style="color: hsl(120, 100%, 40%);">+                      audio_name = talloc_strdup(ctx, "G729/8000/1");</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* The given payload type is not known to us, or it</span><br><span style="color: hsl(120, 100%, 40%);">+                    * it is a dynamic payload type for which we do not</span><br><span style="color: hsl(120, 100%, 40%);">+                    * know the audio name. We must give up here */</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%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Now we extract the codec subtype name, rate and channels. The latter</span><br><span style="color: hsl(120, 100%, 40%);">+        * two are optional. If they are not present we use the safe defaults</span><br><span style="color: hsl(120, 100%, 40%);">+  * above. */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (strlen(audio_name) > sizeof(audio_codec))</span><br><span style="color: hsl(120, 100%, 40%);">+              goto error;</span><br><span style="color: hsl(120, 100%, 40%);">+   channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;</span><br><span style="color: hsl(120, 100%, 40%);">+        rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (sscanf(audio_name, "%63[^/]/%d/%d", audio_codec, &rate, &channels) < 1)</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%);">+ /* Note: We only accept configurations with one audio channel! */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (channels != 1)</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%);">+ codec->rate = rate;</span><br><span style="color: hsl(120, 100%, 40%);">+        codec->channels = channels;</span><br><span style="color: hsl(120, 100%, 40%);">+        codec->subtype_name = talloc_strdup(ctx, audio_codec);</span><br><span style="color: hsl(120, 100%, 40%);">+     codec->audio_name = talloc_strdup(ctx, audio_name);</span><br><span style="color: hsl(120, 100%, 40%);">+        codec->payload_type = payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!strcmp(audio_codec, "G729")) {</span><br><span style="color: hsl(120, 100%, 40%);">+         codec->frame_duration_num = 10;</span><br><span style="color: hsl(120, 100%, 40%);">+            codec->frame_duration_den = 1000;</span><br><span style="color: hsl(120, 100%, 40%);">+  } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;</span><br><span style="color: hsl(120, 100%, 40%);">+               codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;</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%);">+   /* Derive the payload type if it is unknown */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (codec->payload_type == PTYPE_UNDEFINED) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            /* For the known codecs from the static range we restore</span><br><span style="color: hsl(120, 100%, 40%);">+               * the IANA or 3GPP assigned payload type number */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (codec->rate == 8000 && codec->channels == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* See also: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (!strcmp(codec->subtype_name, "GSM"))</span><br><span style="color: hsl(120, 100%, 40%);">+                         codec->payload_type = 3;</span><br><span style="color: hsl(120, 100%, 40%);">+                   else if (!strcmp(codec->subtype_name, "PCMA"))</span><br><span style="color: hsl(120, 100%, 40%);">+                           codec->payload_type = 8;</span><br><span style="color: hsl(120, 100%, 40%);">+                   else if (!strcmp(codec->subtype_name, "PCMU"))</span><br><span style="color: hsl(120, 100%, 40%);">+                           codec->payload_type = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                   else if (!strcmp(codec->subtype_name, "G729"))</span><br><span style="color: hsl(120, 100%, 40%);">+                           codec->payload_type = 18;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* See also: 3GPP TS 48.103, chapter 5.4.2.2 RTP Payload</span><br><span style="color: hsl(120, 100%, 40%);">+                       * Note: These are not fixed payload types as the IANA</span><br><span style="color: hsl(120, 100%, 40%);">+                         * defined once, they still remain dymanic payload</span><br><span style="color: hsl(120, 100%, 40%);">+                     * types, but with a payload type number preference. */</span><br><span style="color: hsl(120, 100%, 40%);">+                       else if (!strcmp(codec->subtype_name, "GSM-EFR"))</span><br><span style="color: hsl(120, 100%, 40%);">+                                codec->payload_type = 110;</span><br><span style="color: hsl(120, 100%, 40%);">+                 else if (!strcmp(codec->subtype_name, "GSM-HR-08"))</span><br><span style="color: hsl(120, 100%, 40%);">+                              codec->payload_type = 111;</span><br><span style="color: hsl(120, 100%, 40%);">+                 else if (!strcmp(codec->subtype_name, "AMR"))</span><br><span style="color: hsl(120, 100%, 40%);">+                            codec->payload_type = 112;</span><br><span style="color: hsl(120, 100%, 40%);">+                 else if (!strcmp(codec->subtype_name, "AMR-WB"))</span><br><span style="color: hsl(120, 100%, 40%);">+                         codec->payload_type = 113;</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%);">+           /* If we could not determine a payload type we assume that</span><br><span style="color: hsl(120, 100%, 40%);">+             * we are dealing with a codec from the dynamic range. We</span><br><span style="color: hsl(120, 100%, 40%);">+              * choose a fixed identifier from 96-109. (Note: normally,</span><br><span style="color: hsl(120, 100%, 40%);">+             * the dynamic payload type rante is from 96-127, but from</span><br><span style="color: hsl(120, 100%, 40%);">+             * 110 onwards 3gpp defines prefered codec types, which are</span><br><span style="color: hsl(120, 100%, 40%);">+            * also fixed, see above)  */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (codec->payload_type < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  codec->payload_type = 96 + pt_offset;</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (codec->payload_type > 109)</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%);">+     }</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%);">+error:</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Make sure we leave a clean codec entry on error. */</span><br><span style="color: hsl(120, 100%, 40%);">+        codec_init(codec);</span><br><span style="color: hsl(120, 100%, 40%);">+    memset(codec, 0, sizeof(*codec));</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%);">+/*! Add codec configuration depending on payload type and/or codec name. This</span><br><span style="color: hsl(120, 100%, 40%);">+ *  function uses the input parameters to extrapolate the full codec information.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] codec configuration (caller provided memory).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] conn related rtp-connection.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] audio_name audio codec name (e.g. "GSM/8000/1").</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success, -EINVAL on failure. */</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)</span><br><span style="color: hsl(120, 100%, 40%);">+{</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%);">+     /* The amount of codecs we can store is limited, make sure we do not</span><br><span style="color: hsl(120, 100%, 40%);">+   * overrun this limit. */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (conn->end.codecs_assigned >= MGCP_MAX_CODECS)</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%);">+     rc = codec_set(conn->conn, &conn->end.codecs[conn->end.codecs_assigned], payload_type, audio_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                      conn->end.codecs_assigned);</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%);">+     conn->end.codecs_assigned++;</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 the given codec is applicable on the specified endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+ * Helper function for mgcp_codec_decide() */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool is_codec_compatible(const struct mgcp_endpoint *endp, const struct mgcp_rtp_codec *codec)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  char codec_name[64];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* A codec name must be set, if not, this might mean that the codec</span><br><span style="color: hsl(120, 100%, 40%);">+    * (payload type) that was assigned is unknown to us so we must stop</span><br><span style="color: hsl(120, 100%, 40%);">+   * here. */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!codec->subtype_name)</span><br><span style="color: hsl(120, 100%, 40%);">+          return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* We now extract the codec_name (letters before the /, e.g. "GSM"</span><br><span style="color: hsl(120, 100%, 40%);">+   * from the audio name that is stored in the trunk configuration.</span><br><span style="color: hsl(120, 100%, 40%);">+      * We do not compare to the full audio_name because we expect that</span><br><span style="color: hsl(120, 100%, 40%);">+     * "GSM", "GSM/8000" and "GSM/8000/1" are all compatible when the</span><br><span style="color: hsl(120, 100%, 40%);">+        * audio name of the codec is set to "GSM" */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (sscanf(endp->tcfg->audio_name, "%63[^/]/%*d/%*d", codec_name) < 1)</span><br><span style="color: hsl(120, 100%, 40%);">+             return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Finally we check if the subtype_name we have generated from the</span><br><span style="color: hsl(120, 100%, 40%);">+     * audio_name in the trunc struct patches the codec_name of the</span><br><span style="color: hsl(120, 100%, 40%);">+        * given codec */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (strcasecmp(codec_name, codec->subtype_name) == 0)</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%);">+        /* FIXME: It is questinable that the method to pick a compatible</span><br><span style="color: hsl(120, 100%, 40%);">+       * codec can work properly. Since this useses tcfg->audio_name, as</span><br><span style="color: hsl(120, 100%, 40%);">+  * a reference, which is set to "AMR/8000" permanently.</span><br><span style="color: hsl(120, 100%, 40%);">+      * tcfg->audio_name must be updated by the first connection that</span><br><span style="color: hsl(120, 100%, 40%);">+    * has been made on an endpoint, so that the second connection</span><br><span style="color: hsl(120, 100%, 40%);">+         * can make a meaningful decision here */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return false;</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%);">+/*! Decide for one suitable codec</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] conn related rtp-connection.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success, -EINVAL on failure. */</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_codec_decide(struct mgcp_conn_rtp *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct mgcp_rtp_end *rtp;</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_endpoint *endp;</span><br><span style="color: hsl(120, 100%, 40%);">+   bool codec_assigned = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        endp = conn->conn->endp;</span><br><span style="color: hsl(120, 100%, 40%);">+        rtp = &conn->end;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* This function works on the results the SDP/LCO parser has extracted</span><br><span style="color: hsl(120, 100%, 40%);">+         * from the MGCP message. The goal is to select a suitable codec for</span><br><span style="color: hsl(120, 100%, 40%);">+   * the given connection. When transcoding is available, the first codec</span><br><span style="color: hsl(120, 100%, 40%);">+        * from the codec list is taken without further checking. When</span><br><span style="color: hsl(120, 100%, 40%);">+         * transcoding is not available, then the choice must be made more</span><br><span style="color: hsl(120, 100%, 40%);">+     * carefully. Each codec in the list is checked until one is found that</span><br><span style="color: hsl(120, 100%, 40%);">+        * is rated compatible. The rating is done by the helper function</span><br><span style="color: hsl(120, 100%, 40%);">+      * is_codec_compatible(), which does the actual checking. */</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < rtp->codecs_assigned; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+            /* When no transcoding is available, avoid codecs that would</span><br><span style="color: hsl(120, 100%, 40%);">+           * require transcoding. */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (endp->tcfg->no_audio_transcoding && !is_codec_compatible(endp, &rtp->codecs[i])) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOGP(DLMGCP, LOGL_NOTICE, "transcoding not available, skipping codec: %d/%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                          rtp->codecs[i].payload_type, rtp->codecs[i].subtype_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                 continue;</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%);">+           rtp->codec = &rtp->codecs[i];</span><br><span style="color: hsl(120, 100%, 40%);">+               codec_assigned = true;</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 style="color: hsl(120, 100%, 40%);">+   /* FIXME: To the reviewes: This is problematic. I do not get why we</span><br><span style="color: hsl(120, 100%, 40%);">+    * need to reset the packet_duration_ms depending on the codec</span><br><span style="color: hsl(120, 100%, 40%);">+         * selection. I thought it were all 20ms? Is this to address some</span><br><span style="color: hsl(120, 100%, 40%);">+      * cornercase. (This piece of code was in the code path before,</span><br><span style="color: hsl(120, 100%, 40%);">+        * together with the note: "TODO/XXX: Store this per codec and derive</span><br><span style="color: hsl(120, 100%, 40%);">+     * it on use" */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (codec_assigned) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (rtp->maximum_packet_time >= 0</span><br><span style="color: hsl(120, 100%, 40%);">+                   && rtp->maximum_packet_time * rtp->codec->frame_duration_den ></span><br><span style="color: hsl(120, 100%, 40%);">+                    rtp->codec->frame_duration_num * 1500)</span><br><span style="color: hsl(120, 100%, 40%);">+                      rtp->packet_duration_ms = 0;</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%);">+   return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_conn.c b/src/libosmo-mgcp/mgcp_conn.c</span><br><span>index 4926768..e49559c 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_conn.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_conn.c</span><br><span>@@ -25,6 +25,8 @@</span><br><span> #include <osmocom/mgcp/mgcp_internal.h></span><br><span> #include <osmocom/mgcp/mgcp_common.h></span><br><span> #include <osmocom/mgcp/mgcp_endp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_sdp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_codec.h></span><br><span> #include <osmocom/gsm/gsm_utils.h></span><br><span> #include <osmocom/core/rate_ctr.h></span><br><span> #include <ctype.h></span><br><span>@@ -88,22 +90,6 @@</span><br><span>      return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Reset codec state and free memory */</span><br><span style="color: hsl(0, 100%, 40%);">-static void mgcp_rtp_codec_init(struct mgcp_rtp_codec *codec)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        /* see also mgcp_sdp.c, mgcp_set_audio_info() */</span><br><span style="color: hsl(0, 100%, 40%);">-        talloc_free(codec->subtype_name);</span><br><span style="color: hsl(0, 100%, 40%);">-    talloc_free(codec->audio_name);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      codec->payload_type = -1;</span><br><span style="color: hsl(0, 100%, 40%);">-    codec->subtype_name = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-  codec->audio_name = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;</span><br><span style="color: hsl(0, 100%, 40%);">- codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;</span><br><span style="color: hsl(0, 100%, 40%);">- codec->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;</span><br><span style="color: hsl(0, 100%, 40%);">-        codec->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* Initialize rtp connection struct with default values */</span><br><span> static void mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)</span><br><span> {</span><br><span>@@ -130,13 +116,15 @@</span><br><span>       end->frames_per_packet = 0;  /* unknown */</span><br><span>        end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;</span><br><span>   end->output_enabled = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     mgcp_rtp_codec_init(&end->codec);</span><br><span style="color: hsl(120, 100%, 40%);">+      end->maximum_packet_time = -1;</span><br><span> </span><br><span>        conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index);</span><br><span>  conn_rtp->state.in_stream.err_ts_ctr = &conn_rtp->rate_ctr_group->ctr[IN_STREAM_ERR_TSTMP_CTR];</span><br><span>         conn_rtp->state.out_stream.err_ts_ctr = &conn_rtp->rate_ctr_group->ctr[OUT_STREAM_ERR_TSTMP_CTR];</span><br><span>       rate_ctr_index++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Make sure codec table is reset */</span><br><span style="color: hsl(120, 100%, 40%);">+  mgcp_codec_reset_all(conn_rtp);</span><br><span> }</span><br><span> </span><br><span> /* Cleanup rtp connection struct */</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c</span><br><span>index 2da37b4..b47b76c 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_network.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_network.c</span><br><span>@@ -310,7 +310,7 @@</span><br><span>                            ENDPOINT_NUMBER(endp), tsdelta,</span><br><span>                              inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));</span><br><span>                } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                        tsdelta = rtp_end->codec.rate * 20 / 1000;</span><br><span style="color: hsl(120, 100%, 40%);">+                 tsdelta = rtp_end->codec->rate * 20 / 1000;</span><br><span>                    LOGP(DRTP, LOGL_NOTICE,</span><br><span>                           "Fixed packet duration and last timestamp delta "</span><br><span>                          "are not available on 0x%x, "</span><br><span>@@ -421,8 +421,8 @@</span><br><span>        "endpoint:0x%x conn:%s using format defaults\n",</span><br><span>           ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- *payload_type = conn->end.codec.payload_type;</span><br><span style="color: hsl(0, 100%, 40%);">-        *audio_name = conn->end.codec.audio_name;</span><br><span style="color: hsl(120, 100%, 40%);">+  *payload_type = conn->end.codec->payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+  *audio_name = conn->end.codec->audio_name;</span><br><span>     *fmtp_extra = conn->end.fmtp_extra;</span><br><span> }</span><br><span> </span><br><span>@@ -490,7 +490,7 @@</span><br><span>        uint16_t seq;</span><br><span>        uint32_t timestamp, ssrc;</span><br><span>    struct rtp_hdr *rtp_hdr;</span><br><span style="color: hsl(0, 100%, 40%);">-        int payload = rtp_end->codec.payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ int payload = rtp_end->codec->payload_type;</span><br><span> </span><br><span>        if (len < sizeof(*rtp_hdr))</span><br><span>               return;</span><br><span>@@ -498,7 +498,7 @@</span><br><span>        rtp_hdr = (struct rtp_hdr *)data;</span><br><span>    seq = ntohs(rtp_hdr->sequence);</span><br><span>   timestamp = ntohl(rtp_hdr->timestamp);</span><br><span style="color: hsl(0, 100%, 40%);">-       arrival_time = get_current_ts(rtp_end->codec.rate);</span><br><span style="color: hsl(120, 100%, 40%);">+        arrival_time = get_current_ts(rtp_end->codec->rate);</span><br><span>   ssrc = ntohl(rtp_hdr->ssrc);</span><br><span>      transit = arrival_time - timestamp;</span><br><span> </span><br><span>@@ -524,7 +524,7 @@</span><br><span>                     inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));</span><br><span>                if (state->packet_duration == 0) {</span><br><span>                        state->packet_duration =</span><br><span style="color: hsl(0, 100%, 40%);">-                         rtp_end->codec.rate * 20 / 1000;</span><br><span style="color: hsl(120, 100%, 40%);">+                           rtp_end->codec->rate * 20 / 1000;</span><br><span>                  LOGP(DRTP, LOGL_NOTICE,</span><br><span>                           "endpoint:0x%x fixed packet duration is not available, "</span><br><span>                           "using fixed 20ms instead: %d from %s:%d\n",</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c</span><br><span>index 21f6cf3..eea67a6 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_protocol.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_protocol.c</span><br><span>@@ -40,6 +40,7 @@</span><br><span> #include <osmocom/mgcp/mgcp_msg.h></span><br><span> #include <osmocom/mgcp/mgcp_endp.h></span><br><span> #include <osmocom/mgcp/mgcp_sdp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_codec.h></span><br><span> </span><br><span> struct mgcp_request {</span><br><span>   char *name;</span><br><span>@@ -534,12 +535,15 @@</span><br><span> </span><br><span>      talloc_free(lco->string);</span><br><span>         lco->string = talloc_strdup(ctx, options);</span><br><span style="color: hsl(0, 100%, 40%);">-   </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   p_opt = strstr(lco->string, "p:");</span><br><span>      if (p_opt && sscanf(p_opt, "p:%d-%d",</span><br><span>                          &lco->pkt_period_min, &lco->pkt_period_max) == 1)</span><br><span>          lco->pkt_period_max = lco->pkt_period_min;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  /* FIXME: LCO also supports the negotiation of more then one codec.</span><br><span style="color: hsl(120, 100%, 40%);">+    * (e.g. a:PCMU;G726-32) But this implementation only supports a single</span><br><span style="color: hsl(120, 100%, 40%);">+        * codec only. */</span><br><span>    a_opt = strstr(lco->string, "a:");</span><br><span>      if (a_opt && sscanf(a_opt, "a:%8[^,]", codec) == 1) {</span><br><span>              talloc_free(lco->codec);</span><br><span>@@ -585,15 +589,15 @@</span><br><span>  /* Get the number of frames per channel and packet */</span><br><span>        if (rtp->frames_per_packet)</span><br><span>               f = rtp->frames_per_packet;</span><br><span style="color: hsl(0, 100%, 40%);">-  else if (rtp->packet_duration_ms && rtp->codec.frame_duration_num) {</span><br><span style="color: hsl(0, 100%, 40%);">-              int den = 1000 * rtp->codec.frame_duration_num;</span><br><span style="color: hsl(0, 100%, 40%);">-              f = (rtp->packet_duration_ms * rtp->codec.frame_duration_den +</span><br><span style="color: hsl(120, 100%, 40%);">+  else if (rtp->packet_duration_ms && rtp->codec->frame_duration_num) {</span><br><span style="color: hsl(120, 100%, 40%);">+                int den = 1000 * rtp->codec->frame_duration_num;</span><br><span style="color: hsl(120, 100%, 40%);">+                f = (rtp->packet_duration_ms * rtp->codec->frame_duration_den +</span><br><span>                  den / 2)</span><br><span>                    / den;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return rtp->codec.rate * f * rtp->codec.frame_duration_num /</span><br><span style="color: hsl(0, 100%, 40%);">-          rtp->codec.frame_duration_den;</span><br><span style="color: hsl(120, 100%, 40%);">+ return rtp->codec->rate * f * rtp->codec->frame_duration_num /</span><br><span style="color: hsl(120, 100%, 40%);">+        rtp->codec->frame_duration_den;</span><br><span> }</span><br><span> </span><br><span> static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)</span><br><span>@@ -609,6 +613,68 @@</span><br><span>       return mgcp_parse_osmux_cid(line);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Process codec information contained in CRCX/MDCX */</span><br><span style="color: hsl(120, 100%, 40%);">+static int handle_codec_info(struct mgcp_conn_rtp *conn,</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct mgcp_parse_data *p, int have_sdp, bool crcx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct mgcp_endpoint *endp = p->endp;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       char *cmd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (crcx)</span><br><span style="color: hsl(120, 100%, 40%);">+             cmd = "CRCX";</span><br><span style="color: hsl(120, 100%, 40%);">+       else</span><br><span style="color: hsl(120, 100%, 40%);">+          cmd = "MDCX";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Collect codec information */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (have_sdp) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* If we have SDP, we ignore the local connection options and</span><br><span style="color: hsl(120, 100%, 40%);">+          * use only the SDP information. */</span><br><span style="color: hsl(120, 100%, 40%);">+           mgcp_codec_reset_all(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = mgcp_parse_sdp_data(endp, conn, p);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGP(DLMGCP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                           "%s: endpoint:%x sdp not parseable\n", cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+                         ENDPOINT_NUMBER(endp));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* See also RFC 3661: Protocol error */</span><br><span style="color: hsl(120, 100%, 40%);">+                       return 510;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (endp->local_options.codec) {</span><br><span style="color: hsl(120, 100%, 40%);">+            /* When no SDP is available, we use the codec information from</span><br><span style="color: hsl(120, 100%, 40%);">+                 * the local connection options (if present) */</span><br><span style="color: hsl(120, 100%, 40%);">+               mgcp_codec_reset_all(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = mgcp_codec_add(conn, PTYPE_UNDEFINED, endp->local_options.codec);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc != 0)</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Make sure we always set a sane default codec */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (conn->end.codecs_assigned == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* When SDP and/or LCO did not supply any codec information,</span><br><span style="color: hsl(120, 100%, 40%);">+           * than it makes sense to pick a sane default: (payload-type 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                * PCMU), see also: OS#2658 */</span><br><span style="color: hsl(120, 100%, 40%);">+                mgcp_codec_reset_all(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = mgcp_codec_add(conn, 0, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc != 0)</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Make codec decision */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (mgcp_codec_decide(conn) != 0)</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%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+error:</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DLMGCP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+           "%s: endpoint:0x%x codec negotiation failure\n", cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+       ENDPOINT_NUMBER(endp));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* See also RFC 3661: Codec negotiation failure */</span><br><span style="color: hsl(120, 100%, 40%);">+    return 534;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* CRCX command handler, processes the received command */</span><br><span> static struct msgb *handle_create_con(struct mgcp_parse_data *p)</span><br><span> {</span><br><span>@@ -726,17 +792,6 @@</span><br><span>        * connection ids) */</span><br><span>        endp->callid = talloc_strdup(tcfg->endpoints, callid);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        /* Extract audio codec information */</span><br><span style="color: hsl(0, 100%, 40%);">-   rc = set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,</span><br><span style="color: hsl(0, 100%, 40%);">-                               local_options);</span><br><span style="color: hsl(0, 100%, 40%);">-       if (rc != 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGP(DLMGCP, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                     "CRCX: endpoint:%x inavlid local connection options!\n",</span><br><span style="color: hsl(0, 100%, 40%);">-              ENDPOINT_NUMBER(endp));</span><br><span style="color: hsl(0, 100%, 40%);">-            error_code = rc;</span><br><span style="color: hsl(0, 100%, 40%);">-                goto error2;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    snprintf(conn_name, sizeof(conn_name), "%s", callid);</span><br><span>      _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP, conn_name);</span><br><span>  if (!_conn) {</span><br><span>@@ -767,12 +822,27 @@</span><br><span>                goto error2;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* set up RTP media parameters */</span><br><span style="color: hsl(0, 100%, 40%);">-       if (have_sdp)</span><br><span style="color: hsl(0, 100%, 40%);">-           mgcp_parse_sdp_data(endp, conn, p);</span><br><span style="color: hsl(0, 100%, 40%);">-     else if (endp->local_options.codec)</span><br><span style="color: hsl(0, 100%, 40%);">-          mgcp_set_audio_info(p->cfg, &conn->end.codec,</span><br><span style="color: hsl(0, 100%, 40%);">-                             PTYPE_UNDEFINED, endp->local_options.codec);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Set local connection options, if present */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (local_options) {</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = set_local_cx_options(endp->tcfg->endpoints,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          &endp->local_options, local_options);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGP(DLMGCP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                           "CRCX: endpoint:%x inavlid local connection options!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            ENDPOINT_NUMBER(endp));</span><br><span style="color: hsl(120, 100%, 40%);">+                  error_code = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+                      goto error2;</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%);">+   /* Handle codec information and decide for a suitable codec */</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = handle_codec_info(conn, p, have_sdp, true);</span><br><span style="color: hsl(120, 100%, 40%);">+      mgcp_codec_summary(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             error_code = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+              goto error2;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  conn->end.fmtp_extra = talloc_strdup(tcfg->endpoints,</span><br><span>                                       tcfg->audio_fmtp_extra);</span><br><span> </span><br><span>@@ -852,6 +922,10 @@</span><br><span>  return create_err_response(endp, error_code, "CRCX", p->trans);</span><br><span> }</span><br><span> </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%);">+</span><br><span> /* MDCX command handler, processes the received command */</span><br><span> static struct msgb *handle_modify_con(struct mgcp_parse_data *p)</span><br><span> {</span><br><span>@@ -943,23 +1017,27 @@</span><br><span>        } else</span><br><span>                       conn->conn->mode = conn->conn->mode_orig;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       if (have_sdp)</span><br><span style="color: hsl(0, 100%, 40%);">-           mgcp_parse_sdp_data(endp, conn, p);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Set local connection options, if present */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (local_options) {</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = set_local_cx_options(endp->tcfg->endpoints,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          &endp->local_options, local_options);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGP(DLMGCP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                           "MDCX: endpoint:%x inavlid local connection options!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            ENDPOINT_NUMBER(endp));</span><br><span style="color: hsl(120, 100%, 40%);">+                  error_code = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+                      goto error3;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   rc = set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,</span><br><span style="color: hsl(0, 100%, 40%);">-                               local_options);</span><br><span style="color: hsl(0, 100%, 40%);">-       if (rc != 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGP(DLMGCP, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                     "MDCX: endpoint:%x inavlid local connection options!\n",</span><br><span style="color: hsl(0, 100%, 40%);">-              ENDPOINT_NUMBER(endp));</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Handle codec information and decide for a suitable codec */</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = handle_codec_info(conn, p, have_sdp, false);</span><br><span style="color: hsl(120, 100%, 40%);">+     mgcp_codec_summary(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc) {</span><br><span>            error_code = rc;</span><br><span>             goto error3;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (!have_sdp && endp->local_options.codec)</span><br><span style="color: hsl(0, 100%, 40%);">-          mgcp_set_audio_info(p->cfg, &conn->end.codec,</span><br><span style="color: hsl(0, 100%, 40%);">-                             PTYPE_UNDEFINED, endp->local_options.codec);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>  /* check connection mode setting */</span><br><span>  if (conn->conn->mode != MGCP_CONN_LOOPBACK</span><br><span>         && conn->conn->mode != MGCP_CONN_RECV_ONLY</span><br><span>@@ -971,6 +1049,7 @@</span><br><span>          goto error3;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      if (setup_rtp_processing(endp, conn) != 0)</span><br><span>           goto error3;</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 5cc34ea..102c8c3 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_sdp.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_sdp.c</span><br><span>@@ -25,9 +25,13 @@</span><br><span> #include <osmocom/mgcp/mgcp_internal.h></span><br><span> #include <osmocom/mgcp/mgcp_msg.h></span><br><span> #include <osmocom/mgcp/mgcp_endp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_codec.h></span><br><span> </span><br><span> #include <errno.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* A struct to store intermediate parsing results. The function</span><br><span style="color: hsl(120, 100%, 40%);">+ * mgcp_parse_sdp_data() is using it as temporary storage for parsing the SDP</span><br><span style="color: hsl(120, 100%, 40%);">+ * codec information. */</span><br><span> struct sdp_rtp_map {</span><br><span>   /* the type */</span><br><span>       int payload_type;</span><br><span>@@ -40,89 +44,8 @@</span><br><span>       int channels;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! Set codec configuration depending on payload type and codec name.</span><br><span style="color: hsl(0, 100%, 40%);">- *  \param[in] ctx talloc context.</span><br><span style="color: hsl(0, 100%, 40%);">- *  \param[out] codec configuration (caller provided memory).</span><br><span style="color: hsl(0, 100%, 40%);">- *  \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined).</span><br><span style="color: hsl(0, 100%, 40%);">- *  \param[in] audio_name audio codec name (e.g. "GSM/8000/1").</span><br><span style="color: hsl(0, 100%, 40%);">- *  \returns 0 on success, -1 on failure. */</span><br><span style="color: hsl(0, 100%, 40%);">-int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,</span><br><span style="color: hsl(0, 100%, 40%);">-                  int payload_type, const char *audio_name)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      int rate = codec->rate;</span><br><span style="color: hsl(0, 100%, 40%);">-      int channels = codec->channels;</span><br><span style="color: hsl(0, 100%, 40%);">-      char audio_codec[64];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   talloc_free(codec->subtype_name);</span><br><span style="color: hsl(0, 100%, 40%);">-    codec->subtype_name = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-  talloc_free(codec->audio_name);</span><br><span style="color: hsl(0, 100%, 40%);">-      codec->audio_name = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (payload_type != PTYPE_UNDEFINED)</span><br><span style="color: hsl(0, 100%, 40%);">-            codec->payload_type = payload_type;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!audio_name) {</span><br><span style="color: hsl(0, 100%, 40%);">-              switch (payload_type) {</span><br><span style="color: hsl(0, 100%, 40%);">-         case 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                 audio_name = "PCMU/8000/1";</span><br><span style="color: hsl(0, 100%, 40%);">-                   break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 3:</span><br><span style="color: hsl(0, 100%, 40%);">-                 audio_name = "GSM/8000/1";</span><br><span style="color: hsl(0, 100%, 40%);">-                    break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 8:</span><br><span style="color: hsl(0, 100%, 40%);">-                 audio_name = "PCMA/8000/1";</span><br><span style="color: hsl(0, 100%, 40%);">-                   break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 18:</span><br><span style="color: hsl(0, 100%, 40%);">-                        audio_name = "G729/8000/1";</span><br><span style="color: hsl(0, 100%, 40%);">-                   break;</span><br><span style="color: hsl(0, 100%, 40%);">-          default:</span><br><span style="color: hsl(0, 100%, 40%);">-                        /* Payload type is unknown, don't change rate and</span><br><span style="color: hsl(0, 100%, 40%);">-                    * channels. */</span><br><span style="color: hsl(0, 100%, 40%);">-                 /* TODO: return value? */</span><br><span style="color: hsl(0, 100%, 40%);">-                       return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (sscanf(audio_name, "%63[^/]/%d/%d",</span><br><span style="color: hsl(0, 100%, 40%);">-                  audio_codec, &rate, &channels) < 1)</span><br><span style="color: hsl(0, 100%, 40%);">-               return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- codec->rate = rate;</span><br><span style="color: hsl(0, 100%, 40%);">-  codec->channels = channels;</span><br><span style="color: hsl(0, 100%, 40%);">-  codec->subtype_name = talloc_strdup(ctx, audio_codec);</span><br><span style="color: hsl(0, 100%, 40%);">-       codec->audio_name = talloc_strdup(ctx, audio_name);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!strcmp(audio_codec, "G729")) {</span><br><span style="color: hsl(0, 100%, 40%);">-           codec->frame_duration_num = 10;</span><br><span style="color: hsl(0, 100%, 40%);">-              codec->frame_duration_den = 1000;</span><br><span style="color: hsl(0, 100%, 40%);">-    } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;</span><br><span style="color: hsl(0, 100%, 40%);">-         codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (payload_type < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-              payload_type = 96;</span><br><span style="color: hsl(0, 100%, 40%);">-              if (rate == 8000 && channels == 1) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    if (!strcmp(audio_codec, "GSM"))</span><br><span style="color: hsl(0, 100%, 40%);">-                              payload_type = 3;</span><br><span style="color: hsl(0, 100%, 40%);">-                       else if (!strcmp(audio_codec, "PCMA"))</span><br><span style="color: hsl(0, 100%, 40%);">-                                payload_type = 8;</span><br><span style="color: hsl(0, 100%, 40%);">-                       else if (!strcmp(audio_codec, "PCMU"))</span><br><span style="color: hsl(0, 100%, 40%);">-                                payload_type = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-                       else if (!strcmp(audio_codec, "G729"))</span><br><span style="color: hsl(0, 100%, 40%);">-                                payload_type = 18;</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               codec->payload_type = payload_type;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (channels != 1)</span><br><span style="color: hsl(0, 100%, 40%);">-              LOGP(DLMGCP, LOGL_NOTICE,</span><br><span style="color: hsl(0, 100%, 40%);">-                    "Channels != 1 in SDP: '%s'\n", audio_name);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+/* Helper function to extrapolate missing codec parameters in a codec mao from</span><br><span style="color: hsl(120, 100%, 40%);">+ * an already filled in payload_type, called from: mgcp_parse_sdp_data() */</span><br><span> static void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used)</span><br><span> {</span><br><span>       int i;</span><br><span>@@ -149,10 +72,16 @@</span><br><span>                        codecs[i].rate = 8000;</span><br><span>                       codecs[i].channels = 1;</span><br><span>                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      codecs[i].codec_name = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                  codecs[i].rate = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                   codecs[i].channels = 0;</span><br><span>              }</span><br><span>    }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Helper function to update codec map information with additional data from</span><br><span style="color: hsl(120, 100%, 40%);">+ * SDP, called from: mgcp_parse_sdp_data() */</span><br><span> static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,</span><br><span>                          int payload, const char *audio_name)</span><br><span> {</span><br><span>@@ -162,8 +91,13 @@</span><br><span>            char audio_codec[64];</span><br><span>                int rate = -1;</span><br><span>               int channels = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Note: We can only update payload codecs that already exist</span><br><span style="color: hsl(120, 100%, 40%);">+          * in our codec list. If we get an unexpected payload type,</span><br><span style="color: hsl(120, 100%, 40%);">+            * we just drop it */</span><br><span>                if (codecs[i].payload_type != payload)</span><br><span>                       continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          if (sscanf(audio_name, "%63[^/]/%d/%d",</span><br><span>                       audio_codec, &rate, &channels) < 1) {</span><br><span>                  LOGP(DLMGCP, LOGL_ERROR, "Failed to parse '%s'\n",</span><br><span>@@ -182,43 +116,72 @@</span><br><span>              audio_name);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Check if the codec matches what is set up in the trunk config */</span><br><span style="color: hsl(0, 100%, 40%);">-static int is_codec_compatible(const struct mgcp_endpoint *endp,</span><br><span style="color: hsl(0, 100%, 40%);">-                          const struct sdp_rtp_map *codec)</span><br><span style="color: hsl(120, 100%, 40%);">+/* Extract payload types from SDP, also check for duplicates */</span><br><span style="color: hsl(120, 100%, 40%);">+static int pt_from_sdp(void *ctx, struct sdp_rtp_map *codecs,</span><br><span style="color: hsl(120, 100%, 40%);">+                      unsigned int codecs_len, char *sdp)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- char *codec_str;</span><br><span style="color: hsl(0, 100%, 40%);">-        char audio_codec[64];</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 *pt_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%);">+       unsigned int i;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     if (!codec->codec_name)</span><br><span style="color: hsl(0, 100%, 40%);">-              return 0;</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> </span><br><span style="color: hsl(0, 100%, 40%);">-       /* GSM, GSM/8000 and GSM/8000/1 should all be compatible...</span><br><span style="color: hsl(0, 100%, 40%);">-      * let's go by name first. */</span><br><span style="color: hsl(0, 100%, 40%);">-       codec_str = endp->tcfg->audio_name;</span><br><span style="color: hsl(0, 100%, 40%);">-       if (sscanf(codec_str, "%63[^/]/%*d/%*d", audio_codec) < 1)</span><br><span style="color: hsl(0, 100%, 40%);">-         return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     str_ptr = strstr(str_ptr, "RTP/AVP ");</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> </span><br><span style="color: hsl(0, 100%, 40%);">-  return strcasecmp(audio_codec, codec->codec_name) == 0;</span><br><span style="color: hsl(120, 100%, 40%);">+    pt_str = strtok(str_ptr, " ");</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!pt_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%);">+           /* Do not allow excessive payload types */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (count > codecs_len)</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%);">+         pt_str = strtok(NULL, " ");</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!pt_str)</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%);">+              pt = atoi(pt_str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Do not allow duplicate payload types */</span><br><span style="color: hsl(120, 100%, 40%);">+            for (i = 0; i < count; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (codecs[i].payload_type == pt)</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%);">+         codecs[count].payload_type = pt;</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 count;</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> }</span><br><span> </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>  *  \param[out] caller provided memory to store the parsing results.</span><br><span style="color: hsl(0, 100%, 40%);">- *  \returns 1 when a codec is assigned, 0 when no codec is assigned</span><br><span>  *</span><br><span>  *  Note: In conn (conn->end) the function returns the packet duration,</span><br><span style="color: hsl(0, 100%, 40%);">- *  rtp port, rtcp port and the assigned codec. */</span><br><span style="color: hsl(120, 100%, 40%);">+ *  rtp port, rtcp port and the codec information.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success, -1 on failure. */</span><br><span> int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,</span><br><span style="color: hsl(0, 100%, 40%);">-                    struct mgcp_conn_rtp *conn,</span><br><span style="color: hsl(0, 100%, 40%);">-                     struct mgcp_parse_data *p)</span><br><span style="color: hsl(120, 100%, 40%);">+                    struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     struct sdp_rtp_map codecs[10];</span><br><span style="color: hsl(0, 100%, 40%);">-  int codecs_used = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct sdp_rtp_map codecs[MGCP_MAX_CODECS];</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int codecs_used = 0;</span><br><span>        char *line;</span><br><span style="color: hsl(0, 100%, 40%);">-     int maxptime = -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      int i;</span><br><span style="color: hsl(0, 100%, 40%);">-  bool codec_assigned = false;</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int i;</span><br><span>      void *tmp_ctx = talloc_new(NULL);</span><br><span>    struct mgcp_rtp_end *rtp;</span><br><span> </span><br><span>@@ -255,34 +218,21 @@</span><br><span>                                        rtp->packet_duration_ms = 0;</span><br><span>                              else</span><br><span>                                         rtp->packet_duration_ms = ptime;</span><br><span style="color: hsl(0, 100%, 40%);">-                     } else if (sscanf(line, "a=maxptime:%d", &ptime2)</span><br><span style="color: hsl(0, 100%, 40%);">-                            == 1) {</span><br><span style="color: hsl(0, 100%, 40%);">-                              maxptime = ptime2;</span><br><span style="color: hsl(120, 100%, 40%);">+                    } else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               rtp->maximum_packet_time = ptime2;</span><br><span>                        }</span><br><span>                    break;</span><br><span>               case 'm':</span><br><span style="color: hsl(0, 100%, 40%);">-                       rc = sscanf(line,</span><br><span style="color: hsl(0, 100%, 40%);">-                                   "m=audio %d RTP/AVP %d %d %d %d %d %d %d %d %d %d",</span><br><span style="color: hsl(0, 100%, 40%);">-                                   &port, &codecs[0].payload_type,</span><br><span style="color: hsl(0, 100%, 40%);">-                                 &codecs[1].payload_type,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    &codecs[2].payload_type,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    &codecs[3].payload_type,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    &codecs[4].payload_type,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    &codecs[5].payload_type,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    &codecs[6].payload_type,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    &codecs[7].payload_type,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    &codecs[8].payload_type,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    &codecs[9].payload_type);</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (rc >= 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc = sscanf(line, "m=audio %d RTP/AVP", &port);</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (rc == 1) {</span><br><span>                               rtp->rtp_port = htons(port);</span><br><span>                              rtp->rtcp_port = htons(port + 1);</span><br><span style="color: hsl(0, 100%, 40%);">-                            codecs_used = rc - 1;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                           /* So far we have only set the payload type in</span><br><span style="color: hsl(0, 100%, 40%);">-                           * the codec struct. Now we fill up the</span><br><span style="color: hsl(0, 100%, 40%);">-                          * remaining fields of the codec description */</span><br><span style="color: hsl(0, 100%, 40%);">-                         codecs_initialize(tmp_ctx, codecs, codecs_used);</span><br><span>                     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   rc = pt_from_sdp(conn->conn, codecs,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        ARRAY_SIZE(codecs), line);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (rc > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                                codecs_used = rc;</span><br><span>                    break;</span><br><span>               case 'c':</span><br><span> </span><br><span>@@ -303,47 +253,36 @@</span><br><span>                        break;</span><br><span>               }</span><br><span>    }</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(codecs_used <= MGCP_MAX_CODECS);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     /* Now select a suitable codec */</span><br><span style="color: hsl(120, 100%, 40%);">+     /* So far we have only set the payload type in the codec struct. Now we</span><br><span style="color: hsl(120, 100%, 40%);">+        * fill up the remaining fields of the codec description with some default</span><br><span style="color: hsl(120, 100%, 40%);">+     * information */</span><br><span style="color: hsl(120, 100%, 40%);">+     codecs_initialize(tmp_ctx, codecs, codecs_used);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Store parsed codec information */</span><br><span>         for (i = 0; i < codecs_used; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-          /* When no transcoding is available, avoid codecs that would</span><br><span style="color: hsl(0, 100%, 40%);">-             * require transcoding. */</span><br><span style="color: hsl(0, 100%, 40%);">-              if (endp->tcfg->no_audio_transcoding &&</span><br><span style="color: hsl(0, 100%, 40%);">-               !is_codec_compatible(endp, &codecs[i])) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       LOGP(DLMGCP, LOGL_NOTICE, "Skipping codec %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                           codecs[i].codec_name);</span><br><span style="color: hsl(0, 100%, 40%);">-                     continue;</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               mgcp_set_audio_info(p->cfg, &rtp->codec,</span><br><span style="color: hsl(0, 100%, 40%);">-                                  codecs[i].payload_type, codecs[i].map_line);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                codec_assigned = true;</span><br><span style="color: hsl(0, 100%, 40%);">-          break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (codec_assigned) {</span><br><span style="color: hsl(0, 100%, 40%);">-           /* TODO/XXX: Store this per codec and derive it on use */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (maxptime >= 0 && maxptime * rtp->codec.frame_duration_den ></span><br><span style="color: hsl(0, 100%, 40%);">-                    rtp->codec.frame_duration_num * 1500) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  /* more than 1 frame */</span><br><span style="color: hsl(0, 100%, 40%);">-                 rtp->packet_duration_ms = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGP(DLMGCP, LOGL_NOTICE,</span><br><span style="color: hsl(0, 100%, 40%);">-                    "Got media info via SDP: port %d, payload %d (%s), "</span><br><span style="color: hsl(0, 100%, 40%);">-                  "duration %d, addr %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     ntohs(rtp->rtp_port), rtp->codec.payload_type,</span><br><span style="color: hsl(0, 100%, 40%);">-                    rtp->codec.subtype_name ? rtp-></span><br><span style="color: hsl(0, 100%, 40%);">-                   codec.subtype_name : "unknown", rtp->packet_duration_ms,</span><br><span style="color: hsl(0, 100%, 40%);">-                   inet_ntoa(rtp->addr));</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGP(DLMGCP, LOGL_NOTICE, "endpoint:0x%x, failed to add codec\n", ENDPOINT_NUMBER(p->endp));</span><br><span>    }</span><br><span> </span><br><span>        talloc_free(tmp_ctx);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       if (codec_assigned)</span><br><span style="color: hsl(0, 100%, 40%);">-             return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DLMGCP, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+          "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",</span><br><span style="color: hsl(120, 100%, 40%);">+            ntohs(rtp->rtp_port), inet_ntoa(rtp->addr),</span><br><span style="color: hsl(120, 100%, 40%);">+             rtp->packet_duration_ms);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (codecs_used == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGPC(DLMGCP, LOGL_NOTICE, "none");</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < codecs_used; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",</span><br><span style="color: hsl(120, 100%, 40%);">+               rtp->codecs[i].payload_type,</span><br><span style="color: hsl(120, 100%, 40%);">+               rtp->codecs[i].subtype_name ? rtp-> codecs[i].subtype_name : "unknown");</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGPC(DLMGCP, LOGL_NOTICE, " ");</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGPC(DLMGCP, LOGL_NOTICE, "\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -389,7 +328,9 @@</span><br><span>             if (rc < 0)</span><br><span>                       goto buffer_too_small;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-              if (audio_name && endp->tcfg->audio_send_name) {</span><br><span style="color: hsl(120, 100%, 40%);">+                /* FIXME: Check if the payload type is from the static range,</span><br><span style="color: hsl(120, 100%, 40%);">+          * if yes, omitthe a=rtpmap since it is unnecessary */</span><br><span style="color: hsl(120, 100%, 40%);">+                if (audio_name && endp->tcfg->audio_send_name && (payload_type >= 96 && payload_type <= 127)) {</span><br><span>                  rc = msgb_printf(sdp, "a=rtpmap:%d %s\r\n",</span><br><span>                                         payload_type, audio_name);</span><br><span> </span><br><span>diff --git a/src/libosmo-mgcp/mgcp_vty.c b/src/libosmo-mgcp/mgcp_vty.c</span><br><span>index 3c1b596..a7a1feb 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_vty.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_vty.c</span><br><span>@@ -157,7 +157,7 @@</span><br><span> static void dump_rtp_end(struct vty *vty, struct mgcp_rtp_state *state,</span><br><span>                     struct mgcp_rtp_end *end)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct mgcp_rtp_codec *codec = &end->codec;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct mgcp_rtp_codec *codec = end->codec;</span><br><span> </span><br><span>    vty_out(vty,</span><br><span>                 "   Timestamp Errs: %lu->%lu%s"</span><br><span>diff --git a/tests/mgcp/mgcp_test.c b/tests/mgcp/mgcp_test.c</span><br><span>index 3fc8bc0..1d2cf4a 100644</span><br><span>--- a/tests/mgcp/mgcp_test.c</span><br><span>+++ b/tests/mgcp/mgcp_test.c</span><br><span>@@ -26,6 +26,8 @@</span><br><span> #include <osmocom/mgcp/mgcp_stat.h></span><br><span> #include <osmocom/mgcp/mgcp_msg.h></span><br><span> #include <osmocom/mgcp/mgcp_endp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_sdp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_codec.h></span><br><span> </span><br><span> #include <osmocom/core/application.h></span><br><span> #include <osmocom/core/talloc.h></span><br><span>@@ -156,8 +158,8 @@</span><br><span>         "s=-\r\n" \</span><br><span>        "c=IN IP4 0.0.0.0\r\n" \</span><br><span>   "t=0 0\r\n" \</span><br><span style="color: hsl(0, 100%, 40%);">- "m=audio 16002 RTP/AVP 96\r\n" \</span><br><span style="color: hsl(0, 100%, 40%);">-      "a=rtpmap:96 AMR\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+     "m=audio 16002 RTP/AVP 112\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+   "a=rtpmap:112 AMR\r\n" \</span><br><span>   "a=ptime:40\r\n"</span><br><span> </span><br><span> #define MDCX4_PT1 \</span><br><span>@@ -404,7 +406,7 @@</span><br><span>  "v=0\r\n" \</span><br><span>        "o=- 1439038275 1439038275 IN IP4 192.168.181.247\r\n" \</span><br><span>   "s=-\r\nc=IN IP4 192.168.181.247\r\n" \</span><br><span style="color: hsl(0, 100%, 40%);">-       "t=0 0\r\nm=audio 29084 RTP/AVP 255 0 8 3 18 4 96 97 101\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+     "t=0 0\r\nm=audio 29084 RTP/AVP 0 8 3 18 4 96 97 101\r\n" \</span><br><span>        "a=rtpmap:0 PCMU/8000\r\n" \</span><br><span>       "a=rtpmap:8 PCMA/8000\r\n" \</span><br><span>       "a=rtpmap:3 gsm/8000\r\n" \</span><br><span>@@ -425,7 +427,24 @@</span><br><span>         "I: %s\r\n" \</span><br><span>      "\r\n" \</span><br><span>   "c=IN IP4 8.8.8.8\r\n" \</span><br><span style="color: hsl(0, 100%, 40%);">-      "m=audio 16434 RTP/AVP 255\r\n"</span><br><span style="color: hsl(120, 100%, 40%);">+     "m=audio 16434 RTP/AVP 3\r\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CRCX_NO_LCO_NO_SDP \</span><br><span style="color: hsl(120, 100%, 40%);">+       "CRCX 2 6@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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CRCX_NO_LCO_NO_SDP_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 16008 RTP/AVP 0\r\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+     "a=ptime:20\r\n"</span><br><span> </span><br><span> struct mgcp_test {</span><br><span>         const char *name;</span><br><span>@@ -462,6 +481,7 @@</span><br><span>      {"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE,.extra_fmtp =</span><br><span>   "a=fmtp:126 0/1/2"},</span><br><span>      {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE,.extra_fmtp = "a=fmtp:126 0/1/2"},</span><br><span style="color: hsl(120, 100%, 40%);">+  {"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},</span><br><span> };</span><br><span> </span><br><span> static const struct mgcp_test retransmit[] = {</span><br><span>@@ -764,14 +784,14 @@</span><br><span>                      fprintf(stderr, "endpoint %d: "</span><br><span>                            "payload type %d (expected %d)\n",</span><br><span>                                 last_endpoint,</span><br><span style="color: hsl(0, 100%, 40%);">-                          conn->end.codec.payload_type, t->ptype);</span><br><span style="color: hsl(120, 100%, 40%);">+                                conn->end.codec->payload_type, t->ptype);</span><br><span> </span><br><span>                       if (t->ptype != PTYPE_IGNORE)</span><br><span style="color: hsl(0, 100%, 40%);">-                                OSMO_ASSERT(conn->end.codec.payload_type ==</span><br><span style="color: hsl(120, 100%, 40%);">+                                OSMO_ASSERT(conn->end.codec->payload_type ==</span><br><span>                                       t->ptype);</span><br><span> </span><br><span>                        /* Reset them again for next test */</span><br><span style="color: hsl(0, 100%, 40%);">-                    conn->end.codec.payload_type = PTYPE_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+                 conn->end.codec->payload_type = PTYPE_NONE;</span><br><span>            }</span><br><span>    }</span><br><span> </span><br><span>@@ -1167,7 +1187,8 @@</span><br><span> </span><br><span>    rtp = &conn->end;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    rtp->codec.payload_type = 98;</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1") == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      rtp->codec = &rtp->codecs[0];</span><br><span> </span><br><span>  for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {</span><br><span>             struct rtp_packet_info *info = test_rtp_packets1 + i;</span><br><span>@@ -1243,7 +1264,7 @@</span><br><span>        endp = &cfg->trunk.endpoints[last_endpoint];</span><br><span>  conn = mgcp_conn_get_rtp(endp, conn_id);</span><br><span>     OSMO_ASSERT(conn);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(conn->end.codec.payload_type == 18);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(conn->end.codec->payload_type == 18);</span><br><span> </span><br><span>  /* Allocate 2@mgw with three codecs, last one ignored */</span><br><span>     last_endpoint = -1;</span><br><span>@@ -1258,9 +1279,14 @@</span><br><span>         endp = &cfg->trunk.endpoints[last_endpoint];</span><br><span>  conn = mgcp_conn_get_rtp(endp, conn_id);</span><br><span>     OSMO_ASSERT(conn);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(conn->end.codec.payload_type == 18);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(conn->end.codec->payload_type == 18);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     /* Allocate 3@mgw with no codecs, check for PT == -1 */</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Allocate 3@mgw with no codecs, check for PT == 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Note: It usually makes no sense to leave the payload type list</span><br><span style="color: hsl(120, 100%, 40%);">+      * out. However RFC 2327 does not clearly forbid this case and</span><br><span style="color: hsl(120, 100%, 40%);">+         * it makes and since we already decided in OS#2658 that a missing</span><br><span style="color: hsl(120, 100%, 40%);">+     * LCO should pick a sane default codec, it makes sense to expect</span><br><span style="color: hsl(120, 100%, 40%);">+      * the same behaviour if SDP lacks proper payload type information */</span><br><span>        last_endpoint = -1;</span><br><span>  inp = create_msg(CRCX_MULT_3, NULL);</span><br><span>         resp = mgcp_handle_message(cfg, inp);</span><br><span>@@ -1273,7 +1299,7 @@</span><br><span>        endp = &cfg->trunk.endpoints[last_endpoint];</span><br><span>  conn = mgcp_conn_get_rtp(endp, conn_id);</span><br><span>     OSMO_ASSERT(conn);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(conn->end.codec.payload_type == -1);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(conn->end.codec->payload_type == 0);</span><br><span> </span><br><span>   /* Allocate 4@mgw with a single codec */</span><br><span>     last_endpoint = -1;</span><br><span>@@ -1288,7 +1314,7 @@</span><br><span>  endp = &cfg->trunk.endpoints[last_endpoint];</span><br><span>  conn = mgcp_conn_get_rtp(endp, conn_id);</span><br><span>     OSMO_ASSERT(conn);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(conn->end.codec.payload_type == 18);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(conn->end.codec->payload_type == 18);</span><br><span> </span><br><span>  /* Allocate 5@mgw at select GSM.. */</span><br><span>         last_endpoint = -1;</span><br><span>@@ -1306,7 +1332,7 @@</span><br><span>  endp = &cfg->trunk.endpoints[last_endpoint];</span><br><span>  conn = mgcp_conn_get_rtp(endp, conn_id);</span><br><span>     OSMO_ASSERT(conn);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(conn->end.codec.payload_type == 3);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(conn->end.codec->payload_type == 3);</span><br><span> </span><br><span>   inp = create_msg(MDCX_NAT_DUMMY, conn_id);</span><br><span>   last_endpoint = -1;</span><br><span>@@ -1317,7 +1343,7 @@</span><br><span>  endp = &cfg->trunk.endpoints[last_endpoint];</span><br><span>  conn = mgcp_conn_get_rtp(endp, conn_id);</span><br><span>     OSMO_ASSERT(conn);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(conn->end.codec.payload_type == 3);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(conn->end.codec->payload_type == 3);</span><br><span>       OSMO_ASSERT(conn->end.rtp_port == htons(16434));</span><br><span>  memset(&addr, 0, sizeof(addr));</span><br><span>  inet_aton("8.8.8.8", &addr);</span><br><span>@@ -1347,7 +1373,7 @@</span><br><span>   endp = &cfg->trunk.endpoints[last_endpoint];</span><br><span>  conn = mgcp_conn_get_rtp(endp, conn_id);</span><br><span>     OSMO_ASSERT(conn);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(conn->end.codec.payload_type == 255);</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(conn->end.codec->payload_type == 0);</span><br><span> </span><br><span>   talloc_free(cfg);</span><br><span> }</span><br><span>diff --git a/tests/mgcp/mgcp_test.ok b/tests/mgcp/mgcp_test.ok</span><br><span>index e293533..9838f4d 100644</span><br><span>--- a/tests/mgcp/mgcp_test.ok</span><br><span>+++ b/tests/mgcp/mgcp_test.ok</span><br><span>@@ -408,6 +408,21 @@</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 6@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%);">+</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 does not contain 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>@@ -1031,7 +1046,7 @@</span><br><span> s=- </span><br><span> c=IN IP4 192.168.181.247 </span><br><span> t=0 0 </span><br><span style="color: hsl(0, 100%, 40%);">-m=audio 29084 RTP/AVP 255 0 8 3 18 4 96 97 101 </span><br><span style="color: hsl(120, 100%, 40%);">+m=audio 29084 RTP/AVP 0 8 3 18 4 96 97 101 </span><br><span> a=rtpmap:0 PCMU/8000 </span><br><span> a=rtpmap:8 PCMA/8000 </span><br><span> a=rtpmap:3 gsm/8000 </span><br><span>@@ -1054,7 +1069,7 @@</span><br><span> I: %s </span><br><span> </span><br><span> c=IN IP4 8.8.8.8 </span><br><span style="color: hsl(0, 100%, 40%);">-m=audio 16434 RTP/AVP 255 </span><br><span style="color: hsl(120, 100%, 40%);">+m=audio 16434 RTP/AVP 3 </span><br><span> </span><br><span> ---------8<---------</span><br><span> creating message from statically defined input:</span><br><span>@@ -1069,7 +1084,7 @@</span><br><span> s=- </span><br><span> c=IN IP4 192.168.181.247 </span><br><span> t=0 0 </span><br><span style="color: hsl(0, 100%, 40%);">-m=audio 29084 RTP/AVP 255 0 8 3 18 4 96 97 101 </span><br><span style="color: hsl(120, 100%, 40%);">+m=audio 29084 RTP/AVP 0 8 3 18 4 96 97 101 </span><br><span> a=rtpmap:0 PCMU/8000 </span><br><span> a=rtpmap:8 PCMA/8000 </span><br><span> a=rtpmap:3 gsm/8000 </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/9648">change 9648</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/9648"/><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: If730d022ba6bdb217ad4e20b3fbbd1114dbb4b8f </div>
<div style="display:none"> Gerrit-Change-Number: 9648 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </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 </div>