This patch parses the MGCP 'p' value of the local connection options,
the 'ptime' and 'maxptime' SDP attributes, and the SDP rate
information and sets up packet_duration_ms accordingly. The MGCP 'p' has
priority over the values derived from the SDP data. If the packet
duration is unknown or allows for different values (e.g. because 'p'
uses a range or maxptime allows for more than one frame) the duration
is set to 0.

Sponsored-by: On-Waves ehf
---
 openbsc/src/libmgcp/mgcp_network.c  |    9 ++++
 openbsc/src/libmgcp/mgcp_protocol.c |   89 +++++++++++++++++++++++++++++++----
 openbsc/tests/mgcp/mgcp_test.c      |    4 ++
 openbsc/tests/mgcp/mgcp_test.ok     |   14 +++---
 4 files changed, 100 insertions(+), 16 deletions(-)

diff --git a/openbsc/src/libmgcp/mgcp_network.c 
b/openbsc/src/libmgcp/mgcp_network.c
index 8bd8afb..40227af 100644
--- a/openbsc/src/libmgcp/mgcp_network.c
+++ b/openbsc/src/libmgcp/mgcp_network.c
@@ -300,6 +300,15 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, 
struct mgcp_rtp_state *sta
                        state->seq_offset, state->packet_duration,
                        inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
                        endp->conn_mode);
+               if (state->packet_duration == 0 && 
rtp_end->force_constant_timing)
+                       LOGP(DMGCP, LOGL_ERROR,
+                       "Cannot patch timestamps on 0x%x: "
+                       "RTP packet duration is unknown, SSRC: %u, "
+                       "from %s:%d in %d\n",
+                       ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
+                       inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
+                       endp->conn_mode);
+
        } else if (state->in_stream.ssrc != ssrc) {
                LOGP(DMGCP, LOGL_NOTICE,
                        "The SSRC changed on 0x%x: %u -> %u  "
diff --git a/openbsc/src/libmgcp/mgcp_protocol.c 
b/openbsc/src/libmgcp/mgcp_protocol.c
index 3e26ad6..ba53df1 100644
--- a/openbsc/src/libmgcp/mgcp_protocol.c
+++ b/openbsc/src/libmgcp/mgcp_protocol.c
@@ -75,7 +75,7 @@ char *strline_r(char *str, char **saveptr)
 /* Assume audio frame length of 20ms */
 #define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
 #define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
-#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
+#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 0 /* we don't know */
 #define DEFAULT_RTP_AUDIO_DEFAULT_RATE  8000
 
 static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
@@ -562,25 +562,64 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, 
struct mgcp_parse_data *p)
 {
        char *line;
        int found_media = 0;
+       int audio_payload = -1;
 
        for_each_line(line, p->save) {
                switch (line[0]) {
-               case 'a':
                case 'o':
                case 's':
                case 't':
                case 'v':
                        /* skip these SDP attributes */
                        break;
+               case 'a': {
+                       int payload;
+                       int rate;
+                       int channels = 1;
+                       int ptime, ptime2 = 0;
+                       char audio_name[64];
+                       char audio_codec[64];
+
+                       if (audio_payload == -1)
+                               break;
+
+                       if (sscanf(line, "a=rtpmap:%d %64s",
+                                  &payload, audio_name) == 2) {
+                               if (payload != audio_payload)
+                                       break;
+
+                               if (sscanf(audio_name, "%[^/]/%d/%d",
+                                         audio_codec, &rate, &channels) < 2)
+                                       break;
+
+                               rtp->rate = rate;
+                               if (channels != 1)
+                                       LOGP(DMGCP, LOGL_NOTICE,
+                                            "Channels != 1 in SDP: '%s' on 
0x%x\n",
+                                            line, ENDPOINT_NUMBER(p->endp));
+                       } else if (sscanf(line, "a=ptime:%d-%d",
+                                         &ptime, &ptime2) >= 1) {
+                               if (ptime2 > 0 && ptime2 != ptime)
+                                       rtp->packet_duration_ms = 0;
+                               else
+                                       rtp->packet_duration_ms = ptime;
+                       } else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) 
{
+                               if (ptime2 * rtp->frame_duration_den >
+                                   rtp->frame_duration_num * 1500)
+                                       /* more than 1 frame */
+                                       rtp->packet_duration_ms = 0;
+                       }
+                       break;
+               }
                case 'm': {
                        int port;
-                       int payload;
+                       audio_payload = -1;
 
                        if (sscanf(line, "m=audio %d RTP/AVP %d",
-                                  &port, &payload) == 2) {
+                                  &port, &audio_payload) == 2) {
                                rtp->rtp_port = htons(port);
                                rtp->rtcp_port = htons(port + 1);
-                               rtp->payload_type = payload;
+                               rtp->payload_type = audio_payload;
                                found_media = 1;
                        }
                        break;
@@ -608,12 +647,33 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, 
struct mgcp_parse_data *p)
 
        if (found_media)
                LOGP(DMGCP, LOGL_NOTICE,
-                    "Got media info via SDP: port %d, payload %d, addr %s\n",
-                    ntohs(rtp->rtp_port), rtp->payload_type, 
inet_ntoa(rtp->addr));
+                    "Got media info via SDP: port %d, payload %d, "
+                    "duration %d, addr %s\n",
+                    ntohs(rtp->rtp_port), rtp->payload_type,
+                    rtp->packet_duration_ms, inet_ntoa(rtp->addr));
 
        return found_media;
 }
 
+static void parse_local_cx_options(struct mgcp_rtp_end *rtp, const char 
*options)
+{
+       int ptime, ptime2 = 0;
+       char *p_opt = strstr(options, "p:");
+       if (p_opt && sscanf(p_opt, "p:%d-%d", &ptime, &ptime2) >= 1) {
+               if (ptime2 > 0 && ptime2 != ptime)
+                       ptime = 0;
+
+               if (rtp->packet_duration_ms &&
+                   rtp->packet_duration_ms != ptime)
+                       LOGP(DMGCP, LOGL_NOTICE,
+                            "CRCX inconsistent ptime: SDP: %d, L: %d "
+                            "(will use %d)\n",
+                            rtp->packet_duration_ms, ptime, ptime);
+
+               rtp->packet_duration_ms = ptime;
+       }
+}
+
 void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
                         struct mgcp_rtp_end *rtp)
 {
@@ -707,7 +767,8 @@ mgcp_header_done:
        endp->callid = talloc_strdup(tcfg->endpoints, callid);
 
        if (local_options)
-               endp->local_options = talloc_strdup(tcfg->endpoints, 
local_options);
+               endp->local_options = talloc_strdup(tcfg->endpoints,
+                                                   local_options);
 
        if (parse_conn_mode(mode, &endp->conn_mode) != 0) {
                    error_code = 517;
@@ -740,6 +801,9 @@ mgcp_header_done:
        if (have_sdp)
                parse_sdp_data(&endp->net_end, p);
 
+       if (local_options)
+               parse_local_cx_options(&endp->net_end, local_options);
+
        /* policy CB */
        if (p->cfg->policy_cb) {
                int rc;
@@ -783,6 +847,7 @@ static struct msgb *handle_modify_con(struct 
mgcp_parse_data *p)
        int error_code = 500;
        int silent = 0;
        char *line;
+       const char *local_options = NULL;
 
        if (p->found != 0)
                return create_err_response(NULL, 510, "MDCX", p->trans);
@@ -806,7 +871,7 @@ static struct msgb *handle_modify_con(struct 
mgcp_parse_data *p)
                        break;
                }
                case 'L':
-                       /* skip */
+                       local_options = (const char *) line + 3;
                        break;
                case 'M':
                        if (parse_conn_mode(line + 3, &endp->conn_mode) != 0) {
@@ -832,6 +897,12 @@ static struct msgb *handle_modify_con(struct 
mgcp_parse_data *p)
                }
        }
 
+       if (local_options) {
+               endp->local_options = talloc_strdup(endp->tcfg->endpoints,
+                                                   local_options);
+               parse_local_cx_options(&endp->net_end, local_options);
+       }
+
        /* policy CB */
        if (p->cfg->policy_cb) {
                int rc;
diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c
index 11e4b56..fb056e6 100644
--- a/openbsc/tests/mgcp/mgcp_test.c
+++ b/openbsc/tests/mgcp/mgcp_test.c
@@ -628,6 +628,10 @@ static void test_packet_error_detection(int patch_ssrc, 
int patch_ts)
         * trunk.endpoints are set up properly. */
        mgcp_free_endp(&endp);
 
+       /* There is no MGCP/SDP around, so set this by hand to make timestamp
+        * patching possible */
+       rtp->packet_duration_ms = 20;
+
        rtp->payload_type = 98;
 
        for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
diff --git a/openbsc/tests/mgcp/mgcp_test.ok b/openbsc/tests/mgcp/mgcp_test.ok
index 5c6fe37..32af3b5 100644
--- a/openbsc/tests/mgcp/mgcp_test.ok
+++ b/openbsc/tests/mgcp/mgcp_test.ok
@@ -16,19 +16,19 @@ Testing AUEP2
 Testing MDCX1
 Testing MDCX2
 Testing CRCX
-Packet duration not set
+Detected packet duration: 20
 Testing MDCX3
 Packet duration not set
 Testing MDCX4
-Packet duration not set
+Detected packet duration: 20
 Testing MDCX4_PT1
-Packet duration not set
+Detected packet duration: 0
 Testing MDCX4_PT2
-Packet duration not set
+Detected packet duration: 20
 Testing MDCX4_PT3
-Packet duration not set
+Detected packet duration: 40
 Testing DLCX
-Detected packet duration: 20
+Detected packet duration: 0
 Testing CRCX_ZYN
 Packet duration not set
 Testing EMPTY
@@ -39,7 +39,7 @@ Testing SHORT4
 Testing RQNT1
 Testing RQNT2
 Testing DLCX
-Detected packet duration: 20
+Detected packet duration: 0
 Testing CRCX
 Re-transmitting CRCX
 Testing RQNT1
-- 
1.7.9.5


Reply via email to