This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.
Jacob Erlbeck jerlbeck at sysmocom.deThis 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