diff options
author | Max <msuraev@sysmocom.de> | 2016-06-13 12:06:06 +0200 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2016-06-14 10:18:59 +0000 |
commit | 8ecadc66cef3ceb17f9f815ba5bd4e31406a664a (patch) | |
tree | cf8239e5605740cf9fc4cedfccff401419514b5f | |
parent | 9302abe0547e6f6172416b1d07182916b628e480 (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.c | 2 | ||||
-rw-r--r-- | src/osmo-bts-sysmo/l1_if.h | 2 | ||||
-rw-r--r-- | src/osmo-bts-sysmo/tch.c | 133 |
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: |