Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
/*! \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;
}