aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bts-litecell15/tch.c
diff options
context:
space:
mode:
authorMax <msuraev@sysmocom.de>2016-10-03 17:37:45 +0200
committerHarald Welte <laforge@gnumonks.org>2016-10-13 06:58:06 +0000
commitbabd05661d13b12234e848acf9c4bff909ef05f4 (patch)
tree656168076a94b5a430d2b0c1d856011e3b4c6a4d /src/osmo-bts-litecell15/tch.c
parentc09e5a44c3c1c2882339fe8822f373b1e12839ae (diff)
DTX DL: use FSM for AMR
Use dedicated FSM to handle all DTX DL related events: - add explicit checks if DTX DL is enabled (fixes regression for non-DTX setup introduced in 654175f33bd412671e3ef8cdd65c0689d10f278c) - fix handling of AMR CMI for SPEECH frames - add FSM for DTX DL - sync with corresponding changes in OpenBSC's - handle FACCH-related DTX ONSET events This affects both lc15 and sysmobts and requires corresponding change in OpenBSC (Change-Id: Idac8609faf9b5ced818fde899ccfc6ed0c42e8fd). Change-Id: I74a0b42cb34d525b8a70d264135e82994ca70d31
Diffstat (limited to 'src/osmo-bts-litecell15/tch.c')
-rw-r--r--src/osmo-bts-litecell15/tch.c122
1 files changed, 94 insertions, 28 deletions
diff --git a/src/osmo-bts-litecell15/tch.c b/src/osmo-bts-litecell15/tch.c
index e246ffb1..b2513887 100644
--- a/src/osmo-bts-litecell15/tch.c
+++ b/src/osmo-bts-litecell15/tch.c
@@ -45,6 +45,7 @@
#include <osmo-bts/measurement.h>
#include <osmo-bts/amr.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/dtx_dl_amr_fsm.h>
#include <nrw/litecell15/litecell15.h>
#include <nrw/litecell15/gsml1prim.h>
@@ -198,8 +199,7 @@ static struct msgb *l1_to_rtppayload_amr(uint8_t *l1_payload, uint8_t payload_le
* \returns number of \a l1_payload bytes filled
*/
static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload,
- uint8_t payload_len,
- struct gsm_lchan *lchan, uint8_t ft)
+ uint8_t payload_len, uint8_t ft)
{
memcpy(l1_payload, rtp_payload, payload_len);
return payload_len;
@@ -210,10 +210,11 @@ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload,
/*! \brief function for incoming RTP via TCH.req
* \param[in] rtp_pl buffer containing RTP payload
* \param[in] rtp_pl_len length of \a rtp_pl
+ * \param[in] use_cache Use cached payload instead of parsing RTP
* \param[in] marker RTP header Marker bit (indicates speech onset)
* \returns 0 if encoding result can be sent further to L1 without extra actions
* positive value if data is ready AND extra actions are required
- * negative value otherwise
+ * negative value otherwise (no data for L1 encoded)
*
* This function prepares a msgb with a L1 PH-DATA.req primitive and
* queues it into lchan->dl_tch_queue.
@@ -223,7 +224,8 @@ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload,
* pre-fill the primtive.
*/
int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
- const uint8_t *rtp_pl, unsigned int rtp_pl_len, uint32_t fn, bool marker)
+ const uint8_t *rtp_pl, unsigned int rtp_pl_len, uint32_t fn,
+ bool use_cache, bool marker)
{
uint8_t *payload_type;
uint8_t *l1_payload, ft;
@@ -242,17 +244,17 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
*payload_type = GsmL1_TchPlType_Fr;
rc = rtppayload_to_l1_fr(l1_payload,
rtp_pl, rtp_pl_len);
- if (rc)
+ if (rc && lchan->ts->trx->bts->dtxd)
is_sid = osmo_fr_check_sid(rtp_pl, rtp_pl_len);
} else{
*payload_type = GsmL1_TchPlType_Hr;
rc = rtppayload_to_l1_hr(l1_payload,
rtp_pl, rtp_pl_len);
- if (rc)
+ if (rc && lchan->ts->trx->bts->dtxd)
is_sid = osmo_hr_check_sid(rtp_pl, rtp_pl_len);
}
if (is_sid)
- save_last_sid(lchan, rtp_pl, rtp_pl_len, fn, -1, 0, 0);
+ dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, -1);
break;
case GSM48_CMODE_SPEECH_EFR:
*payload_type = GsmL1_TchPlType_Efr;
@@ -261,25 +263,75 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
/* FIXME: detect and save EFR SID */
break;
case GSM48_CMODE_SPEECH_AMR:
- rc = dtx_amr_check_onset(lchan, rtp_pl, rtp_pl_len, fn,
- l1_payload, &ft);
+ if (use_cache) {
+ *payload_type = GsmL1_TchPlType_Amr;
+ rtppayload_to_l1_amr(l1_payload, lchan->tch.dtx.cache,
+ lchan->tch.dtx.len, ft);
+ *len = lchan->tch.dtx.len + 1;
+ return 0;
+ }
+
+ rc = dtx_dl_amr_fsm_step(lchan, rtp_pl, rtp_pl_len, fn,
+ l1_payload, marker, len, &ft);
+ if (rc < 0)
+ return rc;
+ if (!lchan->ts->trx->bts->dtxd) {
+ *payload_type = GsmL1_TchPlType_Amr;
+ rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len,
+ ft);
+ return 0;
+ }
- if (marker || rc > 0) {
+ /* DTX DL-specific logic below: */
+ switch (lchan->tch.dtx.dl_amr_fsm->state) {
+ case ST_ONSET_V:
+ case ST_ONSET_F:
*payload_type = GsmL1_TchPlType_Amr_Onset;
+ dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0);
*len = 1;
- if (rc != 0) {
- LOGP(DRTP, LOGL_NOTICE, "%s SPEECH frame without"
- " Marker: ONSET forced\n",
- get_value_string(osmo_amr_type_names, ft));
- return rc;
+ return 1;
+ case ST_VOICE:
+ *payload_type = GsmL1_TchPlType_Amr;
+ rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len,
+ ft);
+ return 0;
+ case ST_SID_F1:
+ if (lchan->type == GSM_LCHAN_TCH_H) { /* AMR HR */
+ *payload_type = GsmL1_TchPlType_Amr_SidFirstP1;
+ rtppayload_to_l1_amr(l1_payload + 2, rtp_pl,
+ rtp_pl_len, ft);
+ return 0;
}
- LOGP(DRTP, LOGL_DEBUG, "%s SPEECH frame with Marker\n",
- get_value_string(osmo_amr_type_names, ft));
- }
- else {
+ /* AMR FR */
*payload_type = GsmL1_TchPlType_Amr;
- rc = 2 + rtppayload_to_l1_amr(l1_payload + 2, rtp_pl,
- rtp_pl_len, lchan, ft);
+ rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len,
+ ft);
+ return 0;
+ case ST_SID_F2:
+ *payload_type = GsmL1_TchPlType_Amr;
+ rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len,
+ ft);
+ return 0;
+ case ST_F1_INH:
+ *payload_type = GsmL1_TchPlType_Amr_SidFirstInH;
+ *len = 3;
+ dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0);
+ return 1;
+ case ST_U_INH:
+ *payload_type = GsmL1_TchPlType_Amr_SidUpdateInH;
+ *len = 3;
+ dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0);
+ return 1;
+ case ST_SID_U:
+ return -EAGAIN;
+ case ST_FACCH_V:
+ case ST_FACCH:
+ /* FIXME: if this possible at all? */
+ return 0;
+ default:
+ LOGP(DRTP, LOGL_ERROR, "Unhandled DTX DL AMR FSM state "
+ "%d\n", lchan->tch.dtx.dl_amr_fsm->state);
+ return -EINVAL;
}
break;
default:
@@ -442,7 +494,20 @@ struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn)
switch (lchan->tch_mode) {
case GSM48_CMODE_SPEECH_AMR:
- *payload_type = GsmL1_TchPlType_Amr;
+ if (lchan->type == GSM_LCHAN_TCH_H &&
+ lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1 &&
+ lchan->ts->trx->bts->dtxd) {
+ *payload_type = GsmL1_TchPlType_Amr_SidFirstP2;
+ rc = dtx_dl_amr_fsm_step(lchan, NULL, 0, fn, l1_payload,
+ false, &(msu_param->u8Size),
+ NULL);
+ if (rc < 0) {
+ msgb_free(msg);
+ return NULL;
+ }
+ return msg;
+ } else
+ *payload_type = GsmL1_TchPlType_Amr;
break;
case GSM48_CMODE_SPEECH_V1:
if (lchan->type == GSM_LCHAN_TCH_F)
@@ -458,12 +523,13 @@ struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn)
return NULL;
}
- rc = repeat_last_sid(lchan, l1_payload, fn);
- if (!rc) {
- msgb_free(msg);
- return NULL;
+ if (lchan->ts->trx->bts->dtxd) {
+ rc = repeat_last_sid(lchan, l1_payload, fn);
+ if (!rc) {
+ msgb_free(msg);
+ return NULL;
+ }
+ msu_param->u8Size = rc;
}
- msu_param->u8Size = rc;
-
return msg;
}