From 093cc765665cae83ce17b0eb452ff3f7b8bfdb14 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Thu, 27 Apr 2017 15:59:19 +0200 Subject: nat: Add jitter buffer on the uplink receiver Default usage values are defined in mgcp node, and can be per-BSC overriden on each bsc node. Change-Id: Ibf3932adc07442fb5e9c7a06404853f9d0a20959 --- openbsc/include/openbsc/bsc_nat.h | 10 ++++ openbsc/include/openbsc/mgcp.h | 6 +++ openbsc/include/openbsc/mgcp_internal.h | 14 ++++++ openbsc/src/libmgcp/mgcp_network.c | 42 +++++++++++++++-- openbsc/src/libmgcp/mgcp_protocol.c | 24 ++++++++++ openbsc/src/libmgcp/mgcp_vty.c | 74 ++++++++++++++++++++++++++++++ openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c | 10 ++++ openbsc/src/osmo-bsc_nat/bsc_nat_vty.c | 76 +++++++++++++++++++++++++++++++ 8 files changed, 253 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index fad380438..5171c3e0c 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -175,6 +175,16 @@ struct bsc_config { /* Osmux is enabled/disabled per BSC */ int osmux; + + /* Use a jitterbuffer on the bts-side receiver */ + bool bts_use_jibuf; + /* Minimum and maximum buffer size for the jitter buffer, in ms */ + uint32_t bts_jitter_delay_min; + uint32_t bts_jitter_delay_max; + /* Enabled if explicitly configured through VTY: */ + bool bts_use_jibuf_override; + bool bts_jitter_delay_min_override; + bool bts_jitter_delay_max_override; }; struct bsc_lac_entry { diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index b2262bc8d..4d1c5ef47 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -236,6 +236,12 @@ struct mgcp_config { * message. */ uint16_t osmux_dummy; + + /* Use a jitterbuffer on the bts-side receiver */ + bool bts_use_jibuf; + /* Minimum and maximum buffer size for the jitter buffer, in ms */ + uint32_t bts_jitter_delay_min; + uint32_t bts_jitter_delay_max; }; /* config management */ diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 7c89d1021..cd6365f98 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -25,6 +25,7 @@ #include #include +#include #define CI_UNUSED 0 @@ -205,6 +206,14 @@ struct mgcp_endpoint { uint32_t octets; } stats; } osmux; + + /* Jitter buffer */ + struct osmo_jibuf* bts_jb; + /* Use a jitterbuffer on the bts-side receiver */ + bool bts_use_jibuf; + /* Minimum and maximum buffer size for the jitter buffer, in ms */ + uint32_t bts_jitter_delay_min; + uint32_t bts_jitter_delay_max; }; #define for_each_line(line, save) \ @@ -340,3 +349,8 @@ static inline const char *mgcp_bts_src_addr(struct mgcp_endpoint *endp) return endp->cfg->bts_ports.bind_addr; return endp->cfg->source_addr; } + +/** + * Internal jitter buffer related + */ +void mgcp_dejitter_udp_send(struct msgb *msg, void *data); diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index abce6e49d..799d99838 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -580,6 +580,36 @@ static int mgcp_send_transcoder(struct mgcp_rtp_end *end, return rc; } +void mgcp_dejitter_udp_send(struct msgb *msg, void *data) +{ + struct mgcp_rtp_end *rtp_end = (struct mgcp_rtp_end *) data; + + int rc = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, + rtp_end->rtp_port, (char*) msg->data, msg->len); + if (rc != msg->len) + LOGP(DMGCP, LOGL_ERROR, + "Failed to send data after jitter buffer: %d\n", rc); + msgb_free(msg); +} + +static int enqueue_dejitter(struct osmo_jibuf *jb, struct mgcp_rtp_end *rtp_end, char *buf, int len) +{ + struct msgb *msg; + msg = msgb_alloc(len, "mgcp-jibuf"); + if (!msg) + return -1; + + memcpy(msg->data, buf, len); + msgb_put(msg, len); + + if (osmo_jibuf_enqueue(jb, msg) < 0) { + rtp_end->dropped_packets += 1; + msgb_free(msg); + } + + return len; +} + int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, struct sockaddr_in *addr, char *buf, int rc) { @@ -587,6 +617,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, struct mgcp_rtp_end *rtp_end; struct mgcp_rtp_state *rtp_state; int tap_idx; + struct osmo_jibuf *jb; /* For loop toggle the destination and then dispatch. */ if (tcfg->audio_loop) @@ -600,10 +631,12 @@ int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, rtp_end = &endp->net_end; rtp_state = &endp->bts_state; tap_idx = MGCP_TAP_NET_OUT; + jb = endp->bts_jb; } else { rtp_end = &endp->bts_end; rtp_state = &endp->net_state; tap_idx = MGCP_TAP_BTS_OUT; + jb = NULL; } if (!rtp_end->output_enabled) @@ -621,9 +654,12 @@ int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, buf, len); forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx], buf, len); - rc = mgcp_udp_send(rtp_end->rtp.fd, - &rtp_end->addr, - rtp_end->rtp_port, buf, len); + if (jb) + rc = enqueue_dejitter(jb, rtp_end, buf, len); + else + rc = mgcp_udp_send(rtp_end->rtp.fd, + &rtp_end->addr, + rtp_end->rtp_port, buf, len); if (rc <= 0) return rc; diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index ae5c90bcc..84dbc1f52 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -827,6 +827,12 @@ mgcp_header_done: goto error2; } + /* Apply Jiter buffer settings for this endpoint, they can be overriden by CRCX policy later */ + endp->bts_use_jibuf = endp->cfg->bts_use_jibuf; + endp->bts_jitter_delay_min = endp->cfg->bts_jitter_delay_min; + endp->bts_jitter_delay_max = endp->cfg->bts_jitter_delay_max; + + endp->allocated = 1; /* set up RTP media parameters */ @@ -862,6 +868,13 @@ mgcp_header_done: case MGCP_POLICY_DEFER: /* stop processing */ create_transcoder(endp); + /* Set up jitter buffer if required after policy has updated jibuf endp values */ + if (endp->bts_use_jibuf) { + endp->bts_jb = osmo_jibuf_alloc(tcfg->endpoints); + osmo_jibuf_set_min_delay(endp->bts_jb, endp->bts_jitter_delay_min); + osmo_jibuf_set_max_delay(endp->bts_jb, endp->bts_jitter_delay_max); + osmo_jibuf_set_dequeue_cb(endp->bts_jb, mgcp_dejitter_udp_send, &endp->net_end); + } return NULL; break; case MGCP_POLICY_CONT: @@ -870,6 +883,14 @@ mgcp_header_done: } } + /* Set up jitter buffer if required after policy has updated jibuf endp values */ + if (endp->bts_use_jibuf) { + endp->bts_jb = osmo_jibuf_alloc(tcfg->endpoints); + osmo_jibuf_set_min_delay(endp->bts_jb, endp->bts_jitter_delay_min); + osmo_jibuf_set_max_delay(endp->bts_jb, endp->bts_jitter_delay_max); + osmo_jibuf_set_dequeue_cb(endp->bts_jb, mgcp_dejitter_udp_send, &endp->net_end); + } + LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n", ENDPOINT_NUMBER(endp), endp->ci, endp->net_end.local_port, endp->bts_end.local_port); @@ -1333,6 +1354,9 @@ int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg) void mgcp_release_endp(struct mgcp_endpoint *endp) { LOGP(DMGCP, LOGL_DEBUG, "Releasing endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp)); + if (endp->bts_jb) + osmo_jibuf_delete(endp->bts_jb); + endp->bts_jb = NULL; endp->ci = CI_UNUSED; endp->allocated = 0; diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c index b97d7f835..6d1a7acc7 100644 --- a/openbsc/src/libmgcp/mgcp_vty.c +++ b/openbsc/src/libmgcp/mgcp_vty.c @@ -29,6 +29,7 @@ #include #include +#include #define RTCP_OMIT_STR "Drop RTCP packets in both directions\n" #define RTP_PATCH_STR "Modify RTP packet header in both directions\n" @@ -164,6 +165,13 @@ static int config_write_mgcp(struct vty *vty) vty_out(vty, " osmux dummy %s%s", g_cfg->osmux_dummy ? "on" : "off", VTY_NEWLINE); } + if (g_cfg->bts_use_jibuf) + vty_out(vty, " bts-jitter-buffer%s", VTY_NEWLINE); + if (g_cfg->bts_jitter_delay_min) + vty_out(vty, " bts-jitter-delay-min %"PRIu32"%s", g_cfg->bts_jitter_delay_min, VTY_NEWLINE); + if (g_cfg->bts_jitter_delay_max) + vty_out(vty, " bts-jitter-delay-max %"PRIu32"%s", g_cfg->bts_jitter_delay_max, VTY_NEWLINE); + return CMD_SUCCESS; } @@ -241,6 +249,11 @@ DEFUN(show_mcgp, show_mgcp_cmd, if (g_cfg->osmux) vty_out(vty, "Osmux used CID: %d%s", osmux_used_cid(), VTY_NEWLINE); + vty_out(vty, "Jitter Buffer by default on Uplink : %s%s", + g_cfg->bts_use_jibuf ? "on" : "off", VTY_NEWLINE); + if (g_cfg->bts_use_jibuf) + vty_out(vty, "Jitter Buffer delays: min=%"PRIu32" max=%"PRIu32"%s", + g_cfg->bts_jitter_delay_min, g_cfg->bts_jitter_delay_max, VTY_NEWLINE); return CMD_SUCCESS; } @@ -1333,6 +1346,63 @@ DEFUN(cfg_mgcp_osmux_dummy, return CMD_SUCCESS; } +#define DEJITTER_STR "Uplink Jitter Buffer" +DEFUN(cfg_mgcp_bts_use_jibuf, + cfg_mgcp_bts_use_jibuf_cmd, + "bts-jitter-buffer", + DEJITTER_STR "\n") +{ + g_cfg->bts_use_jibuf = true; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_no_bts_use_jibuf, + cfg_mgcp_no_bts_use_jibuf_cmd, + "no bts-jitter-buffer", + NO_STR DEJITTER_STR "\n") +{ + g_cfg->bts_use_jibuf = false; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bts_jitter_delay_min, + cfg_mgcp_bts_jitter_delay_min_cmd, + "bts-jitter-buffer-delay-min <1-65535>", + DEJITTER_STR " Minimum Delay in ms\n" "Minimum Delay in ms\n") +{ + g_cfg->bts_jitter_delay_min = atoi(argv[0]); + if (!g_cfg->bts_jitter_delay_min) { + vty_out(vty, "bts-jitter-buffer-delay-min cannot be zero.%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (g_cfg->bts_jitter_delay_min && g_cfg->bts_jitter_delay_max && + g_cfg->bts_jitter_delay_min > g_cfg->bts_jitter_delay_max) { + vty_out(vty, "bts-jitter-buffer-delay-min cannot be bigger than " \ + "bts-jitter-buffer-delay-max.%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bts_jitter_delay_max, + cfg_mgcp_bts_jitter_delay_max_cmd, + "bts-jitter-buffer-delay-max <1-65535>", + DEJITTER_STR " Maximum Delay in ms\n" "Maximum Delay in ms\n") +{ + g_cfg->bts_jitter_delay_max = atoi(argv[0]); + if (!g_cfg->bts_jitter_delay_max) { + vty_out(vty, "bts-jitter-buffer-delay-max cannot be zero.%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (g_cfg->bts_jitter_delay_min && g_cfg->bts_jitter_delay_max && + g_cfg->bts_jitter_delay_min > g_cfg->bts_jitter_delay_max) { + vty_out(vty, "bts-jitter-buffer-delay-max cannot be smaller than " \ + "bts-jitter-buffer-delay-min.%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + int mgcp_vty_init(void) { install_element_ve(&show_mgcp_cmd); @@ -1399,6 +1469,10 @@ int mgcp_vty_init(void) install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd); install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd); install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bts_use_jibuf_cmd); + install_element(MGCP_NODE, &cfg_mgcp_no_bts_use_jibuf_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bts_jitter_delay_min_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bts_jitter_delay_max_cmd); install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd); diff --git a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c index 48847865c..8cf4e9427 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c @@ -585,6 +585,16 @@ static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int if (state == MGCP_ENDP_CRCX) { struct sockaddr_in sock; + /* set up jitter buffer parameters */ + if (bsc_endp->bsc->cfg->bts_use_jibuf_override) + mgcp_endp->bts_use_jibuf = bsc_endp->bsc->cfg->bts_use_jibuf; + + if (bsc_endp->bsc->cfg->bts_jitter_delay_min_override) + mgcp_endp->bts_jitter_delay_min = bsc_endp->bsc->cfg->bts_jitter_delay_min; + + if (bsc_endp->bsc->cfg->bts_jitter_delay_max_override) + mgcp_endp->bts_jitter_delay_max = bsc_endp->bsc->cfg->bts_jitter_delay_max; + /* Annotate the allocated Osmux CID until the bsc confirms that * it agrees to use Osmux for this voice flow. */ diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c index d4cef5dbe..e51de537a 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c @@ -40,6 +40,7 @@ #include #include +#include static struct bsc_nat *_nat; @@ -173,6 +174,12 @@ static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc) vty_out(vty, " osmux only%s", VTY_NEWLINE); break; } + if (bsc->bts_use_jibuf_override) + vty_out(vty, " %sbts-jitter-buffer%s", bsc->bts_use_jibuf? "" : "no ", VTY_NEWLINE); + if (bsc->bts_jitter_delay_min_override) + vty_out(vty, " bts-jitter-delay-min %"PRIu32"%s", bsc->bts_jitter_delay_min, VTY_NEWLINE); + if (bsc->bts_jitter_delay_max_override) + vty_out(vty, " bts-jitter-delay-max %"PRIu32"%s", bsc->bts_jitter_delay_max, VTY_NEWLINE); } static int config_write_bsc(struct vty *vty) @@ -1231,6 +1238,71 @@ DEFUN(cfg_bsc_osmux, return CMD_SUCCESS; } +#define DEJITTER_STR "Uplink Jitter Buffer" +DEFUN(cfg_bsc_bts_use_jibuf, + cfg_bsc_bts_use_jibuf_cmd, + "bts-jitter-buffer", + DEJITTER_STR "\n") +{ + struct bsc_config *conf = vty->index; + conf->bts_use_jibuf = true; + conf->bts_use_jibuf_override = true; + return CMD_SUCCESS; +} + +DEFUN(cfg_bsc_no_bts_use_jibuf, + cfg_bsc_no_bts_use_jibuf_cmd, + "no bts-jitter-buffer", + NO_STR DEJITTER_STR "\n") +{ + struct bsc_config *conf = vty->index; + conf->bts_use_jibuf = false; + conf->bts_use_jibuf_override = true; + return CMD_SUCCESS; +} + +DEFUN(cfg_bsc_bts_jitter_delay_min, + cfg_bsc_bts_jitter_delay_min_cmd, + "bts-jitter-buffer-delay-min <1-65535>", + DEJITTER_STR " Minimum Delay in ms\n" "Minimum Delay in ms\n") +{ + struct bsc_config *conf = vty->index; + conf->bts_jitter_delay_min = atoi(argv[0]); + if (!conf->bts_jitter_delay_min) { + vty_out(vty, "bts-jitter-buffer-delay-min cannot be zero.%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (conf->bts_jitter_delay_min && conf->bts_jitter_delay_max && + conf->bts_jitter_delay_min > conf->bts_jitter_delay_max) { + vty_out(vty, "bts-jitter-buffer-delay-min cannot be bigger than " \ + "bts-jitter-buffer-delay-max.%s", VTY_NEWLINE); + return CMD_WARNING; + } + conf->bts_jitter_delay_min_override = true; + return CMD_SUCCESS; +} + +DEFUN(cfg_bsc_bts_jitter_delay_max, + cfg_bsc_bts_jitter_delay_max_cmd, + "bts-jitter-buffer-delay-max <1-65535>", + DEJITTER_STR " Maximum Delay in ms\n" "Maximum Delay in ms\n") +{ + struct bsc_config *conf = vty->index; + conf->bts_jitter_delay_max = atoi(argv[0]); + if (!conf->bts_jitter_delay_max) { + vty_out(vty, "bts-jitter-buffer-delay-max cannot be zero.%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (conf->bts_jitter_delay_min && conf->bts_jitter_delay_max && + conf->bts_jitter_delay_min > conf->bts_jitter_delay_max) { + vty_out(vty, "bts-jitter-buffer-delay-max cannot be smaller than " \ + "bts-jitter-buffer-delay-min.%s", VTY_NEWLINE); + return CMD_WARNING; + } + conf->bts_jitter_delay_max_override = true; + return CMD_SUCCESS; +} + int bsc_nat_vty_init(struct bsc_nat *nat) { _nat = nat; @@ -1318,6 +1390,10 @@ int bsc_nat_vty_init(struct bsc_nat *nat) install_element(NAT_BSC_NODE, &cfg_bsc_paging_grp_cmd); install_element(NAT_BSC_NODE, &cfg_bsc_no_paging_grp_cmd); install_element(NAT_BSC_NODE, &cfg_bsc_osmux_cmd); + install_element(NAT_BSC_NODE, &cfg_bsc_bts_use_jibuf_cmd); + install_element(NAT_BSC_NODE, &cfg_bsc_no_bts_use_jibuf_cmd); + install_element(NAT_BSC_NODE, &cfg_bsc_bts_jitter_delay_min_cmd); + install_element(NAT_BSC_NODE, &cfg_bsc_bts_jitter_delay_max_cmd); mgcp_vty_init(); -- cgit v1.2.3