From 58b9f1189843a91f53bce76b3afa9483f89440a0 Mon Sep 17 00:00:00 2001 From: Philipp Maier Date: Thu, 6 Feb 2020 14:31:22 +0100 Subject: 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 --- include/osmo-bts/scheduler.h | 1 + include/osmo-bts/scheduler_backend.h | 3 +- src/common/scheduler.c | 4 +- src/osmo-bts-trx/scheduler_trx.c | 112 +++++++++++++++++++++++++++++++---- 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 #include #include +#include + #include #include @@ -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 */ -- cgit v1.2.3