laforge submitted this change.

View Change


Approvals: laforge: Looks good to me, approved pespin: Looks good to me, but someone else must approve Jenkins Builder: Verified
common: implement rtp continuous-streaming mode

In some environments it is highly desirable for the RTP stream
coming from each GSM call UL on a BTS to be fully continuous,
without any gaps, with _some_ RTP packet emitted every 20 ms,
even if there is no speech or SID frame to be sent in that frame
time window. The present change adds an rtp continuous-streaming
vty option which, when enabled, causes the BTS to emit RTP packets
with a zero-length payload, instead of producing gaps in the RTP
stream, when it has nothing else to send.

Related: OS#5975
Change-Id: Ic0e2edf2ed90ba0ac6bee5e7d9629bf0255e256d
---
M include/osmo-bts/bts.h
M src/common/l1sap.c
M src/common/vty.c
M tests/osmo-bts.vty
4 files changed, 90 insertions(+), 16 deletions(-)

diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h
index ed3da1d..14c78a3 100644
--- a/include/osmo-bts/bts.h
+++ b/include/osmo-bts/bts.h
@@ -314,6 +314,8 @@
int rtp_ip_dscp;
int rtp_priority;

+ bool rtp_nogaps_mode; /* emit RTP stream without any gaps */
+
struct {
uint8_t ciphers; /* flags A5/1==0x1, A5/2==0x2, A5/3==0x4 */
} support;
diff --git a/src/common/l1sap.c b/src/common/l1sap.c
index efde406..89aea58 100644
--- a/src/common/l1sap.c
+++ b/src/common/l1sap.c
@@ -1247,6 +1247,18 @@

static bool rtppayload_is_valid(struct gsm_lchan *lchan, struct msgb *resp_msg)
{
+ /* If rtp continuous-streaming is enabled, we shall emit RTP packets
+ * with zero-length payloads as BFI markers. In a TrFO scenario such
+ * RTP packets sent by call leg A will be received by call leg B,
+ * hence we need to handle them gracefully. For the purposes of a BTS
+ * that runs on its own TDMA timing and does not need timing ticks from
+ * an incoming RTP stream, the correct action upon receiving such
+ * timing-tick-only RTP packets should be the same as when receiving
+ * no RTP packet at all. The simplest way to produce that behavior
+ * is to treat zero-length RTP payloads as invalid. */
+ if (resp_msg->len == 0)
+ return false;
+
/* Avoid sending bw-efficient AMR to lower layers, most bts models
* don't support it. */
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR &&
@@ -1567,6 +1579,21 @@
return 1;
}

+/* a helper function for the logic in l1sap_tch_ind() */
+static void send_ul_rtp_packet(struct gsm_lchan *lchan, uint32_t fn,
+ const uint8_t *rtp_pl, uint16_t rtp_pl_len)
+{
+ if (lchan->abis_ip.osmux.use) {
+ lchan_osmux_send_frame(lchan, rtp_pl, rtp_pl_len,
+ fn_ms_adj(fn, lchan), lchan->rtp_tx_marker);
+ } else if (lchan->abis_ip.rtp_socket) {
+ osmo_rtp_send_frame_ext(lchan->abis_ip.rtp_socket,
+ rtp_pl, rtp_pl_len, fn_ms_adj(fn, lchan), lchan->rtp_tx_marker);
+ }
+ /* Only clear the marker bit once we have sent a RTP packet with it */
+ lchan->rtp_tx_marker = false;
+}
+
/* TCH received from bts model */
static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap,
struct ph_tch_param *tch_ind)
@@ -1605,13 +1632,7 @@
* good enough. */
if (msg->len && tch_ind->lqual_cb >= bts->min_qual_norm) {
/* hand msg to RTP code for transmission */
- if (lchan->abis_ip.osmux.use) {
- lchan_osmux_send_frame(lchan, msg->data, msg->len,
- fn_ms_adj(fn, lchan), lchan->rtp_tx_marker);
- } else if (lchan->abis_ip.rtp_socket) {
- osmo_rtp_send_frame_ext(lchan->abis_ip.rtp_socket,
- msg->data, msg->len, fn_ms_adj(fn, lchan), lchan->rtp_tx_marker);
- }
+ send_ul_rtp_packet(lchan, fn, msg->data, msg->len);
/* if loopback is enabled, also queue received RTP data */
if (lchan->loopback) {
/* add new frame to queue, make sure the queue doesn't get too long */
@@ -1619,16 +1640,20 @@
/* Return 1 to signal that we're still using msg and it should not be freed */
return 1;
}
- /* Only clear the marker bit once we have sent a RTP packet with it */
- lchan->rtp_tx_marker = false;
} else {
- DEBUGPGT(DRTP, &g_time, "Skipping RTP frame with lost payload (chan_nr=0x%02x)\n",
- chan_nr);
- if (lchan->abis_ip.osmux.use)
- lchan_osmux_skipped_frame(lchan, fn_ms_adj(fn, lchan));
- else if (lchan->abis_ip.rtp_socket)
- osmo_rtp_skipped_frame(lchan->abis_ip.rtp_socket, fn_ms_adj(fn, lchan));
- lchan->rtp_tx_marker = true;
+ /* Are we in rtp continuous-stream special mode? If so, send
+ * out a BFI packet as zero-length RTP payload. */
+ if (bts->rtp_nogaps_mode) {
+ send_ul_rtp_packet(lchan, fn, msg->data, msg->len);
+ } else {
+ DEBUGPGT(DRTP, &g_time, "Skipping RTP frame with lost payload (chan_nr=0x%02x)\n",
+ chan_nr);
+ if (lchan->abis_ip.osmux.use)
+ lchan_osmux_skipped_frame(lchan, fn_ms_adj(fn, lchan));
+ else if (lchan->abis_ip.rtp_socket)
+ osmo_rtp_skipped_frame(lchan->abis_ip.rtp_socket, fn_ms_adj(fn, lchan));
+ lchan->rtp_tx_marker = true;
+ }
}

lchan->tch.last_fn = fn;
diff --git a/src/common/vty.c b/src/common/vty.c
index 93fc0d6..1ef79f0 100644
--- a/src/common/vty.c
+++ b/src/common/vty.c
@@ -422,6 +422,8 @@
vty_out(vty, " rtp ip-dscp %d%s", bts->rtp_ip_dscp, VTY_NEWLINE);
if (bts->rtp_priority != -1)
vty_out(vty, " rtp socket-priority %d%s", bts->rtp_priority, VTY_NEWLINE);
+ if (bts->rtp_nogaps_mode)
+ vty_out(vty, " rtp continuous-streaming%s", VTY_NEWLINE);
vty_out(vty, " paging queue-size %u%s", paging_get_queue_max(bts->paging_state),
VTY_NEWLINE);
vty_out(vty, " paging lifetime %u%s", paging_get_lifetime(bts->paging_state),
@@ -781,6 +783,28 @@
return CMD_SUCCESS;
}

+DEFUN(cfg_bts_rtp_cont_stream,
+ cfg_bts_rtp_cont_stream_cmd,
+ "rtp continuous-streaming",
+ RTP_STR "Always emit an RTP packet every 20 ms\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->rtp_nogaps_mode = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_no_rtp_cont_stream,
+ cfg_bts_no_rtp_cont_stream_cmd,
+ "no rtp continuous-streaming",
+ NO_STR RTP_STR "Always emit an RTP packet every 20 ms\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->rtp_nogaps_mode = false;
+ return CMD_SUCCESS;
+}
+
#define PAG_STR "Paging related parameters\n"

DEFUN_ATTR(cfg_bts_paging_queue_size,
@@ -2681,6 +2705,8 @@
install_element(BTS_NODE, &cfg_bts_rtp_port_range_cmd);
install_element(BTS_NODE, &cfg_bts_rtp_ip_dscp_cmd);
install_element(BTS_NODE, &cfg_bts_rtp_priority_cmd);
+ install_element(BTS_NODE, &cfg_bts_rtp_cont_stream_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_rtp_cont_stream_cmd);
install_element(BTS_NODE, &cfg_bts_band_cmd);
install_element(BTS_NODE, &cfg_description_cmd);
install_element(BTS_NODE, &cfg_no_description_cmd);
diff --git a/tests/osmo-bts.vty b/tests/osmo-bts.vty
index 3e526e7..7f2e78c 100644
--- a/tests/osmo-bts.vty
+++ b/tests/osmo-bts.vty
@@ -233,6 +233,8 @@
rtp port-range <1-65534> <1-65534>
rtp ip-dscp <0-63>
rtp socket-priority <0-255>
+ rtp continuous-streaming
+ no rtp continuous-streaming
band (450|GSM450|480|GSM480|750|GSM750|810|GSM810|850|GSM850|900|GSM900|1800|DCS1800|1900|PCS1900)
description .TEXT
no description

To view, visit change 32098. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: osmo-bts
Gerrit-Branch: master
Gerrit-Change-Id: Ic0e2edf2ed90ba0ac6bee5e7d9629bf0255e256d
Gerrit-Change-Number: 32098
Gerrit-PatchSet: 4
Gerrit-Owner: falconia <falcon@freecalypso.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge@osmocom.org>
Gerrit-Reviewer: pespin <pespin@sysmocom.de>
Gerrit-MessageType: merged