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..d59c5d7cb 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; @@ -59,6 +59,7 @@ struct mgcp_rtp_state { int cycles; int32_t timestamp_offset; + uint32_t packet_duration; uint32_t jitter; int32_t transit; @@ -81,8 +82,13 @@ 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 */ + int force_constant_ssrc; /* -1: always, 0: don't, 1: once */ + int force_constant_timing; + /* * Each end has a socket... */ @@ -142,9 +148,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 +179,11 @@ 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); +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); 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 75d39c195..bf205d1c7 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,41 +227,68 @@ 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; state->jitter = 0; state->transit = arrival_time - timestamp; + state->packet_duration = mgcp_rtp_packet_duration(endp, rtp_end); state->out_stream = state->in_stream; - } else if (state->in_stream.ssrc != rtp_hdr->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->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 = endp->allow_patch; - LOGP(DMGCP, LOGL_NOTICE, - "The SSRC changed on 0x%x SSRC: %u offset: %d tsdelta: %d " - "from %s:%d in %d\n", + state->out_stream.last_timestamp = timestamp; + 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", ENDPOINT_NUMBER(endp), state->in_stream.ssrc, - state->seq_offset, tsdelta, + state->seq_offset, state->packet_duration, 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 " + "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); + + state->in_stream.ssrc = ssrc; + if (rtp_end->force_constant_ssrc) { + int32_t tsdelta = state->out_stream.last_tsdelta; + if (tsdelta == 0) { + tsdelta = state->packet_duration; + LOGP(DMGCP, LOGL_NOTICE, + "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; + state->timestamp_offset = + (state->out_stream.last_timestamp + tsdelta) - + timestamp; + state->patch_ssrc = 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 " + "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 { @@ -269,26 +296,52 @@ 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) + ssrc = state->orig_ssrc; } /* Save before patching */ 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); - rtp_hdr->ssrc = state->orig_ssrc; + 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; - timestamp += state->timestamp_offset; - rtp_hdr->timestamp = htonl(timestamp); + 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); + + /* 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 */ - check_rtp_timestamp(endp, &state->out_stream, rtp_end, addr, - seq, timestamp, "output", - &state->out_stream.last_tsdelta); + if (state->out_stream.ssrc == 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 @@ -322,7 +375,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/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index a0b905de0..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); @@ -614,6 +614,40 @@ 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; + + int patch_ssrc = expect_ssrc_change && tcfg->force_constant_ssrc; + + rtp->force_constant_timing = tcfg->force_constant_timing; + rtp->force_constant_ssrc = patch_ssrc ? 1 : 0; + + 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" : ""); +} + +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; @@ -688,6 +722,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 +861,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)); @@ -1064,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) @@ -1121,7 +1161,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 c58f52d9e..e5b8bbdd5 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)); @@ -535,6 +558,9 @@ static void test_packet_error_detection(void) 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 @@ -545,7 +571,6 @@ static void test_packet_error_detection(void) mgcp_free_endp(&endp); rtp->payload_type = 98; - endp.allow_patch = 1; for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) { struct rtp_packet_info *info = test_rtp_packets1 + i; @@ -554,9 +579,17 @@ static void test_packet_error_detection(void) 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); + if (state.out_stream.ssrc != last_ssrc) { + printf("Output SSRC changed to %08x\n", + 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 +608,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..3beeb5970 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: 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 +TS: 160, dTS: 160, TS Errs: in 0, out 0 +TS: 320, dTS: 160, TS Errs: in 0, out 0 +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: 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: 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