From 83c052373907c1cdaa134b5a7420eacabd893901 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Tue, 3 Dec 2013 12:48:07 +0100 Subject: [PATCH 01/10] mgcp/rtp: Add more test cases for RTP header patching This patch extends the existing RTP error check test by adding a check for timestamp errors after SSRC changes and a check for a segno delta of 2 (with a timestamp delta of 320). To test SSRC patching too, a corresponding line will be written on each SSRC change that has been detected in the output stream. In addition there is now support for selectively enabling/disabling SSRC and timestamp patching. The RTP test sequence is repeated for all combinations thereof. Sponsored-by: On-Waves ehf --- openbsc/tests/mgcp/mgcp_test.c | 40 +++++++++++++++-- openbsc/tests/mgcp/mgcp_test.ok | 80 ++++++++++++++++++++++++++++++++- 2 files changed, 115 insertions(+), 5 deletions(-) diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c index c58f52d9e..8e130bbd8 100644 --- a/openbsc/tests/mgcp/mgcp_test.c +++ b/openbsc/tests/mgcp/mgcp_test.c @@ -510,13 +510,33 @@ struct rtp_packet_info test_rtp_packets1[] = { /* RTP: SeqNo=14, TS=35008 */ {0.280000, 20, "\x80\x62\x00\x0E\x00\x00\x88\xC0\x10\x20\x30\x40" "\x01\x23\x45\x67\x89\xAB\xCD\xEF"}, + /* Non 20ms RTP timestamp (delta = 120): */ + /* RTP: SeqNo=15, TS=35128 */ + {0.300000, 20, "\x80\x62\x00\x0F\x00\x00\x89\x38\x10\x20\x30\x40" + "\x01\x23\x45\x67\x89\xAB\xCD\xEF"}, + /* RTP: SeqNo=16, TS=35288 */ + {0.320000, 20, "\x80\x62\x00\x10\x00\x00\x89\xD8\x10\x20\x30\x40" + "\x01\x23\x45\x67\x89\xAB\xCD\xEF"}, + /* RTP: SeqNo=17, TS=35448 */ + {0.340000, 20, "\x80\x62\x00\x11\x00\x00\x8A\x78\x10\x20\x30\x40" + "\x01\x23\x45\x67\x8A\xAB\xCD\xEF"}, + /* SeqNo increment by 2, RTP timestamp delta = 320: */ + /* RTP: SeqNo=19, TS=35768 */ + {0.360000, 20, "\x80\x62\x00\x13\x00\x00\x8B\xB8\x10\x20\x30\x40" + "\x01\x23\x45\x67\x89\xAB\xCD\xEF"}, + /* RTP: SeqNo=20, TS=35928 */ + {0.380000, 20, "\x80\x62\x00\x14\x00\x00\x8C\x58\x10\x20\x30\x40" + "\x01\x23\x45\x67\x89\xAB\xCD\xEF"}, + /* RTP: SeqNo=21, TS=36088 */ + {0.380000, 20, "\x80\x62\x00\x14\x00\x00\x8C\xF8\x10\x20\x30\x40" + "\x01\x23\x45\x67\x89\xAB\xCD\xEF"}, }; void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state, struct mgcp_rtp_end *rtp_end, struct sockaddr_in *addr, char *data, int len); -static void test_packet_error_detection(void) +static void test_packet_error_detection(int patch_ssrc, int patch_ts) { int i; @@ -526,8 +546,11 @@ static void test_packet_error_detection(void) struct mgcp_rtp_end *rtp = &endp.net_end; struct sockaddr_in addr = {0}; char buffer[4096]; + uint32_t last_ssrc = 0; - printf("Testing packet error detection.\n"); + printf("Testing packet error detection%s%s.\n", + patch_ssrc ? ", patch SSRC" : "", + patch_ts ? ", patch timestamps" : ""); memset(&trunk, 0, sizeof(trunk)); memset(&endp, 0, sizeof(endp)); @@ -545,7 +568,7 @@ static void test_packet_error_detection(void) mgcp_free_endp(&endp); rtp->payload_type = 98; - endp.allow_patch = 1; + endp.allow_patch = patch_ssrc; for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) { struct rtp_packet_info *info = test_rtp_packets1 + i; @@ -557,6 +580,12 @@ static void test_packet_error_detection(void) mgcp_patch_and_count(&endp, &state, rtp, &addr, buffer, info->len); + if (state.out_stream.ssrc != last_ssrc) { + printf("Output SSRC changed to %08x\n", + ntohl(state.out_stream.ssrc)); + last_ssrc = state.out_stream.ssrc; + } + printf("TS: %d, dTS: %d, TS Errs: in %d, out %d\n", state.out_stream.last_timestamp, state.out_stream.last_tsdelta, @@ -575,7 +604,10 @@ int main(int argc, char **argv) test_packet_loss_calc(); test_rqnt_cb(); test_mgcp_stats(); - test_packet_error_detection(); + test_packet_error_detection(1, 0); + test_packet_error_detection(0, 0); + test_packet_error_detection(0, 1); + test_packet_error_detection(1, 1); printf("Done\n"); return EXIT_SUCCESS; diff --git a/openbsc/tests/mgcp/mgcp_test.ok b/openbsc/tests/mgcp/mgcp_test.ok index 3bfd78b3d..57d3bfbcb 100644 --- a/openbsc/tests/mgcp/mgcp_test.ok +++ b/openbsc/tests/mgcp/mgcp_test.ok @@ -42,7 +42,8 @@ Testing packet loss calculation. Testing stat parsing Parsing result: 0 Parsing result: 0 -Testing packet error detection. +Testing packet error detection, patch SSRC. +Output SSRC changed to 11223344 TS: 0, dTS: 0, TS Errs: in 0, out 0 TS: 160, dTS: 160, TS Errs: in 0, out 0 TS: 320, dTS: 160, TS Errs: in 0, out 0 @@ -58,4 +59,81 @@ TS: 1720, dTS: 160, TS Errs: in 5, out 5 TS: 1880, dTS: 160, TS Errs: in 5, out 5 TS: 2040, dTS: 160, TS Errs: in 5, out 5 TS: 2200, dTS: 160, TS Errs: in 5, out 5 +TS: 2320, dTS: 120, TS Errs: in 6, out 6 +TS: 2480, dTS: 160, TS Errs: in 7, out 7 +TS: 2640, dTS: 160, TS Errs: in 7, out 7 +TS: 2960, dTS: 160, TS Errs: in 7, out 7 +TS: 3120, dTS: 160, TS Errs: in 7, out 7 +TS: 3280, dTS: 160, TS Errs: in 8, out 8 +Testing packet error detection. +Output SSRC changed to 11223344 +TS: 0, dTS: 0, TS Errs: in 0, out 0 +TS: 160, dTS: 160, TS Errs: in 0, out 0 +TS: 320, dTS: 160, TS Errs: in 0, out 0 +TS: 320, dTS: 160, TS Errs: in 1, out 1 +TS: 480, dTS: 160, TS Errs: in 1, out 1 +TS: 640, dTS: 160, TS Errs: in 1, out 1 +TS: 960, dTS: 320, TS Errs: in 2, out 2 +TS: 1120, dTS: 160, TS Errs: in 3, out 3 +TS: 1280, dTS: 160, TS Errs: in 3, out 3 +TS: 1400, dTS: 120, TS Errs: in 4, out 4 +TS: 1560, dTS: 160, TS Errs: in 5, out 5 +TS: 1720, dTS: 160, TS Errs: in 5, out 5 +Output SSRC changed to 10203040 +TS: 34688, dTS: 32968, TS Errs: in 5, out 6 +TS: 34848, dTS: 160, TS Errs: in 5, out 7 +TS: 35008, dTS: 160, TS Errs: in 5, out 7 +TS: 35128, dTS: 120, TS Errs: in 6, out 8 +TS: 35288, dTS: 160, TS Errs: in 7, out 9 +TS: 35448, dTS: 160, TS Errs: in 7, out 9 +TS: 35768, dTS: 160, TS Errs: in 7, out 9 +TS: 35928, dTS: 160, TS Errs: in 7, out 9 +TS: 36088, dTS: 160, TS Errs: in 8, out 10 +Testing packet error detection, patch timestamps. +Output SSRC changed to 11223344 +TS: 0, dTS: 0, TS Errs: in 0, out 0 +TS: 160, dTS: 160, TS Errs: in 0, out 0 +TS: 320, dTS: 160, TS Errs: in 0, out 0 +TS: 320, dTS: 160, TS Errs: in 1, out 1 +TS: 480, dTS: 160, TS Errs: in 1, out 1 +TS: 640, dTS: 160, TS Errs: in 1, out 1 +TS: 960, dTS: 320, TS Errs: in 2, out 2 +TS: 1120, dTS: 160, TS Errs: in 3, out 3 +TS: 1280, dTS: 160, TS Errs: in 3, out 3 +TS: 1400, dTS: 120, TS Errs: in 4, out 4 +TS: 1560, dTS: 160, TS Errs: in 5, out 5 +TS: 1720, dTS: 160, TS Errs: in 5, out 5 +Output SSRC changed to 10203040 +TS: 34688, dTS: 32968, TS Errs: in 5, out 6 +TS: 34848, dTS: 160, TS Errs: in 5, out 7 +TS: 35008, dTS: 160, TS Errs: in 5, out 7 +TS: 35128, dTS: 120, TS Errs: in 6, out 8 +TS: 35288, dTS: 160, TS Errs: in 7, out 9 +TS: 35448, dTS: 160, TS Errs: in 7, out 9 +TS: 35768, dTS: 160, TS Errs: in 7, out 9 +TS: 35928, dTS: 160, TS Errs: in 7, out 9 +TS: 36088, dTS: 160, TS Errs: in 8, out 10 +Testing packet error detection, patch SSRC, patch timestamps. +Output SSRC changed to 11223344 +TS: 0, dTS: 0, TS Errs: in 0, out 0 +TS: 160, dTS: 160, TS Errs: in 0, out 0 +TS: 320, dTS: 160, TS Errs: in 0, out 0 +TS: 320, dTS: 160, TS Errs: in 1, out 1 +TS: 480, dTS: 160, TS Errs: in 1, out 1 +TS: 640, dTS: 160, TS Errs: in 1, out 1 +TS: 960, dTS: 320, TS Errs: in 2, out 2 +TS: 1120, dTS: 160, TS Errs: in 3, out 3 +TS: 1280, dTS: 160, TS Errs: in 3, out 3 +TS: 1400, dTS: 120, TS Errs: in 4, out 4 +TS: 1560, dTS: 160, TS Errs: in 5, out 5 +TS: 1720, dTS: 160, TS Errs: in 5, out 5 +TS: 1880, dTS: 160, TS Errs: in 5, out 5 +TS: 2040, dTS: 160, TS Errs: in 5, out 5 +TS: 2200, dTS: 160, TS Errs: in 5, out 5 +TS: 2320, dTS: 120, TS Errs: in 6, out 6 +TS: 2480, dTS: 160, TS Errs: in 7, out 7 +TS: 2640, dTS: 160, TS Errs: in 7, out 7 +TS: 2960, dTS: 160, TS Errs: in 7, out 7 +TS: 3120, dTS: 160, TS Errs: in 7, out 7 +TS: 3280, dTS: 160, TS Errs: in 8, out 8 Done From 55ba140da126c78013fe1a6055d750ee10b60ecf Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Fri, 29 Nov 2013 11:16:07 +0100 Subject: [PATCH 02/10] mgcp/rtp: Fix output timing error counter The tsdelta computation and error detection didn't handle the intialisation phase properly. This patches fixes this by skipping the output timing validation when the SSRCs don't match. Sponsored-by: On-Waves ehf --- openbsc/src/libmgcp/mgcp_network.c | 17 +++++++++++--- openbsc/tests/mgcp/mgcp_test.ok | 36 +++++++++++++++--------------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index 75d39c195..53f1a20e9 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -237,6 +237,16 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta state->jitter = 0; state->transit = arrival_time - timestamp; state->out_stream = state->in_stream; + state->out_stream.last_timestamp = timestamp; + /* force output SSRC change */ + state->out_stream.ssrc = rtp_hdr->ssrc - 1; + LOGP(DMGCP, LOGL_INFO, + "Initializing stream on 0x%x SSRC: %u timestamp: %u " + "from %s:%d in %d\n", + ENDPOINT_NUMBER(endp), state->in_stream.ssrc, + state->seq_offset, + inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), + endp->conn_mode); } else if (state->in_stream.ssrc != rtp_hdr->ssrc) { int32_t tsdelta = state->out_stream.last_tsdelta; if (tsdelta == 0) { @@ -286,9 +296,10 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta } /* Check again, whether the timestamps are still valid */ - check_rtp_timestamp(endp, &state->out_stream, rtp_end, addr, - seq, timestamp, "output", - &state->out_stream.last_tsdelta); + if (state->out_stream.ssrc == rtp_hdr->ssrc) + check_rtp_timestamp(endp, &state->out_stream, rtp_end, addr, + seq, timestamp, "output", + &state->out_stream.last_tsdelta); /* * The below takes the shape of the validation from Appendix A. Check diff --git a/openbsc/tests/mgcp/mgcp_test.ok b/openbsc/tests/mgcp/mgcp_test.ok index 57d3bfbcb..4d3caacb5 100644 --- a/openbsc/tests/mgcp/mgcp_test.ok +++ b/openbsc/tests/mgcp/mgcp_test.ok @@ -80,15 +80,15 @@ TS: 1400, dTS: 120, TS Errs: in 4, out 4 TS: 1560, dTS: 160, TS Errs: in 5, out 5 TS: 1720, dTS: 160, TS Errs: in 5, out 5 Output SSRC changed to 10203040 -TS: 34688, dTS: 32968, TS Errs: in 5, out 6 -TS: 34848, dTS: 160, TS Errs: in 5, out 7 -TS: 35008, dTS: 160, TS Errs: in 5, out 7 -TS: 35128, dTS: 120, TS Errs: in 6, out 8 -TS: 35288, dTS: 160, TS Errs: in 7, out 9 -TS: 35448, dTS: 160, TS Errs: in 7, out 9 -TS: 35768, dTS: 160, TS Errs: in 7, out 9 -TS: 35928, dTS: 160, TS Errs: in 7, out 9 -TS: 36088, dTS: 160, TS Errs: in 8, out 10 +TS: 34688, dTS: 160, TS Errs: in 5, out 5 +TS: 34848, dTS: 160, TS Errs: in 5, out 5 +TS: 35008, dTS: 160, TS Errs: in 5, out 5 +TS: 35128, dTS: 120, TS Errs: in 6, out 6 +TS: 35288, dTS: 160, TS Errs: in 7, out 7 +TS: 35448, dTS: 160, TS Errs: in 7, out 7 +TS: 35768, dTS: 160, TS Errs: in 7, out 7 +TS: 35928, dTS: 160, TS Errs: in 7, out 7 +TS: 36088, dTS: 160, TS Errs: in 8, out 8 Testing packet error detection, patch timestamps. Output SSRC changed to 11223344 TS: 0, dTS: 0, TS Errs: in 0, out 0 @@ -104,15 +104,15 @@ TS: 1400, dTS: 120, TS Errs: in 4, out 4 TS: 1560, dTS: 160, TS Errs: in 5, out 5 TS: 1720, dTS: 160, TS Errs: in 5, out 5 Output SSRC changed to 10203040 -TS: 34688, dTS: 32968, TS Errs: in 5, out 6 -TS: 34848, dTS: 160, TS Errs: in 5, out 7 -TS: 35008, dTS: 160, TS Errs: in 5, out 7 -TS: 35128, dTS: 120, TS Errs: in 6, out 8 -TS: 35288, dTS: 160, TS Errs: in 7, out 9 -TS: 35448, dTS: 160, TS Errs: in 7, out 9 -TS: 35768, dTS: 160, TS Errs: in 7, out 9 -TS: 35928, dTS: 160, TS Errs: in 7, out 9 -TS: 36088, dTS: 160, TS Errs: in 8, out 10 +TS: 34688, dTS: 160, TS Errs: in 5, out 5 +TS: 34848, dTS: 160, TS Errs: in 5, out 5 +TS: 35008, dTS: 160, TS Errs: in 5, out 5 +TS: 35128, dTS: 120, TS Errs: in 6, out 6 +TS: 35288, dTS: 160, TS Errs: in 7, out 7 +TS: 35448, dTS: 160, TS Errs: in 7, out 7 +TS: 35768, dTS: 160, TS Errs: in 7, out 7 +TS: 35928, dTS: 160, TS Errs: in 7, out 7 +TS: 36088, dTS: 160, TS Errs: in 8, out 8 Testing packet error detection, patch SSRC, patch timestamps. Output SSRC changed to 11223344 TS: 0, dTS: 0, TS Errs: in 0, out 0 From db2d431697609d473de433b7028f81ce499a02c0 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Tue, 3 Dec 2013 14:43:34 +0100 Subject: [PATCH 03/10] mgcp/rtp: Add RTP header patch mode configuration This adds datastructures and a VTY frontend to configure the different type of RTP header patching: SSRC and timestamp. Note that timestamp patching is not yet implemented. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp.h | 4 + openbsc/include/openbsc/mgcp_internal.h | 10 +- openbsc/src/libmgcp/mgcp_network.c | 2 +- openbsc/src/libmgcp/mgcp_protocol.c | 21 +++- openbsc/src/libmgcp/mgcp_vty.c | 145 +++++++++++++++++++++++- openbsc/tests/mgcp/mgcp_test.c | 6 +- 6 files changed, 181 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 4e22e0f5e..8ab52ce1a 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -118,6 +118,10 @@ struct mgcp_trunk_config { int omit_rtcp; + /* RTP patching */ + int force_constant_ssrc; /* 0: don't, 1: once */ + int force_constant_timing; + /* spec handling */ int force_realloc; diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 0b52c1c06..02e193df2 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -83,6 +83,10 @@ struct mgcp_rtp_end { int frames_per_packet; char *fmtp_extra; + /* RTP patching */ + int force_constant_ssrc; + int force_constant_timing; + /* * Each end has a socket... */ @@ -142,9 +146,6 @@ struct mgcp_endpoint { struct mgcp_rtp_state net_state; struct mgcp_rtp_state bts_state; - /* SSRC/seq/ts patching for loop */ - int allow_patch; - /* fields for re-transmission */ char *last_trans; char *last_response; @@ -176,6 +177,9 @@ static inline int endp_back_channel(int endpoint) struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int index); struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index); +void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change, + struct mgcp_rtp_end *rtp); + void mgcp_state_calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *, uint32_t *expected, int *loss); uint32_t mgcp_state_calc_jitter(struct mgcp_rtp_state *); diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index 53f1a20e9..367cebd9b 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -264,7 +264,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta state->seq_offset = (state->out_stream.last_seq + 1) - seq; state->timestamp_offset = (state->out_stream.last_timestamp + tsdelta) - timestamp; - state->patch = endp->allow_patch; + state->patch = rtp_end->force_constant_ssrc; LOGP(DMGCP, LOGL_NOTICE, "The SSRC changed on 0x%x SSRC: %u offset: %d tsdelta: %d " "from %s:%d in %d\n", diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index a0b905de0..c703bec13 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -614,6 +614,21 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) return found_media; } +void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change, + struct mgcp_rtp_end *rtp) +{ + struct mgcp_trunk_config *tcfg = endp->tcfg; + + rtp->force_constant_timing = tcfg->force_constant_timing; + rtp->force_constant_ssrc = tcfg->force_constant_ssrc; + + LOGP(DMGCP, LOGL_DEBUG, + "Configuring RTP endpoint: local port %d%s%s\n", + ntohs(rtp->rtp_port), + rtp->force_constant_timing ? ", force constant timing" : "", + rtp->force_constant_ssrc ? ", force constant ssrc" : ""); +} + static struct msgb *handle_create_con(struct mgcp_parse_data *p) { struct mgcp_trunk_config *tcfg; @@ -688,6 +703,8 @@ mgcp_header_done: /* initialize */ endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0; + mgcp_rtp_end_config(endp, 0, &endp->net_end); + mgcp_rtp_end_config(endp, 0, &endp->bts_end); /* set to zero until we get the info */ memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr)); @@ -825,6 +842,9 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) } } + mgcp_rtp_end_config(endp, 1, &endp->net_end); + mgcp_rtp_end_config(endp, 1, &endp->bts_end); + /* modify */ LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n", ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port)); @@ -1121,7 +1141,6 @@ void mgcp_free_endp(struct mgcp_endpoint *endp) memset(&endp->bts_state, 0, sizeof(endp->bts_state)); endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE; - endp->allow_patch = 0; memset(&endp->taps, 0, sizeof(endp->taps)); } diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c index 5aeb3930e..e48b0503e 100644 --- a/openbsc/src/libmgcp/mgcp_vty.c +++ b/openbsc/src/libmgcp/mgcp_vty.c @@ -31,6 +31,7 @@ #include #define RTCP_OMIT_STR "Drop RTCP packets in both directions\n" +#define RTP_PATCH_STR "Modify RTP packet header in both directions\n" static struct mgcp_config *g_cfg = NULL; @@ -88,6 +89,13 @@ static int config_write_mgcp(struct vty *vty) vty_out(vty, " rtcp-omit%s", VTY_NEWLINE); else vty_out(vty, " no rtcp-omit%s", VTY_NEWLINE); + if (g_cfg->trunk.force_constant_ssrc || g_cfg->trunk.force_constant_timing) { + vty_out(vty, " %srtp-patch ssrc%s", + g_cfg->trunk.force_constant_ssrc ? "" : "no ", VTY_NEWLINE); + vty_out(vty, " %srtp-patch timestamp%s", + g_cfg->trunk.force_constant_timing ? "" : "no ", VTY_NEWLINE); + } else + vty_out(vty, " no rtp-patch%s", VTY_NEWLINE); if (g_cfg->trunk.audio_payload != -1) vty_out(vty, " sdp audio-payload number %d%s", g_cfg->trunk.audio_payload, VTY_NEWLINE); @@ -421,6 +429,61 @@ DEFUN(cfg_mgcp_no_omit_rtcp, return CMD_SUCCESS; } +DEFUN(cfg_mgcp_patch_rtp_ssrc, + cfg_mgcp_patch_rtp_ssrc_cmd, + "rtp-patch ssrc", + RTP_PATCH_STR + "Force a fixed SSRC\n" + ) +{ + g_cfg->trunk.force_constant_ssrc = 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_no_patch_rtp_ssrc, + cfg_mgcp_no_patch_rtp_ssrc_cmd, + "no rtp-patch ssrc", + NO_STR RTP_PATCH_STR + "Force a fixed SSRC\n" + ) +{ + g_cfg->trunk.force_constant_ssrc = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_patch_rtp_ts, + cfg_mgcp_patch_rtp_ts_cmd, + "rtp-patch timestamp", + RTP_PATCH_STR + "Adjust RTP timestamp\n" + ) +{ + g_cfg->trunk.force_constant_timing = 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_no_patch_rtp_ts, + cfg_mgcp_no_patch_rtp_ts_cmd, + "no rtp-patch timestamp", + NO_STR RTP_PATCH_STR + "Adjust RTP timestamp\n" + ) +{ + g_cfg->trunk.force_constant_timing = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_no_patch_rtp, + cfg_mgcp_no_patch_rtp_cmd, + "no rtp-patch", + NO_STR RTP_PATCH_STR) +{ + g_cfg->trunk.force_constant_ssrc = 0; + g_cfg->trunk.force_constant_timing = 0; + return CMD_SUCCESS; +} + + #define CALL_AGENT_STR "Callagent information\n" DEFUN(cfg_mgcp_agent_addr, cfg_mgcp_agent_addr_cmd, @@ -511,6 +574,13 @@ static int config_write_trunk(struct vty *vty) vty_out(vty, " rtcp-omit%s", VTY_NEWLINE); else vty_out(vty, " no rtcp-omit%s", VTY_NEWLINE); + if (trunk->force_constant_ssrc || trunk->force_constant_timing) { + vty_out(vty, " %srtp-patch ssrc%s", + trunk->force_constant_ssrc ? "" : "no ", VTY_NEWLINE); + vty_out(vty, " %srtp-patch timestamp%s", + trunk->force_constant_timing ? "" : "no ", VTY_NEWLINE); + } else + vty_out(vty, " no rtp-patch%s", VTY_NEWLINE); if (trunk->audio_fmtp_extra) vty_out(vty, " sdp audio fmtp-extra %s%s", trunk->audio_fmtp_extra, VTY_NEWLINE); @@ -599,6 +669,66 @@ DEFUN(cfg_trunk_no_omit_rtcp, return CMD_SUCCESS; } +DEFUN(cfg_trunk_patch_rtp_ssrc, + cfg_trunk_patch_rtp_ssrc_cmd, + "rtp-patch ssrc", + RTP_PATCH_STR + "Force a fixed SSRC\n" + ) +{ + struct mgcp_trunk_config *trunk = vty->index; + trunk->force_constant_ssrc = 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_trunk_no_patch_rtp_ssrc, + cfg_trunk_no_patch_rtp_ssrc_cmd, + "no rtp-patch ssrc", + NO_STR RTP_PATCH_STR + "Force a fixed SSRC\n" + ) +{ + struct mgcp_trunk_config *trunk = vty->index; + trunk->force_constant_ssrc = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_trunk_patch_rtp_ts, + cfg_trunk_patch_rtp_ts_cmd, + "rtp-patch timestamp", + RTP_PATCH_STR + "Adjust RTP timestamp\n" + ) +{ + struct mgcp_trunk_config *trunk = vty->index; + trunk->force_constant_timing = 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_trunk_no_patch_rtp_ts, + cfg_trunk_no_patch_rtp_ts_cmd, + "no rtp-patch timestamp", + NO_STR RTP_PATCH_STR + "Adjust RTP timestamp\n" + ) +{ + struct mgcp_trunk_config *trunk = vty->index; + trunk->force_constant_timing = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_trunk_no_patch_rtp, + cfg_trunk_no_patch_rtp_cmd, + "no rtp-patch", + NO_STR RTP_PATCH_STR) +{ + struct mgcp_trunk_config *trunk = vty->index; + trunk->force_constant_ssrc = 0; + trunk->force_constant_timing = 0; + return CMD_SUCCESS; +} + + DEFUN(loop_endp, loop_endp_cmd, "loop-endpoint <0-64> NAME (0|1)", @@ -636,7 +766,10 @@ DEFUN(loop_endp, endp->conn_mode = MGCP_CONN_LOOPBACK; else endp->conn_mode = endp->orig_mode; - endp->allow_patch = 1; + + /* Handle it like a MDCX, switch on SSRC patching if enabled */ + mgcp_rtp_end_config(endp, 1, &endp->bts_end); + mgcp_rtp_end_config(endp, 1, &endp->net_end); return CMD_SUCCESS; } @@ -827,6 +960,11 @@ int mgcp_vty_init(void) install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd); install_element(MGCP_NODE, &cfg_mgcp_omit_rtcp_cmd); install_element(MGCP_NODE, &cfg_mgcp_no_omit_rtcp_cmd); + install_element(MGCP_NODE, &cfg_mgcp_patch_rtp_ssrc_cmd); + install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_ssrc_cmd); + install_element(MGCP_NODE, &cfg_mgcp_patch_rtp_ts_cmd); + install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_ts_cmd); + install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_cmd); install_element(MGCP_NODE, &cfg_mgcp_sdp_fmtp_extra_cmd); install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd); @@ -839,6 +977,11 @@ int mgcp_vty_init(void) install_element(TRUNK_NODE, &cfg_trunk_loop_cmd); install_element(TRUNK_NODE, &cfg_trunk_omit_rtcp_cmd); install_element(TRUNK_NODE, &cfg_trunk_no_omit_rtcp_cmd); + install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_ssrc_cmd); + install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ssrc_cmd); + install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_ts_cmd); + install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ts_cmd); + install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_cmd); install_element(TRUNK_NODE, &cfg_trunk_sdp_fmtp_extra_cmd); return 0; diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c index 8e130bbd8..908773a69 100644 --- a/openbsc/tests/mgcp/mgcp_test.c +++ b/openbsc/tests/mgcp/mgcp_test.c @@ -558,6 +558,9 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts) trunk.number_endpoints = 1; trunk.endpoints = &endp; + trunk.force_constant_ssrc = patch_ssrc; + trunk.force_constant_timing = patch_ts; + endp.tcfg = &trunk; /* This doesn't free endp but resets/frees all fields of the structure @@ -568,7 +571,6 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts) mgcp_free_endp(&endp); rtp->payload_type = 98; - endp.allow_patch = patch_ssrc; for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) { struct rtp_packet_info *info = test_rtp_packets1 + i; @@ -577,6 +579,8 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts) OSMO_ASSERT(info->len >= 0); memmove(buffer, info->data, info->len); + mgcp_rtp_end_config(&endp, 1, rtp); + mgcp_patch_and_count(&endp, &state, rtp, &addr, buffer, info->len); From 5e9549e6a968fa0b5ef313a3e5a2622ceff42839 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Thu, 5 Dec 2013 12:20:05 +0100 Subject: [PATCH 04/10] mgcp/rtp: Change the log message shown when the SSRC changes Show old and new SSRC. Move logging command upward to show the values immediately after the change has been detected and before any fixing attempt is made. Sponsored-by: On-Waves ehf --- openbsc/src/libmgcp/mgcp_network.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index 367cebd9b..d19b56e4c 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -249,6 +249,15 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta endp->conn_mode); } else if (state->in_stream.ssrc != rtp_hdr->ssrc) { int32_t tsdelta = state->out_stream.last_tsdelta; + + LOGP(DMGCP, LOGL_NOTICE, + "The SSRC changed on 0x%x: %u -> %u " + "from %s:%d in %d\n", + ENDPOINT_NUMBER(endp), + state->in_stream.ssrc, rtp_hdr->ssrc, + inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), + endp->conn_mode); + if (tsdelta == 0) { tsdelta = rtp_end->rate * rtp_end->frames_per_packet * rtp_end->frame_duration_num / @@ -265,13 +274,6 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta state->timestamp_offset = (state->out_stream.last_timestamp + tsdelta) - timestamp; state->patch = rtp_end->force_constant_ssrc; - LOGP(DMGCP, LOGL_NOTICE, - "The SSRC changed on 0x%x SSRC: %u offset: %d tsdelta: %d " - "from %s:%d in %d\n", - ENDPOINT_NUMBER(endp), state->in_stream.ssrc, - state->seq_offset, tsdelta, - inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), - endp->conn_mode); state->in_stream.last_tsdelta = 0; } else { From b35a77751b278c7c81e6cc012df2d113f10b3116 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Thu, 5 Dec 2013 11:33:20 +0100 Subject: [PATCH 05/10] mgcp/rtp: Only update RTP header field offsets if enabled Currently seq_offset and timestamp_offset are updated on each SSRC change even when SSRC patching is not allowed. This patch fixes this by changing mgcp_patch_and_count() to only update these fields when SSRC patching is allowed. Sponsored-by: On-Waves ehf --- openbsc/src/libmgcp/mgcp_network.c | 46 +++++++++++++++++++----------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index d19b56e4c..c14b9133b 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -248,8 +248,6 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), endp->conn_mode); } else if (state->in_stream.ssrc != rtp_hdr->ssrc) { - int32_t tsdelta = state->out_stream.last_tsdelta; - LOGP(DMGCP, LOGL_NOTICE, "The SSRC changed on 0x%x: %u -> %u " "from %s:%d in %d\n", @@ -258,22 +256,36 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), endp->conn_mode); - if (tsdelta == 0) { - tsdelta = rtp_end->rate * rtp_end->frames_per_packet * - rtp_end->frame_duration_num / - rtp_end->frame_duration_den; - LOGP(DMGCP, LOGL_NOTICE, - "Computed timestamp delta %d based on " - "rate %d, num frames %d, frame duration %d/%d\n", - tsdelta, rtp_end->rate, rtp_end->frames_per_packet, - rtp_end->frame_duration_num, - rtp_end->frame_duration_den); - } state->in_stream.ssrc = rtp_hdr->ssrc; - state->seq_offset = (state->out_stream.last_seq + 1) - seq; - state->timestamp_offset = - (state->out_stream.last_timestamp + tsdelta) - timestamp; - state->patch = rtp_end->force_constant_ssrc; + if (rtp_end->force_constant_ssrc) { + int32_t tsdelta = state->out_stream.last_tsdelta; + if (tsdelta == 0) { + tsdelta = rtp_end->rate * rtp_end->frames_per_packet * + rtp_end->frame_duration_num / + rtp_end->frame_duration_den; + LOGP(DMGCP, LOGL_NOTICE, + "Computed timestamp delta %d based on " + "rate %d, num frames %d, frame duration %d/%d\n", + tsdelta, rtp_end->rate, rtp_end->frames_per_packet, + rtp_end->frame_duration_num, + rtp_end->frame_duration_den); + } + state->seq_offset = + (state->out_stream.last_seq + 1) - seq; + state->timestamp_offset = + (state->out_stream.last_timestamp + tsdelta) - + timestamp; + state->patch = 1; + + LOGP(DMGCP, LOGL_NOTICE, + "SSRC patching enabled on 0x%x SSRC: %u " + "offset: %d tsdelta: %d " + "from %s:%d in %d\n", + ENDPOINT_NUMBER(endp), state->in_stream.ssrc, + state->seq_offset, tsdelta, + inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), + endp->conn_mode); + } state->in_stream.last_tsdelta = 0; } else { From 30ce42250f56c930872228604edd7dd0836ec77a Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Thu, 5 Dec 2013 12:02:15 +0100 Subject: [PATCH 06/10] mgcp/rtp: Compute default packet duration at state initialisiation This patch adds a packet_duration field to mgcp_rtp_state which contains the RTP packet's duration in RTP timestamp units or 0, when the duration is unknown or not fixed. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp_internal.h | 1 + openbsc/src/libmgcp/mgcp_network.c | 23 +++++++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 02e193df2..b16bd49a4 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -59,6 +59,7 @@ struct mgcp_rtp_state { int cycles; int32_t timestamp_offset; + uint32_t packet_duration; uint32_t jitter; int32_t transit; diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index c14b9133b..f177339b4 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -236,15 +236,19 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta state->initialized = 1; state->jitter = 0; state->transit = arrival_time - timestamp; + state->packet_duration = + rtp_end->rate * rtp_end->frames_per_packet * + rtp_end->frame_duration_num / + rtp_end->frame_duration_den; state->out_stream = state->in_stream; state->out_stream.last_timestamp = timestamp; /* force output SSRC change */ state->out_stream.ssrc = rtp_hdr->ssrc - 1; LOGP(DMGCP, LOGL_INFO, "Initializing stream on 0x%x SSRC: %u timestamp: %u " - "from %s:%d in %d\n", + "pkt-duration: %d, from %s:%d in %d\n", ENDPOINT_NUMBER(endp), state->in_stream.ssrc, - state->seq_offset, + state->seq_offset, state->packet_duration, inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), endp->conn_mode); } else if (state->in_stream.ssrc != rtp_hdr->ssrc) { @@ -260,15 +264,14 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta if (rtp_end->force_constant_ssrc) { int32_t tsdelta = state->out_stream.last_tsdelta; if (tsdelta == 0) { - tsdelta = rtp_end->rate * rtp_end->frames_per_packet * - rtp_end->frame_duration_num / - rtp_end->frame_duration_den; + tsdelta = state->packet_duration; LOGP(DMGCP, LOGL_NOTICE, - "Computed timestamp delta %d based on " - "rate %d, num frames %d, frame duration %d/%d\n", - tsdelta, rtp_end->rate, rtp_end->frames_per_packet, - rtp_end->frame_duration_num, - rtp_end->frame_duration_den); + "Timestamp delta is not available on 0x%x, " + "using packet duration instead: %d " + "from %s:%d in %d\n", + ENDPOINT_NUMBER(endp), tsdelta, + inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), + endp->conn_mode); } state->seq_offset = (state->out_stream.last_seq + 1) - seq; From 3da9e4e441ff7b6fb1996f775b39d7c3432ad652 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Tue, 3 Dec 2013 15:47:04 +0100 Subject: [PATCH 07/10] mgcp/rtp: Use SSRC in proper byte ordering The ssrc has been used without respect to proper byte ordering in mgcp_patch_and_count(). This only affected log messages. This patch introduces a new variable 'ssrc' that takes the value of the SSRC in proper byte order. Sponsored-by: On-Waves ehf --- openbsc/src/libmgcp/mgcp_network.c | 22 +++++++++++++--------- openbsc/tests/mgcp/mgcp_test.c | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index f177339b4..abb48f5fa 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -216,7 +216,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta uint32_t arrival_time; int32_t transit, d; uint16_t seq, udelta; - uint32_t timestamp; + uint32_t timestamp, ssrc; struct rtp_hdr *rtp_hdr; int payload = rtp_end->payload_type; @@ -227,10 +227,11 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta seq = ntohs(rtp_hdr->sequence); timestamp = ntohl(rtp_hdr->timestamp); arrival_time = get_current_ts(); + ssrc = ntohl(rtp_hdr->ssrc); if (!state->initialized) { state->in_stream.last_seq = seq - 1; - state->in_stream.ssrc = state->orig_ssrc = rtp_hdr->ssrc; + state->in_stream.ssrc = state->orig_ssrc = ssrc; state->in_stream.last_tsdelta = 0; state->base_seq = seq; state->initialized = 1; @@ -242,8 +243,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta rtp_end->frame_duration_den; state->out_stream = state->in_stream; state->out_stream.last_timestamp = timestamp; - /* force output SSRC change */ - state->out_stream.ssrc = rtp_hdr->ssrc - 1; + state->out_stream.ssrc = ssrc - 1; /* force output SSRC change */ LOGP(DMGCP, LOGL_INFO, "Initializing stream on 0x%x SSRC: %u timestamp: %u " "pkt-duration: %d, from %s:%d in %d\n", @@ -251,7 +251,7 @@ 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); - } else if (state->in_stream.ssrc != rtp_hdr->ssrc) { + } else if (state->in_stream.ssrc != ssrc) { LOGP(DMGCP, LOGL_NOTICE, "The SSRC changed on 0x%x: %u -> %u " "from %s:%d in %d\n", @@ -260,7 +260,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), endp->conn_mode); - state->in_stream.ssrc = rtp_hdr->ssrc; + state->in_stream.ssrc = ssrc; if (rtp_end->force_constant_ssrc) { int32_t tsdelta = state->out_stream.last_tsdelta; if (tsdelta == 0) { @@ -279,6 +279,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta (state->out_stream.last_timestamp + tsdelta) - timestamp; state->patch = 1; + ssrc = state->orig_ssrc; LOGP(DMGCP, LOGL_NOTICE, "SSRC patching enabled on 0x%x SSRC: %u " @@ -296,6 +297,9 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta check_rtp_timestamp(endp, &state->in_stream, rtp_end, addr, seq, timestamp, "input", &state->in_stream.last_tsdelta); + + if (state->patch) + ssrc = state->orig_ssrc; } /* Save before patching */ @@ -306,14 +310,14 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta if (state->patch) { seq += state->seq_offset; rtp_hdr->sequence = htons(seq); - rtp_hdr->ssrc = state->orig_ssrc; + rtp_hdr->ssrc = htonl(ssrc); timestamp += state->timestamp_offset; rtp_hdr->timestamp = htonl(timestamp); } /* Check again, whether the timestamps are still valid */ - if (state->out_stream.ssrc == rtp_hdr->ssrc) + if (state->out_stream.ssrc == ssrc) check_rtp_timestamp(endp, &state->out_stream, rtp_end, addr, seq, timestamp, "output", &state->out_stream.last_tsdelta); @@ -350,7 +354,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta /* Save output values */ state->out_stream.last_seq = seq; state->out_stream.last_timestamp = timestamp; - state->out_stream.ssrc = rtp_hdr->ssrc; + state->out_stream.ssrc = ssrc; if (payload < 0) return; diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c index 908773a69..e5b8bbdd5 100644 --- a/openbsc/tests/mgcp/mgcp_test.c +++ b/openbsc/tests/mgcp/mgcp_test.c @@ -586,7 +586,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts) if (state.out_stream.ssrc != last_ssrc) { printf("Output SSRC changed to %08x\n", - ntohl(state.out_stream.ssrc)); + state.out_stream.ssrc); last_ssrc = state.out_stream.ssrc; } From e2292f3aa1e9ae1faf5521a9cb108775f1ac0540 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Tue, 3 Dec 2013 15:13:12 +0100 Subject: [PATCH 08/10] mgcp/rtp: Only patch SSRC once after MDCX if enabled Currently the output SSRC is always forced to be the same if SSRC patching is enabled. This patch modifies this to optionally restrict the number of SSRC changes that will be corrected. Note that the configuration only allows for the 'once' mode and 'off'. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp_internal.h | 2 +- openbsc/src/libmgcp/mgcp_network.c | 2 ++ openbsc/src/libmgcp/mgcp_protocol.c | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index b16bd49a4..255161f45 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -85,7 +85,7 @@ struct mgcp_rtp_end { char *fmtp_extra; /* RTP patching */ - int force_constant_ssrc; + int force_constant_ssrc; /* -1: always, 0: don't, 1: once */ int force_constant_timing; /* diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index abb48f5fa..79c9e1aba 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -280,6 +280,8 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta timestamp; state->patch = 1; ssrc = state->orig_ssrc; + if (rtp_end->force_constant_ssrc != -1) + rtp_end->force_constant_ssrc -= 1; LOGP(DMGCP, LOGL_NOTICE, "SSRC patching enabled on 0x%x SSRC: %u " diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index c703bec13..b8e1ecde4 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -619,8 +619,10 @@ void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change, { struct mgcp_trunk_config *tcfg = endp->tcfg; + int patch_ssrc = expect_ssrc_change && tcfg->force_constant_ssrc; + rtp->force_constant_timing = tcfg->force_constant_timing; - rtp->force_constant_ssrc = tcfg->force_constant_ssrc; + rtp->force_constant_ssrc = patch_ssrc ? 1 : 0; LOGP(DMGCP, LOGL_DEBUG, "Configuring RTP endpoint: local port %d%s%s\n", From 58340e5b5bfa37b09a61d544904330c1932ccfec Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Fri, 29 Nov 2013 11:20:06 +0100 Subject: [PATCH 09/10] mgcp/rtp: Fix RTP timestamps if enabled This forces the output timing to fulfill dTS = dSegNo * fixedPacketDuration where dSegNo = seqNo - lastSeqNo. If timestamp patching is enabled, the output timestamp will be set to lastTimestamp + dTS. This kind of relative updating is used to handle seqNo- and timestamp-wraparounds properly. The updating of timestamp and SSRC has been separated and the patch field of mgcp_rtp_state has been renamed to patch_ssrc to reflect it's semantics more closely. The offset fields are now used always and will change the corresponding header field if they are != 0. Ticket: OW#1065 Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp_internal.h | 2 +- openbsc/src/libmgcp/mgcp_network.c | 40 ++++++++++---- openbsc/tests/mgcp/mgcp_test.ok | 72 ++++++++++++------------- 3 files changed, 68 insertions(+), 46 deletions(-) diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 255161f45..b6f4a0df1 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -50,7 +50,7 @@ struct mgcp_rtp_stream_state { struct mgcp_rtp_state { int initialized; - int patch; + int patch_ssrc; uint32_t orig_ssrc; diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index 79c9e1aba..6463ae0bb 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -278,7 +278,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta state->timestamp_offset = (state->out_stream.last_timestamp + tsdelta) - timestamp; - state->patch = 1; + state->patch_ssrc = 1; ssrc = state->orig_ssrc; if (rtp_end->force_constant_ssrc != -1) rtp_end->force_constant_ssrc -= 1; @@ -300,7 +300,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta seq, timestamp, "input", &state->in_stream.last_tsdelta); - if (state->patch) + if (state->patch_ssrc) ssrc = state->orig_ssrc; } @@ -308,15 +308,37 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta state->in_stream.last_timestamp = timestamp; state->in_stream.last_seq = seq; - /* apply the offset and store it back to the packet */ - if (state->patch) { - seq += state->seq_offset; - rtp_hdr->sequence = htons(seq); + if (rtp_end->force_constant_timing && + state->out_stream.ssrc == ssrc && state->packet_duration) { + int delta_seq = seq + state->seq_offset - state->out_stream.last_seq; + int timestamp_offset = + state->out_stream.last_timestamp - timestamp + + delta_seq * state->packet_duration; + if (state->timestamp_offset != timestamp_offset) { + state->timestamp_offset = timestamp_offset; + + LOGP(DMGCP, LOGL_NOTICE, + "Timestamp patching enabled on 0x%x SSRC: %u " + "SeqNo delta: %d, TS offset: %d, " + "from %s:%d in %d\n", + ENDPOINT_NUMBER(endp), state->in_stream.ssrc, + delta_seq, state->timestamp_offset, + inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), + endp->conn_mode); + } + } + + /* Store the updated SSRC back to the packet */ + if (state->patch_ssrc) rtp_hdr->ssrc = htonl(ssrc); - timestamp += state->timestamp_offset; - rtp_hdr->timestamp = htonl(timestamp); - } + /* Apply the offset and store it back to the packet. + * This won't change anything if the offset is 0, so the conditional is + * omitted. */ + seq += state->seq_offset; + rtp_hdr->sequence = htons(seq); + timestamp += state->timestamp_offset; + rtp_hdr->timestamp = htonl(timestamp); /* Check again, whether the timestamps are still valid */ if (state->out_stream.ssrc == ssrc) diff --git a/openbsc/tests/mgcp/mgcp_test.ok b/openbsc/tests/mgcp/mgcp_test.ok index 4d3caacb5..3beeb5970 100644 --- a/openbsc/tests/mgcp/mgcp_test.ok +++ b/openbsc/tests/mgcp/mgcp_test.ok @@ -94,46 +94,46 @@ Output SSRC changed to 11223344 TS: 0, dTS: 0, TS Errs: in 0, out 0 TS: 160, dTS: 160, TS Errs: in 0, out 0 TS: 320, dTS: 160, TS Errs: in 0, out 0 -TS: 320, dTS: 160, TS Errs: in 1, out 1 -TS: 480, dTS: 160, TS Errs: in 1, out 1 -TS: 640, dTS: 160, TS Errs: in 1, out 1 -TS: 960, dTS: 320, TS Errs: in 2, out 2 -TS: 1120, dTS: 160, TS Errs: in 3, out 3 -TS: 1280, dTS: 160, TS Errs: in 3, out 3 -TS: 1400, dTS: 120, TS Errs: in 4, out 4 -TS: 1560, dTS: 160, TS Errs: in 5, out 5 -TS: 1720, dTS: 160, TS Errs: in 5, out 5 +TS: 480, dTS: 160, TS Errs: in 1, out 0 +TS: 640, dTS: 160, TS Errs: in 1, out 0 +TS: 800, dTS: 160, TS Errs: in 1, out 0 +TS: 960, dTS: 160, TS Errs: in 2, out 0 +TS: 1120, dTS: 160, TS Errs: in 3, out 0 +TS: 1280, dTS: 160, TS Errs: in 3, out 0 +TS: 1440, dTS: 160, TS Errs: in 4, out 0 +TS: 1600, dTS: 160, TS Errs: in 5, out 0 +TS: 1760, dTS: 160, TS Errs: in 5, out 0 Output SSRC changed to 10203040 -TS: 34688, dTS: 160, TS Errs: in 5, out 5 -TS: 34848, dTS: 160, TS Errs: in 5, out 5 -TS: 35008, dTS: 160, TS Errs: in 5, out 5 -TS: 35128, dTS: 120, TS Errs: in 6, out 6 -TS: 35288, dTS: 160, TS Errs: in 7, out 7 -TS: 35448, dTS: 160, TS Errs: in 7, out 7 -TS: 35768, dTS: 160, TS Errs: in 7, out 7 -TS: 35928, dTS: 160, TS Errs: in 7, out 7 -TS: 36088, dTS: 160, TS Errs: in 8, out 8 +TS: 34728, dTS: 160, TS Errs: in 5, out 0 +TS: 34888, dTS: 160, TS Errs: in 5, out 0 +TS: 35048, dTS: 160, TS Errs: in 5, out 0 +TS: 35208, dTS: 160, TS Errs: in 6, out 0 +TS: 35368, dTS: 160, TS Errs: in 7, out 0 +TS: 35528, dTS: 160, TS Errs: in 7, out 0 +TS: 35848, dTS: 160, TS Errs: in 7, out 0 +TS: 36008, dTS: 160, TS Errs: in 7, out 0 +TS: 36008, dTS: 160, TS Errs: in 8, out 0 Testing packet error detection, patch SSRC, patch timestamps. Output SSRC changed to 11223344 TS: 0, dTS: 0, TS Errs: in 0, out 0 TS: 160, dTS: 160, TS Errs: in 0, out 0 TS: 320, dTS: 160, TS Errs: in 0, out 0 -TS: 320, dTS: 160, TS Errs: in 1, out 1 -TS: 480, dTS: 160, TS Errs: in 1, out 1 -TS: 640, dTS: 160, TS Errs: in 1, out 1 -TS: 960, dTS: 320, TS Errs: in 2, out 2 -TS: 1120, dTS: 160, TS Errs: in 3, out 3 -TS: 1280, dTS: 160, TS Errs: in 3, out 3 -TS: 1400, dTS: 120, TS Errs: in 4, out 4 -TS: 1560, dTS: 160, TS Errs: in 5, out 5 -TS: 1720, dTS: 160, TS Errs: in 5, out 5 -TS: 1880, dTS: 160, TS Errs: in 5, out 5 -TS: 2040, dTS: 160, TS Errs: in 5, out 5 -TS: 2200, dTS: 160, TS Errs: in 5, out 5 -TS: 2320, dTS: 120, TS Errs: in 6, out 6 -TS: 2480, dTS: 160, TS Errs: in 7, out 7 -TS: 2640, dTS: 160, TS Errs: in 7, out 7 -TS: 2960, dTS: 160, TS Errs: in 7, out 7 -TS: 3120, dTS: 160, TS Errs: in 7, out 7 -TS: 3280, dTS: 160, TS Errs: in 8, out 8 +TS: 480, dTS: 160, TS Errs: in 1, out 0 +TS: 640, dTS: 160, TS Errs: in 1, out 0 +TS: 800, dTS: 160, TS Errs: in 1, out 0 +TS: 960, dTS: 160, TS Errs: in 2, out 0 +TS: 1120, dTS: 160, TS Errs: in 3, out 0 +TS: 1280, dTS: 160, TS Errs: in 3, out 0 +TS: 1440, dTS: 160, TS Errs: in 4, out 0 +TS: 1600, dTS: 160, TS Errs: in 5, out 0 +TS: 1760, dTS: 160, TS Errs: in 5, out 0 +TS: 1920, dTS: 160, TS Errs: in 5, out 0 +TS: 2080, dTS: 160, TS Errs: in 5, out 0 +TS: 2240, dTS: 160, TS Errs: in 5, out 0 +TS: 2400, dTS: 160, TS Errs: in 6, out 0 +TS: 2560, dTS: 160, TS Errs: in 7, out 0 +TS: 2720, dTS: 160, TS Errs: in 7, out 0 +TS: 3040, dTS: 160, TS Errs: in 7, out 0 +TS: 3200, dTS: 160, TS Errs: in 7, out 0 +TS: 3200, dTS: 160, TS Errs: in 8, out 0 Done From f6ec0e9fc4261d2173286e9b23fd19060040d1d1 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Wed, 4 Dec 2013 10:30:11 +0100 Subject: [PATCH 10/10] mgcp/rtp: Refactored packet_duration computation Since the packet duration is given in ms with the 'ptime' RTP media attribute and also with the 'p' MGCP local connection option, the computation is changed to use this value (if present). The computation assumes, that there are N complete frames in a packet and takes into account, that the ptime value possibly had been rounded towards the next ms value (which is never the case with a frame length of exact 20ms). Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp_internal.h | 3 +++ openbsc/src/libmgcp/mgcp_network.c | 5 +---- openbsc/src/libmgcp/mgcp_protocol.c | 24 +++++++++++++++++++++--- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index b6f4a0df1..d59c5d7cb 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -82,6 +82,7 @@ struct mgcp_rtp_end { uint32_t frame_duration_num; uint32_t frame_duration_den; int frames_per_packet; + uint32_t packet_duration_ms; char *fmtp_extra; /* RTP patching */ @@ -180,6 +181,8 @@ struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index); void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change, struct mgcp_rtp_end *rtp); +uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *rtp); void mgcp_state_calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *, uint32_t *expected, int *loss); diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index 6463ae0bb..bf205d1c7 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -237,10 +237,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta state->initialized = 1; state->jitter = 0; state->transit = arrival_time - timestamp; - state->packet_duration = - rtp_end->rate * rtp_end->frames_per_packet * - rtp_end->frame_duration_num / - rtp_end->frame_duration_den; + state->packet_duration = mgcp_rtp_packet_duration(endp, rtp_end); state->out_stream = state->in_stream; state->out_stream.last_timestamp = timestamp; state->out_stream.ssrc = ssrc - 1; /* force output SSRC change */ diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index b8e1ecde4..ab941645e 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_FRAMES_PER_PACKET 1 +#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20 #define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000 static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end); @@ -631,6 +631,23 @@ void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change, rtp->force_constant_ssrc ? ", force constant ssrc" : ""); } +uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *rtp) +{ + int f = 0; + + /* Get the number of frames per channel and packet */ + if (rtp->frames_per_packet) + f = rtp->frames_per_packet; + else if (rtp->packet_duration_ms && rtp->frame_duration_num) { + int den = 1000 * rtp->frame_duration_num; + f = (rtp->packet_duration_ms * rtp->frame_duration_den + den/2) + / den; + } + + return rtp->rate * f * rtp->frame_duration_num / rtp->frame_duration_den; +} + static struct msgb *handle_create_con(struct mgcp_parse_data *p) { struct mgcp_trunk_config *tcfg; @@ -1086,8 +1103,9 @@ static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end) /* Set default values */ end->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM; end->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN; - end->frames_per_packet = DEFAULT_RTP_AUDIO_FRAMES_PER_PACKET; - end->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE; + end->frames_per_packet = 0; /* unknown */ + end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS; + end->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE; } static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)