static struct msgb *l1_to_rtppayload_fr(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_FR_BYTES); memcpy(cur, l1_payload, GSM_FR_BYTES); #else /* step1: reverse the bit-order of each payload byte */ osmo_revbytebits_buf(l1_payload, payload_len); cur = msgb_put(msg, GSM_FR_BYTES); /* step2: we need to shift the entire L1 payload by 4 bits right */ osmo_nibble_shift_right(cur, l1_payload, GSM_FR_BITS/4); cur[0] |= 0xD0; #endif /* USE_L1_RTP_MODE */ lchan_set_marker(osmo_fr_check_sid(l1_payload, payload_len), lchan); return msg; }
static struct msgb *l1_to_rtppayload_fr(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_FR_BYTES); memcpy(cur, l1_payload, GSM_FR_BYTES); lchan_set_marker(osmo_fr_check_sid(l1_payload, payload_len), lchan); return msg; }
/*! \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 (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. * * Note that the actual L1 primitive header is not fully initialized * yet, as things like the frame number, etc. are unknown at the time we * 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 use_cache, bool marker) { uint8_t *payload_type; uint8_t *l1_payload, ft; int rc = 0; bool is_sid = false; DEBUGP(DRTP, "%s RTP IN: %s\n", gsm_lchan_name(lchan), osmo_hexdump(rtp_pl, rtp_pl_len)); payload_type = &data[0]; l1_payload = &data[1]; switch (lchan->tch_mode) { case GSM48_CMODE_SPEECH_V1: if (lchan->type == GSM_LCHAN_TCH_F) { *payload_type = GsmL1_TchPlType_Fr; rc = rtppayload_to_l1_fr(l1_payload, rtp_pl, rtp_pl_len); 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 && lchan->ts->trx->bts->dtxd) is_sid = osmo_hr_check_sid(rtp_pl, rtp_pl_len); } if (is_sid) dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, -1); break; #if defined(L1_HAS_EFR) && defined(USE_L1_RTP_MODE) case GSM48_CMODE_SPEECH_EFR: *payload_type = GsmL1_TchPlType_Efr; rc = rtppayload_to_l1_efr(l1_payload, rtp_pl, rtp_pl_len); /* FIXME: detect and save EFR SID */ break; #endif case GSM48_CMODE_SPEECH_AMR: 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 (!dtx_dl_amr_enabled(lchan)) { *payload_type = GsmL1_TchPlType_Amr; rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len, ft); return 0; } /* DTX DL-specific logic below: */ switch (lchan->tch.dtx.dl_amr_fsm->state) { case ST_ONSET_V: *payload_type = GsmL1_TchPlType_Amr_Onset; dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0); *len = 3; 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; } /* AMR FR */ *payload_type = GsmL1_TchPlType_Amr; 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: return -EBADMSG; default: LOGP(DRTP, LOGL_ERROR, "Unhandled DTX DL AMR FSM state " "%d\n", lchan->tch.dtx.dl_amr_fsm->state); return -EINVAL; } break; default: /* we don't support CSD modes */ rc = -1; break; } if (rc < 0) { LOGP(DRTP, LOGL_ERROR, "%s unable to parse RTP payload\n", gsm_lchan_name(lchan)); return -EBADMSG; } *len = rc + 1; DEBUGP(DRTP, "%s RTP->L1: %s\n", gsm_lchan_name(lchan), osmo_hexdump(data, *len)); return 0; }