mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-bts.git
synced 2025-11-05 22:53:28 +00:00
Compare commits
2 Commits
master
...
keith/dtx-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9153cac1d0 | ||
|
|
069ba5838e |
@@ -137,17 +137,24 @@ static uint32_t fn_ms_adj(uint32_t fn, const struct gsm_lchan *lchan)
|
||||
/* 12/13 frames usable for audio in TCH,
|
||||
160 samples per RTP packet,
|
||||
1 RTP packet per 4 frames */
|
||||
|
||||
/*! Return the difference of two specified TDMA frame numbers (subtraction) */
|
||||
const uint32_t _num_fn = (fn - lchan->tch.last_fn) * 12 * 160 / (13 * 4); //GSM_TDMA_FN_SUB(fn, lchan->tch.last_fn);
|
||||
const uint32_t num_fn = GSM_TDMA_FN_SUB(fn, lchan->tch.last_fn);
|
||||
|
||||
samples_passed = num_fn * 12 * 160 / (13 * 4);
|
||||
//LOGPLCHAN(lchan, DRTP, LOGL_NOTICE, "OLD [%d], NEW [%d]\n", _num_fn, samples_passed);
|
||||
/* round number of samples to the nearest multiple of
|
||||
GSM_RTP_DURATION */
|
||||
GSM_RTP_DURATION = 160 */
|
||||
r = samples_passed + GSM_RTP_DURATION / 2;
|
||||
r -= r % GSM_RTP_DURATION;
|
||||
|
||||
if (r != GSM_RTP_DURATION)
|
||||
if (r != GSM_RTP_DURATION) {
|
||||
LOGPLCHAN(lchan, DRTP, LOGL_ERROR, "RTP clock out of sync with lower layer:"
|
||||
" %"PRIu32" vs %d (%"PRIu32"->%"PRIu32")\n",
|
||||
r, GSM_RTP_DURATION, lchan->tch.last_fn, fn);
|
||||
" %"PRIu32" vs %d (%"PRIu32"->%"PRIu32") DIFF[%d] SAMPLES[%d]\n ",
|
||||
r, GSM_RTP_DURATION, lchan->tch.last_fn, fn, num_fn, samples_passed);
|
||||
//return r;
|
||||
}
|
||||
}
|
||||
return GSM_RTP_DURATION;
|
||||
}
|
||||
@@ -181,7 +188,8 @@ int add_l1sap_header(struct gsm_bts_trx *trx, struct msgb *rmsg,
|
||||
{
|
||||
struct osmo_phsap_prim *l1sap;
|
||||
|
||||
LOGPLCHAN(lchan, DL1P, LOGL_DEBUG, "Rx -> RTP: %s\n", osmo_hexdump(rmsg->data, rmsg->len));
|
||||
if (rmsg->len > 0)
|
||||
LOGPLCHAN(lchan, DL1P, LOGL_INFO, "Rx -> RTP: %s\n", osmo_hexdump(rmsg->data, rmsg->len));
|
||||
|
||||
rmsg->l2h = rmsg->data;
|
||||
rmsg->l1h = msgb_push(rmsg, sizeof(*l1sap));
|
||||
@@ -635,7 +643,7 @@ static int l1sap_info_time_ind(struct gsm_bts *bts,
|
||||
unsigned int frames_expired;
|
||||
unsigned int i;
|
||||
|
||||
DEBUGPFN(DL1P, info_time_ind->fn, "Rx MPH_INFO time ind\n");
|
||||
//DEBUGPFN(DL1P, info_time_ind->fn, "Rx MPH_INFO time ind\n");
|
||||
|
||||
/* Calculate and check frame difference */
|
||||
frames_expired = GSM_TDMA_FN_SUB(info_time_ind->fn, bts->gsm_time.fn);
|
||||
@@ -1603,35 +1611,54 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap,
|
||||
* the content is not available due to decoding issues. Content not
|
||||
* available is expected as empty payload. We also check if quality is
|
||||
* good enough. */
|
||||
if (msg->len && tch_ind->lqual_cb >= bts->min_qual_norm) {
|
||||
/* hand msg to RTP code for transmission */
|
||||
if (lchan->abis_ip.osmux.use) {
|
||||
lchan_osmux_send_frame(lchan, msg->data, msg->len,
|
||||
fn_ms_adj(fn, lchan), lchan->rtp_tx_marker);
|
||||
} else if (lchan->abis_ip.rtp_socket) {
|
||||
osmo_rtp_send_frame_ext(lchan->abis_ip.rtp_socket,
|
||||
msg->data, msg->len, fn_ms_adj(fn, lchan), lchan->rtp_tx_marker);
|
||||
}
|
||||
/* if loopback is enabled, also queue received RTP data */
|
||||
if (lchan->loopback) {
|
||||
/* add new frame to queue, make sure the queue doesn't get too long */
|
||||
lchan_dl_tch_queue_enqueue(lchan, msg, 1);
|
||||
/* Return 1 to signal that we're still using msg and it should not be freed */
|
||||
return 1;
|
||||
}
|
||||
/* Only clear the marker bit once we have sent a RTP packet with it */
|
||||
lchan->rtp_tx_marker = false;
|
||||
} else {
|
||||
DEBUGPGT(DRTP, &g_time, "Skipping RTP frame with lost payload (chan_nr=0x%02x)\n",
|
||||
//if (1 == 1) {
|
||||
if (!msg->len || (tch_ind->lqual_cb / 10 < bts->min_qual_norm)) {
|
||||
LOGPGT(DRTP, LOGL_NOTICE, &g_time, "Skipping RTP frame with lost payload (chan_nr=0x%02x)\n",
|
||||
chan_nr);
|
||||
if (lchan->abis_ip.osmux.use)
|
||||
lchan_osmux_skipped_frame(lchan, fn_ms_adj(fn, lchan));
|
||||
else if (lchan->abis_ip.rtp_socket)
|
||||
osmo_rtp_skipped_frame(lchan->abis_ip.rtp_socket, fn_ms_adj(fn, lchan));
|
||||
|
||||
lchan->rtp_tx_marker = true;
|
||||
lchan->tch.last_fn = fn;
|
||||
//lchan->tch.dtx.is_speech_resume = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lchan->abis_ip.osmux.use) {
|
||||
lchan_osmux_send_frame(lchan, msg->data, msg->len,
|
||||
fn_ms_adj(fn, lchan), lchan->rtp_tx_marker);
|
||||
} else if (lchan->abis_ip.rtp_socket) {
|
||||
if (msg->len > 0 || lchan->rtp_tx_marker)
|
||||
LOGPGT(DL1P, LOGL_INFO, &g_time, "Send RTP Frame [%d]--> %s\n",
|
||||
msg->len, osmo_hexdump(msg->data, msg->len));
|
||||
/*
|
||||
int osmo_rtp_send_frame_ext(struct osmo_rtp_socket *rs, const uint8_t *payload,
|
||||
unsigned int payload_len, unsigned int duration,
|
||||
bool marker);
|
||||
|
||||
--> duration in number of RTP clock ticks.
|
||||
The duration is the timestamp increase
|
||||
|
||||
*/
|
||||
osmo_rtp_send_frame_ext(lchan->abis_ip.rtp_socket,
|
||||
msg->data, msg->len, fn_ms_adj(fn, lchan), lchan->rtp_tx_marker);
|
||||
}
|
||||
/* if loopback is enabled, also queue received RTP data */
|
||||
if (lchan->loopback) {
|
||||
/* add new frame to queue, make sure the queue doesn't get too long */
|
||||
lchan_dl_tch_queue_enqueue(lchan, msg, 1);
|
||||
/* Return 1 to signal that we're still using msg and it should not be freed */
|
||||
return 1;
|
||||
}
|
||||
/* Only clear the marker bit once we have sent a RTP packet with it */
|
||||
//lchan->rtp_tx_marker = false;
|
||||
|
||||
lchan->tch.last_fn = fn;
|
||||
if (lchan->tch.dtx.is_speech_resume)
|
||||
lchan->tch.dtx.is_speech_resume = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1677,7 +1677,7 @@ static int parse_multirate_config(struct gsm_lchan *lchan,
|
||||
}
|
||||
|
||||
parsed:
|
||||
amr_log_mr_conf(DRTP, LOGL_DEBUG, gsm_lchan_name(lchan), &lchan->tch.amr_mr);
|
||||
amr_log_mr_conf(DRTP, LOGL_INFO, gsm_lchan_name(lchan), &lchan->tch.amr_mr);
|
||||
lchan->tch.last_cmr = AMR_CMR_NONE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -819,7 +819,7 @@ int _sched_compose_tch_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
if (tch_len)
|
||||
memcpy(msg->l2h, tch, tch_len);
|
||||
|
||||
LOGL1S(DL1P, LOGL_DEBUG, l1ts, chan, l1sap->u.data.fn, "%s Rx -> RTP: %s\n",
|
||||
LOGL1S(DL1P, LOGL_INFO, l1ts, chan, l1sap->u.data.fn, "%s Rx -> RTP: %s\n",
|
||||
gsm_lchan_name(lchan), osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
|
||||
/* forward primitive */
|
||||
l1sap_up(l1ts->ts->trx, l1sap);
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
/**
|
||||
* EEPROM device file
|
||||
*/
|
||||
#define EEPROM_DEV "/sys/bus/i2c/devices/i2c-1/1-0050/eeprom"
|
||||
#define EEPROM_DEV "eeprom"
|
||||
|
||||
/**
|
||||
* EEPROM configuration start address
|
||||
|
||||
@@ -56,7 +56,7 @@ enum l1prim_type {
|
||||
};
|
||||
|
||||
#if !defined(SUPERFEMTO_API_VERSION) || SUPERFEMTO_API_VERSION < SUPERFEMTO_API(2,1,0)
|
||||
enum uperfemto_clk_src {
|
||||
enum Superfemto_clk_src {
|
||||
SF_CLKSRC_NONE = 0,
|
||||
SF_CLKSRC_OCXO = 1,
|
||||
SF_CLKSRC_TCXO = 2,
|
||||
|
||||
@@ -966,7 +966,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
|
||||
|
||||
gsm_fn2gsmtime(&g_time, fn);
|
||||
|
||||
DEBUGPGT(DL1P, &g_time, "Rx PH-DATA.ind %s (hL2 %08x): %s, " LOG_FMT_MEAS "\n",
|
||||
LOGPGT(DL1P, LOGL_INFO, &g_time, "Rx PH-DATA.ind %s (hL2 %08x): %s, " LOG_FMT_MEAS "\n",
|
||||
get_value_string(femtobts_l1sapi_names, data_ind->sapi), data_ind->hLayer2,
|
||||
osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size),
|
||||
LOG_PARAM_MEAS(&data_ind->measParam));
|
||||
@@ -980,6 +980,9 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (data_ind->sapi == GsmL1_Sapi_FacchF)
|
||||
LOGPFN(DL1P, LOGL_INFO, data_ind->u32Fn, "Rx SAPI FACCH\n");
|
||||
|
||||
/* fill L1SAP header */
|
||||
sap_msg = l1sap_msgb_alloc(data_ind->msgUnitParam.u8Size);
|
||||
l1sap = msgb_l1sap_prim(sap_msg);
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "sysmobts_par.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
#define EEPROM_PATH "/sys/devices/platform/i2c_davinci.1/i2c-1/1-0050/eeprom"
|
||||
#define EEPROM_PATH "eeprom"
|
||||
|
||||
static const struct osmo_crc8gen_code crc8_ccit = {
|
||||
.bits = 8,
|
||||
|
||||
@@ -56,6 +56,7 @@ static struct msgb *l1_to_rtppayload_fr(uint8_t *l1_payload, uint8_t payload_len
|
||||
{
|
||||
struct msgb *msg;
|
||||
uint8_t *cur;
|
||||
bool t;
|
||||
|
||||
msg = msgb_alloc_headroom(1024, 128, "L1P-to-RTP");
|
||||
if (!msg)
|
||||
@@ -76,8 +77,9 @@ static struct msgb *l1_to_rtppayload_fr(uint8_t *l1_payload, uint8_t payload_len
|
||||
|
||||
cur[0] |= 0xD0;
|
||||
#endif /* USE_L1_RTP_MODE */
|
||||
|
||||
lchan_set_marker(osmo_fr_check_sid(l1_payload, payload_len), lchan);
|
||||
t = osmo_fr_check_sid(l1_payload, payload_len);
|
||||
lchan_set_marker(t, lchan);
|
||||
LOGP(DL1P, LOGL_ERROR, "FR SID:%d\n", t);
|
||||
|
||||
return msg;
|
||||
}
|
||||
@@ -280,11 +282,12 @@ static struct msgb *l1_to_rtppayload_amr(uint8_t *l1_payload, uint8_t payload_le
|
||||
* Audiocode's MGW doesn't like receiving CMRs that are not
|
||||
* the same as the previous one. This means we need to patch
|
||||
* the content here.
|
||||
*/
|
||||
|
||||
if ((cur[0] & 0xF0) == 0xF0)
|
||||
cur[0]= lchan->tch.last_cmr << 4;
|
||||
else
|
||||
lchan->tch.last_cmr = cur[0] >> 4;
|
||||
*/
|
||||
#else
|
||||
u_int8_t cmr;
|
||||
uint8_t ft = l1_payload[2] & 0xF;
|
||||
@@ -508,12 +511,13 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
|
||||
uint8_t *payload, payload_type, payload_len, sid_first[9] = { 0 };
|
||||
struct msgb *rmsg = NULL;
|
||||
struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];
|
||||
int len;
|
||||
|
||||
if (is_recv_only(lchan->abis_ip.speech_mode))
|
||||
return -EAGAIN;
|
||||
|
||||
if (data_ind->msgUnitParam.u8Size < 1) {
|
||||
LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "chan_nr %d Rx Payload size 0\n", chan_nr);
|
||||
LOGPFN(DL1P, LOGL_NOTICE, data_ind->u32Fn, "chan_nr %d Rx Payload size 0\n", chan_nr);
|
||||
/* Push empty payload to upper layers */
|
||||
rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP");
|
||||
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
|
||||
@@ -528,6 +532,10 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
|
||||
payload = data_ind->msgUnitParam.u8Buffer + 1;
|
||||
payload_len = data_ind->msgUnitParam.u8Size - 1;
|
||||
|
||||
/* clear RTP marker if the marker has previously sent */
|
||||
if (!lchan->tch.dtx.is_speech_resume)
|
||||
lchan->rtp_tx_marker = false;
|
||||
|
||||
switch (payload_type) {
|
||||
case GsmL1_TchPlType_Fr:
|
||||
#if defined(L1_HAS_EFR) && defined(USE_L1_RTP_MODE)
|
||||
@@ -544,40 +552,47 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
|
||||
if (lchan->type != GSM_LCHAN_TCH_H &&
|
||||
lchan->type != GSM_LCHAN_TCH_F)
|
||||
goto err_payload_match;
|
||||
LOGPFN(DL1P, LOGL_NOTICE, data_ind->u32Fn, "DTX: received Speech from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
break;
|
||||
case GsmL1_TchPlType_Amr_Onset:
|
||||
if (lchan->type != GSM_LCHAN_TCH_H &&
|
||||
lchan->type != GSM_LCHAN_TCH_F)
|
||||
goto err_payload_match;
|
||||
LOGPFN(DL1P, LOGL_NOTICE, data_ind->u32Fn, "DTX: received ONSET from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
/* according to 3GPP TS 26.093 ONSET frames precede the first
|
||||
speech frame of a speech burst - set the marker for next RTP
|
||||
frame */
|
||||
lchan->tch.dtx.is_speech_resume = true;
|
||||
lchan->rtp_tx_marker = true;
|
||||
break;
|
||||
case GsmL1_TchPlType_Amr_SidFirstP1:
|
||||
if (lchan->type != GSM_LCHAN_TCH_H)
|
||||
goto err_payload_match;
|
||||
LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_P1 from L1 "
|
||||
LOGPFN(DL1P, LOGL_NOTICE, data_ind->u32Fn, "DTX: received SID_FIRST_P1 from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
break;
|
||||
case GsmL1_TchPlType_Amr_SidFirstP2:
|
||||
if (lchan->type != GSM_LCHAN_TCH_H)
|
||||
goto err_payload_match;
|
||||
LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_P2 from L1 "
|
||||
LOGPFN(DL1P, LOGL_NOTICE, data_ind->u32Fn, "DTX: received SID_FIRST_P2 from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
break;
|
||||
case GsmL1_TchPlType_Amr_SidFirstInH:
|
||||
if (lchan->type != GSM_LCHAN_TCH_H)
|
||||
goto err_payload_match;
|
||||
lchan->tch.dtx.is_speech_resume = true;
|
||||
lchan->rtp_tx_marker = true;
|
||||
LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_INH from L1 "
|
||||
LOGPFN(DL1P, LOGL_NOTICE, data_ind->u32Fn, "DTX: received SID_FIRST_INH from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
break;
|
||||
case GsmL1_TchPlType_Amr_SidUpdateInH:
|
||||
if (lchan->type != GSM_LCHAN_TCH_H)
|
||||
goto err_payload_match;
|
||||
lchan->tch.dtx.is_speech_resume = true;
|
||||
lchan->rtp_tx_marker = true;
|
||||
LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_UPDATE_INH from L1 "
|
||||
LOGPFN(DL1P, LOGL_NOTICE, data_ind->u32Fn, "DTX: received SID_UPDATE_INH from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
break;
|
||||
default:
|
||||
@@ -587,7 +602,6 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (payload_type) {
|
||||
case GsmL1_TchPlType_Fr:
|
||||
rmsg = l1_to_rtppayload_fr(payload, payload_len, lchan);
|
||||
@@ -603,12 +617,24 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
|
||||
case GsmL1_TchPlType_Amr:
|
||||
rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan);
|
||||
break;
|
||||
case GsmL1_TchPlType_Amr_SidFirstP1:
|
||||
memcpy(sid_first, payload, payload_len);
|
||||
int len = osmo_amr_rtp_enc(sid_first, 0, AMR_SID, AMR_GOOD);
|
||||
case GsmL1_TchPlType_Amr_Onset:
|
||||
/*memcpy(sid_first+2, payload, payload_len);
|
||||
len = osmo_amr_rtp_enc(sid_first, 15, AMR_SID, AMR_GOOD);
|
||||
LOGPFN(DL1P, LOGL_INFO, data_ind->u32Fn, "ONSET resulted in length [%d]\n", len);
|
||||
if (len < 0)
|
||||
return 0;
|
||||
rmsg = l1_to_rtppayload_amr(sid_first, len, lchan);
|
||||
len = len+2;
|
||||
rmsg = l1_to_rtppayload_amr(sid_first, len, lchan);*/
|
||||
break;
|
||||
case GsmL1_TchPlType_Amr_SidFirstP1:
|
||||
rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan);
|
||||
lchan->rtp_tx_marker = false;
|
||||
/*memcpy(sid_first, payload, payload_len);
|
||||
len = osmo_amr_rtp_enc(sid_first, 0, AMR_SID, AMR_GOOD);
|
||||
LOGPFN(DL1P, LOGL_INFO, data_ind->u32Fn, "SID P1 resulted in length [%d]\n", len);
|
||||
if (len < 0)
|
||||
return 0;
|
||||
rmsg = l1_to_rtppayload_amr(sid_first, len, lchan);*/
|
||||
break;
|
||||
/* FIXME: what about GsmL1_TchPlType_Amr_SidBad? not well documented. */
|
||||
}
|
||||
|
||||
@@ -434,7 +434,7 @@ struct msgb *tch_dl_dequeue(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br
|
||||
if (chan_state->codec[i] == ft_codec)
|
||||
ft = i;
|
||||
}
|
||||
if (ft < 0) {
|
||||
if (ft_codec != 8 && ft < 0) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br,
|
||||
"Codec (FT = %d) of RTP frame not in list\n", ft_codec);
|
||||
goto free_bad_msg;
|
||||
|
||||
Reference in New Issue
Block a user