static struct msgb *l1_to_rtppayload_efr(uint8_t *l1_payload, uint8_t payload_len, struct gsm_lchan *lchan) { struct msgb *msg; uint8_t *cur; msg = msgb_alloc_headroom(1024, 128, "L1C-to-RTP"); if (!msg) return NULL; #ifdef USE_L1_RTP_MODE /* new L1 can deliver bits like we need them */ cur = msgb_put(msg, GSM_EFR_BYTES); memcpy(cur, l1_payload, GSM_EFR_BYTES); #else /* step1: reverse the bit-order of each payload byte */ osmo_revbytebits_buf(l1_payload, payload_len); cur = msgb_put(msg, GSM_EFR_BYTES); /* step 2: we need to shift the entire L1 payload by 4 bits right */ osmo_nibble_shift_right(cur, l1_payload, GSM_EFR_BITS/4); cur[0] |= 0xC0; #endif /* USE_L1_RTP_MODE */ enum osmo_amr_type ft; enum osmo_amr_quality bfi; uint8_t cmr; int8_t sti, cmi; osmo_amr_rtp_dec(l1_payload, payload_len, &cmr, &cmi, &ft, &bfi, &sti); lchan_set_marker(ft == AMR_GSM_EFR_SID, lchan); return msg; }
static struct msgb *l1_to_rtppayload_efr(uint8_t *l1_payload, uint8_t payload_len, struct gsm_lchan *lchan) { struct msgb *msg; uint8_t *cur; msg = msgb_alloc_headroom(1024, 128, "L1P-to-RTP"); if (!msg) return NULL; /* new L1 can deliver bits like we need them */ cur = msgb_put(msg, GSM_EFR_BYTES); memcpy(cur, l1_payload, GSM_EFR_BYTES); enum osmo_amr_type ft; enum osmo_amr_quality bfi; uint8_t cmr; int8_t sti, cmi; osmo_amr_rtp_dec(l1_payload, payload_len, &cmr, &cmi, &ft, &bfi, &sti); lchan_set_marker(ft == AMR_GSM_EFR_SID, lchan); return msg; }
/*! \brief Check current state of DTX DL AMR FSM and dispatch necessary events * \param[in] lchan Logical channel on which we check scheduling * \param[in] rtp_pl buffer with RTP data * \param[in] rtp_pl_len length of rtp_pl * \param[in] fn Frame Number for which we check scheduling * \param[in] l1_payload buffer where CMR and CMI prefix should be added * \param[in] marker RTP Marker bit * \param[out] len Length of expected L1 payload * \param[out] ft_out Frame Type to be populated after decoding * \returns 0 in case of success; negative on error */ int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl, size_t rtp_pl_len, uint32_t fn, uint8_t *l1_payload, bool marker, uint8_t *len, uint8_t *ft_out) { uint8_t cmr; enum osmo_amr_type ft; enum osmo_amr_quality bfi; int8_t sti, cmi; int rc; if (dtx_dl_amr_enabled(lchan)) { if (lchan->type == GSM_LCHAN_TCH_H && lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2 && !rtp_pl) { *len = 3; /* SID-FIRST P1 -> P2 completion */ memcpy(l1_payload, lchan->tch.dtx.cache, 2); dtx_dispatch(lchan, E_SID_U); return 0; } } if (!rtp_pl_len) return -EBADMSG; rc = osmo_amr_rtp_dec(rtp_pl, rtp_pl_len, &cmr, &cmi, &ft, &bfi, &sti); if (rc < 0) { LOGP(DRTP, LOGL_ERROR, "failed to decode AMR RTP (length %zu)\n", rtp_pl_len); return rc; } /* only needed for old sysmo firmware: */ *ft_out = ft; /* CMI in downlink tells the L1 encoder which encoding function * it will use, so we have to use the frame type */ if (osmo_amr_is_speech(ft)) cmi = ft; /* populate L1 payload with CMR/CMI - might be ignored by caller: */ amr_set_mode_pref(l1_payload, &lchan->tch.amr_mr, cmi, cmr); /* populate DTX cache with CMR/CMI - overwrite cache which will be either updated or invalidated by caller anyway: */ amr_set_mode_pref(lchan->tch.dtx.cache, &lchan->tch.amr_mr, cmi, cmr); *len = 3 + rtp_pl_len; /* DTX DL is not enabled, move along */ if (!lchan->ts->trx->bts->dtxd) return 0; if (osmo_amr_is_speech(ft)) { /* AMR HR - Inhibition */ if (lchan->type == GSM_LCHAN_TCH_H && marker && lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1) return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, E_INHIB, (void *)lchan); /* AMR FR & HR - generic */ if (marker && (lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1 || lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2 || lchan->tch.dtx.dl_amr_fsm->state == ST_SID_U )) return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, E_ONSET, (void *)lchan); return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, E_VOICE, (void *)lchan); } if (ft == AMR_SID) { if (lchan->tch.dtx.dl_amr_fsm->state == ST_VOICE) { /* SID FIRST/UPDATE scheduling logic relies on SID FIRST being sent first hence we have to force caching of SID as FIRST regardless of actually decoded type */ dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, false); return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, E_SID_F, (void *)lchan); } else dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, sti); return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, sti ? E_SID_U : E_SID_F, (void *)lchan); } if (ft != AMR_NO_DATA) { LOGP(DRTP, LOGL_ERROR, "unsupported AMR FT 0x%02x\n", ft); return -ENOTSUP; } if (marker) osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, E_VOICE, (void *)lchan); *len = 0; return 0; }