aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax <msuraev@sysmocom.de>2016-06-13 12:06:06 +0200
committerHarald Welte <laforge@gnumonks.org>2016-06-14 10:18:59 +0000
commit8ecadc66cef3ceb17f9f815ba5bd4e31406a664a (patch)
treecf8239e5605740cf9fc4cedfccff401419514b5f
parent9302abe0547e6f6172416b1d07182916b628e480 (diff)
DTXd: store/repeat last SID
Store last SID received over RTP and repeat is if necessary (no new SID or SPEECH frames) according to codec-specific scheduling rules. Change-Id: I4d23846a27d3dbd2a6e75e481c1efcdb2a85f305 Related: OS#1563
-rw-r--r--src/osmo-bts-sysmo/l1_if.c2
-rw-r--r--src/osmo-bts-sysmo/l1_if.h2
-rw-r--r--src/osmo-bts-sysmo/tch.c133
3 files changed, 119 insertions, 18 deletions
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c
index d6d0cdd1..84fad994 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -414,7 +414,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
/* no message/data, we generate an empty traffic msg */
if (!nmsg)
- nmsg = gen_empty_tch_msg(lchan);
+ nmsg = gen_empty_tch_msg(lchan, u32Fn);
/* no traffic message, we generate an empty msg */
if (!nmsg) {
diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h
index bb1d5a52..2fc8a296 100644
--- a/src/osmo-bts-sysmo/l1_if.h
+++ b/src/osmo-bts-sysmo/l1_if.h
@@ -111,7 +111,7 @@ void l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
const uint8_t *rtp_pl, unsigned int rtp_pl_len);
int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg);
int l1if_tch_fill(struct gsm_lchan *lchan, uint8_t *l1_buffer);
-struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan);
+struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn);
/* ciphering */
int l1if_set_ciphering(struct femtol1_hdl *fl1h,
diff --git a/src/osmo-bts-sysmo/tch.c b/src/osmo-bts-sysmo/tch.c
index 63d90af1..07a0efb2 100644
--- a/src/osmo-bts-sysmo/tch.c
+++ b/src/osmo-bts-sysmo/tch.c
@@ -23,7 +23,7 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
-
+#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -577,7 +577,66 @@ err_payload_match:
return -EINVAL;
}
-struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan)
+static inline bool fn_chk(uint8_t *t, uint32_t fn)
+{
+ uint8_t i;
+ for (i = 0; i < ARRAY_SIZE(t); i++)
+ if (fn % 104 == t[i])
+ return false;
+ return true;
+}
+
+static bool dtx_sched_optional(struct gsm_lchan *lchan, uint32_t fn)
+{
+ /* 3GPP TS 45.008 ยง 8.3 */
+ uint8_t f[] = { 52, 53, 54, 55, 56, 57, 58, 59 },
+ h0[] = { 0, 2, 4, 6, 52, 54, 56, 58 },
+ h1[] = { 14, 16, 18, 20, 66, 68, 70, 72 };
+ if (lchan->tch_mode == GSM48_CMODE_SPEECH_V1) {
+ if (lchan->type == GSM_LCHAN_TCH_F)
+ return fn_chk(f, fn);
+ else
+ return fn_chk(lchan->nr ? h1 : h0, fn);
+ }
+ return false;
+}
+
+static bool repeat_last_sid(struct gsm_lchan *lchan, struct msgb *msg)
+{
+ GsmL1_Prim_t *l1p;
+ GsmL1_PhDataReq_t *data_req;
+ GsmL1_MsgUnitParam_t *msu_param;
+ uint8_t *l1_payload;
+
+ l1p = msgb_l1prim(msg);
+ data_req = &l1p->u.phDataReq;
+ msu_param = &data_req->msgUnitParam;
+ l1_payload = &msu_param->u8Buffer[1];
+
+ if (lchan->tch.last_sid.len) {
+ memcpy(l1_payload, lchan->tch.last_sid.buf,
+ lchan->tch.last_sid.len);
+ msu_param->u8Size = lchan->tch.last_sid.len + 1;
+ return true;
+ }
+ return false;
+}
+
+/* store the last SID frame in lchan context */
+void save_last_sid(struct gsm_lchan *lchan, uint8_t *l1_payload, size_t length,
+ uint32_t fn, bool update)
+{
+ size_t copy_len = OSMO_MIN(length + 1,
+ ARRAY_SIZE(lchan->tch.last_sid.buf));
+
+ lchan->tch.last_sid.len = copy_len;
+ lchan->tch.last_sid.fn = fn;
+ lchan->tch.last_sid.is_update = update;
+
+ memcpy(lchan->tch.last_sid.buf, l1_payload, copy_len);
+}
+
+struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn)
{
struct msgb *msg;
GsmL1_Prim_t *l1p;
@@ -599,21 +658,63 @@ struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan)
switch (lchan->tch_mode) {
case GSM48_CMODE_SPEECH_AMR:
*payload_type = GsmL1_TchPlType_Amr;
- if (lchan->tch.last_sid.len) {
- memcpy(l1_payload, lchan->tch.last_sid.buf,
- lchan->tch.last_sid.len);
- msu_param->u8Size = lchan->tch.last_sid.len+1;
+ /* according to 3GPP TS 26.093 A.5.1.1: */
+ if (lchan->tch.last_sid.is_update) {
+ /* SID UPDATE should be repeated every 8th frame */
+ if (fn - lchan->tch.last_sid.fn < 7) {
+ msgb_free(msg);
+ return NULL;
+ }
} else {
- /* FIXME: decide if we should send SPEECH_BAD or
- * SID_BAD */
-#if 0
- *payload_type = GsmL1_TchPlType_Amr_SidBad;
- memset(l1_payload, 0xFF, 5);
- msu_param->u8Size = 5 + 3;
-#else
- /* send an all-zero SID */
- msu_param->u8Size = 8;
-#endif
+ /* 3rd frame after SID FIRST should be SID UPDATE */
+ if (fn - lchan->tch.last_sid.fn < 3) {
+ msgb_free(msg);
+ return NULL;
+ }
+ }
+ if (repeat_last_sid(lchan, msg))
+ return msg;
+ else {
+ LOGP(DL1C, LOGL_NOTICE, "Have to send AMR frame on TCH "
+ "(FN=%u) but SID buffer is empty - sent NO_DATA\n",
+ fn);
+ osmo_amr_rtp_enc(l1_payload, 0, AMR_NO_DATA,
+ AMR_GOOD);
+ return msg;
+ }
+ break;
+ case GSM48_CMODE_SPEECH_V1:
+ if (lchan->type == GSM_LCHAN_TCH_F)
+ *payload_type = GsmL1_TchPlType_Fr;
+ else
+ *payload_type = GsmL1_TchPlType_Hr;
+ /* unlike AMR, FR & HR schedued based on absolute FN value */
+ if (dtx_sched_optional(lchan, fn)) {
+ msgb_free(msg);
+ return NULL;
+ }
+ if (repeat_last_sid(lchan, msg))
+ return msg;
+ else {
+ LOGP(DL1C, LOGL_NOTICE, "Have to send V1 frame on TCH "
+ "(FN=%u) but SID buffer is empty - sent nothing\n",
+ fn);
+ return NULL;
+ }
+ break;
+ case GSM48_CMODE_SPEECH_EFR:
+ *payload_type = GsmL1_TchPlType_Efr;
+ if (dtx_sched_optional(lchan, fn)) {
+ msgb_free(msg);
+ return NULL;
+ }
+ if (repeat_last_sid(lchan, msg))
+ return msg;
+ else {
+ LOGP(DL1C, LOGL_NOTICE, "Have to send EFR frame on TCH "
+ "(FN=%u) but SID buffer is empty - sent nothing\n",
+ fn);
+ return NULL;
}
break;
default: