aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2020-02-06 14:31:22 +0100
committerlaforge <laforge@osmocom.org>2020-04-25 14:03:06 +0000
commit58b9f1189843a91f53bce76b3afa9483f89440a0 (patch)
tree08b2c78e0749622636c82b7c42bd3b489bb77dc5
parent557ca0f468494f23171e4631734e931a7f5e7631 (diff)
dtx: add detection of AMR DTX frames for osmo-bts-trx
Currently we do not detect any of the DTX frames (SID_FIRST, SID_UPDATE etc.) Detecting and tagging those frames as is_sub is important for measurement processing. Also the RTP marker bit must be set on each ONSET frame. - Add detection of DTX frames - Tag DTX frames as is_sub and set frame type to AMR_SID - Set RTP marker bit when ONSET frames are received Change-Id: I5afe730fff2fa3199a5913b0de4f5c7b23a39f31 Depends: libosmocore I2bbdb39ea20461ca08b2e6f1a33532cb55cd5195 Related: OS#2978
-rw-r--r--include/osmo-bts/scheduler.h1
-rw-r--r--include/osmo-bts/scheduler_backend.h3
-rw-r--r--src/common/scheduler.c4
-rw-r--r--src/osmo-bts-trx/scheduler_trx.c112
4 files changed, 107 insertions, 13 deletions
diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h
index fed3f04e..c0264119 100644
--- a/include/osmo-bts/scheduler.h
+++ b/include/osmo-bts/scheduler.h
@@ -106,6 +106,7 @@ struct l1sched_chan_state {
uint8_t ul_cmr; /* current uplink CMR index */
uint8_t dl_cmr; /* current downlink CMR index */
uint8_t amr_loop; /* if AMR loop is enabled */
+ uint8_t amr_last_dtx; /* last received dtx frame type */
/* TCH/H */
uint8_t dl_ongoing_facch; /* FACCH/H on downlink */
diff --git a/include/osmo-bts/scheduler_backend.h b/include/osmo-bts/scheduler_backend.h
index 201b48c3..cfbe7f25 100644
--- a/include/osmo-bts/scheduler_backend.h
+++ b/include/osmo-bts/scheduler_backend.h
@@ -53,7 +53,8 @@ int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len,
- int16_t ta_offs_256bits, uint16_t ber10k, float rssi);
+ int16_t ta_offs_256bits, uint16_t ber10k, float rssi,
+ uint8_t is_sub);
ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
diff --git a/src/common/scheduler.c b/src/common/scheduler.c
index fc4f11ed..be3ae42e 100644
--- a/src/common/scheduler.c
+++ b/src/common/scheduler.c
@@ -739,7 +739,8 @@ int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len,
- int16_t ta_offs_256bits, uint16_t ber10k, float rssi)
+ int16_t ta_offs_256bits, uint16_t ber10k, float rssi,
+ uint8_t is_sub)
{
struct msgb *msg;
struct osmo_phsap_prim *l1sap;
@@ -758,6 +759,7 @@ int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
l1sap->u.tch.rssi = (int8_t) (rssi);
l1sap->u.tch.ber10k = ber10k;
l1sap->u.tch.ta_offs_256bits = ta_offs_256bits;
+ l1sap->u.tch.is_sub = is_sub & 1;
msg->l2h = msgb_put(msg, tch_len);
if (tch_len)
diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c
index f17354a8..8c3dd64f 100644
--- a/src/osmo-bts-trx/scheduler_trx.c
+++ b/src/osmo-bts-trx/scheduler_trx.c
@@ -37,6 +37,8 @@
#include <osmocom/core/bits.h>
#include <osmocom/gsm/a5.h>
#include <osmocom/coding/gsm0503_coding.h>
+#include <osmocom/coding/gsm0503_amr_dtx.h>
+
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/logging.h>
@@ -400,7 +402,7 @@ inval_mode1:
/* Note: RSSI is set to 0 to indicate to the higher
* layers that this is a faked tch_ind */
- _sched_compose_tch_ind(l1t, tn, fn, chan, tch_data, len, toa256, 10000, 0);
+ _sched_compose_tch_ind(l1t, tn, fn, chan, tch_data, len, toa256, 10000, 0, 0);
}
}
@@ -1138,6 +1140,8 @@ int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
get_lchan_by_chan_nr(l1t->trx, trx_chan_desc[chan].chan_nr | bi->tn);
unsigned int fn_begin;
uint16_t ber10k;
+ uint8_t is_sub = 0;
+ uint8_t ft;
/* handle rach, if handover rach detection is turned on */
if (chan_state->ho_rach_detect == 1)
@@ -1200,21 +1204,65 @@ int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
* the first FN 4,13,21 defines that CMR is included in frame.
* NOTE: A frame ends 7 FN after start.
*/
- rc = gsm0503_tch_afs_decode(tch_data + 2, *bursts_p,
+
+ /* The AFS_ONSET frame itself does not result into an RTP frame
+ * since it only contains a recognition pattern that marks the
+ * end of the DTX interval. To mark the end of the DTX interval
+ * in the RTP stream as well, the voice frame after the
+ * AFS_ONSET frame is used. */
+ if (chan_state->amr_last_dtx == AFS_ONSET)
+ lchan_set_marker(false, lchan);
+
+ /* we store tch_data + 2 header bytes, the amr variable set to
+ * 2 will allow us to skip the first 2 bytes in case we did
+ * receive an FACCH frame instead of a voice frame (we do not
+ * know this before we actually decode the frame) */
+ amr = 2;
+ rc = gsm0503_tch_afs_decode_dtx(tch_data + amr, *bursts_p,
(((bi->fn + 26 - 7) % 26) >> 2) & 1, chan_state->codec,
chan_state->codecs, &chan_state->ul_ft,
- &chan_state->ul_cmr, &n_errors, &n_bits_total);
+ &chan_state->ul_cmr, &n_errors, &n_bits_total, &chan_state->amr_last_dtx);
+
+ /* Tag all frames that are not regular AMR voice frames as
+ * SUB-Frames */
+ if (chan_state->amr_last_dtx != AMR_OTHER) {
+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
+ "Received AMR SID frame: %s\n",
+ gsm0503_amr_dtx_frame_name(chan_state->amr_last_dtx));
+ is_sub = 1;
+ }
+
+ /* The occurrence of the following frames indicates that we
+ * are either at the beginning or in the middle of a talk
+ * spurt. We update the SID status accordingly, but we do
+ * not want the marker to be set, since this must only
+ * happen when the talk spurt is over (see above) */
+ switch (chan_state->amr_last_dtx) {
+ case AFS_SID_FIRST:
+ case AFS_SID_UPDATE:
+ case AFS_SID_UPDATE_CN:
+ lchan_set_marker(true, lchan);
+ lchan->rtp_tx_marker = false;
+ break;
+ }
+
if (rc)
trx_loop_amr_input(l1t,
trx_chan_desc[chan].chan_nr | bi->tn, chan_state,
n_errors, n_bits_total);
- amr = 2; /* we store tch_data + 2 header bytes */
/* only good speech frames get rtp header */
if (rc != GSM_MACBLOCK_LEN && rc >= 4) {
+ if (chan_state->amr_last_dtx == AMR_OTHER) {
+ ft = chan_state->codec[chan_state->ul_cmr];
+ } else {
+ /* SID frames will always get Frame Type Index 8 (AMR_SID) */
+ ft = AMR_SID;
+ }
rc = osmo_amr_rtp_enc(tch_data,
chan_state->codec[chan_state->ul_cmr],
- chan_state->codec[chan_state->ul_ft], AMR_GOOD);
+ ft, AMR_GOOD);
}
+
break;
default:
LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,
@@ -1308,7 +1356,7 @@ bfi:
compose_l1sap:
fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_F);
return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan,
- tch_data, rc, bi->toa256, ber10k, bi->rssi);
+ tch_data, rc, bi->toa256, ber10k, bi->rssi, is_sub);
}
/*! \brief a single TCH/H burst was received by the PHY, process it */
@@ -1336,6 +1384,8 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
int fn_is_odd = (((bi->fn + 26 - 10) % 26) >> 2) & 1;
unsigned int fn_begin;
uint16_t ber10k;
+ uint8_t is_sub = 0;
+ uint8_t ft;
/* handle RACH, if handover RACH detection is turned on */
if (chan_state->ho_rach_detect == 1)
@@ -1409,21 +1459,61 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
* in frame, the first FN 4,13,21 or 5,14,22 defines that CMR
* is included in frame.
*/
- rc = gsm0503_tch_ahs_decode(tch_data + 2, *bursts_p,
+
+ /* See comment in function rx_tchf_fn() */
+ switch (chan_state->amr_last_dtx) {
+ case AHS_ONSET:
+ case AHS_SID_FIRST_INH:
+ case AHS_SID_UPDATE_INH:
+ lchan_set_marker(false, lchan);
+ break;
+ }
+
+ /* See comment in function rx_tchf_fn() */
+ amr = 2;
+ rc = gsm0503_tch_ahs_decode_dtx(tch_data + amr, *bursts_p,
fn_is_odd, fn_is_odd, chan_state->codec,
chan_state->codecs, &chan_state->ul_ft,
- &chan_state->ul_cmr, &n_errors, &n_bits_total);
+ &chan_state->ul_cmr, &n_errors, &n_bits_total, &chan_state->amr_last_dtx);
+
+ /* Tag all frames that are not regular AMR voice frames
+ as SUB-Frames */
+ if (chan_state->amr_last_dtx != AMR_OTHER) {
+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
+ "Received AMR SID frame: %s\n",
+ gsm0503_amr_dtx_frame_name(chan_state->amr_last_dtx));
+ is_sub = 1;
+ }
+
+ /* See comment in function rx_tchf_fn() */
+ switch (chan_state->amr_last_dtx) {
+ case AHS_SID_FIRST_P1:
+ case AHS_SID_FIRST_P2:
+ case AHS_SID_UPDATE:
+ case AHS_SID_UPDATE_CN:
+ lchan_set_marker(true, lchan);
+ lchan->rtp_tx_marker = false;
+ break;
+ }
+
if (rc)
trx_loop_amr_input(l1t,
trx_chan_desc[chan].chan_nr | bi->tn, chan_state,
n_errors, n_bits_total);
- amr = 2; /* we store tch_data + 2 two */
+
/* only good speech frames get rtp header */
if (rc != GSM_MACBLOCK_LEN && rc >= 4) {
+ if (chan_state->amr_last_dtx == AMR_OTHER) {
+ ft = chan_state->codec[chan_state->ul_cmr];
+ } else {
+ /* SID frames will always get Frame Type Index 8 (AMR_SID) */
+ ft = AMR_SID;
+ }
rc = osmo_amr_rtp_enc(tch_data,
chan_state->codec[chan_state->ul_cmr],
- chan_state->codec[chan_state->ul_ft], AMR_GOOD);
+ ft, AMR_GOOD);
}
+
break;
default:
LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,
@@ -1529,7 +1619,7 @@ compose_l1sap:
else
fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_H1);
return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan,
- tch_data, rc, bi->toa256, ber10k, bi->rssi);
+ tch_data, rc, bi->toa256, ber10k, bi->rssi, is_sub);
}
/* schedule all frames of all TRX for given FN */