Change-Id: I09e3c6cc8139d7be042278775b8de0b223513d53
This commit is contained in:
Harald Welte 2020-08-24 15:20:37 +02:00
parent 9319514041
commit 71dce2a4e4
3 changed files with 259 additions and 76 deletions

View File

@ -35,7 +35,7 @@ const int g_remote_port = 9000;
const int g_local_port = 8000;
/* codec; can be OSMO_TRAU16_FT_FR or OSMO_TRAU16_FT_EFR */
const enum osmo_trau_frame_type g_ftype = OSMO_TRAU16_FT_EFR;
const enum osmo_trau_frame_type g_ftype = OSMO_TRAU16_FT_AMR;
/***********************************************************************
* END CONFIGURATION
@ -114,21 +114,35 @@ static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int
if (g_local_loop) {
/* Mirror back to other sub-slot */
struct sc_state *peer = opposite_schan(sc);
if (peer) {
struct msgb *msg = msgb_alloc(2*40*8, "mirror");
if (!peer)
return;
struct msgb *msg = msgb_alloc(2*40*8, "mirror");
if (fr.type == OSMO_TRAU16_FT_AMR) {
//fr.c_bits[12-1] = FIXME; /* Req/Ind flag; use from UL */
fr.c_bits[13-1] = 1; /* UFT: no errors */
memset(&fr.c_bits[14-1], 0, 3); /* Config_Prot: no TFO */
memset(&fr.c_bits[17-1], 0, 2); /* Message_No: no TFO */
fr.c_bits[19-1] = 1; /* Reserved */
fr.c_bits[20-1] = 1; /* Reserved */
} else {
fr.c_bits[12-1] = 1; /* C12 = good u-link frame */
memset(&fr.c_bits[13-1], 1, 3); /* C13..C15: spare */
fr.c_bits[16-1] = 1; /* C16 = SP[eech]; no DTX */
memset(&fr.c_bits[6-1], 0, 6); /* C6..C11: tie alignment */
fr.dir = OSMO_TRAU_DIR_DL;
rc = osmo_trau_frame_encode(msgb_data(msg), 2*40*8, &fr);
OSMO_ASSERT(rc >= 0);
msgb_put(msg, rc);
osmo_i460_mux_enqueue(peer->i460_sc, msg);
}
fr.dir = OSMO_TRAU_DIR_DL;
rc = osmo_trau_frame_encode(msgb_data(msg), 2*40*8, &fr);
OSMO_ASSERT(rc >= 0);
msgb_put(msg, rc);
osmo_i460_mux_enqueue(peer->i460_sc, msg);
} else {
/* Convert to RTP */
if (fr.type != OSMO_TRAU16_FT_FR && fr.type != OSMO_TRAU16_FT_EFR)
if (fr.type != OSMO_TRAU16_FT_FR &&
fr.type != OSMO_TRAU16_FT_EFR &&
fr.type != OSMO_TRAU16_FT_AMR)
goto skip;
uint8_t rtpbuf[35];

View File

@ -24,6 +24,11 @@
struct osmo_trau2rtp_state {
enum osmo_trau_frame_type type;
struct {
enum osmo_amr_type last_cmi;
enum osmo_amr_type last_cmr;
bool cmi_cmr_phase;
} amr;
};

View File

@ -26,6 +26,7 @@
#include <osmocom/core/crc8gen.h>
#include <osmocom/codec/codec.h>
#include <osmocom/netif/amr.h>
#include <osmocom/trau/trau_frame.h>
#include <osmocom/trau/trau_rtp.h>
@ -489,103 +490,199 @@ static int rtp2trau_efr(struct osmo_trau_frame *tf, const uint8_t *data, size_t
return 0;
}
#if 0
static inline memcpy_inc(uint8_t *out, const uint8_t *in, size_t len, unsigned int *idx)
/* memcpy + increment index */
static inline void memcpy_inc(uint8_t *out, const uint8_t *in, size_t len, unsigned int *idx)
{
memcpy_inc(out, in, len);
memcpy(out, in, len);
*idx += len;
}
#define S_FROM_D(sbits, dbits, d_from, d_to, idx) \
memcpy_inc(sbits + idx, dbits + (d_from-1), d_to - (d_from-1), &idx)
/* extract the AMR s-bits (codec parameters) from the TRAU frame D-bits */
static int amr_speech_extract_sbits(ubit_t *s_bits, const struct osmo_trau_frame *tf,
enum osmo_amr_mode mode)
enum osmo_amr_type mode)
{
unsigned int s_idx = 0;
switch (mode) {
case AMR_4_75:
memcpy_inc(s_bits + s_idx, tf->d_bits + 44, 67 - 44, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 67, 92 - 67, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 108 - 95, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 111, 132 - 111, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 135, 148 - 135, &s_idx);
S_FROM_D(s_bits, tf->d_bits, 45, 67, s_idx);
S_FROM_D(s_bits, tf->d_bits, 68, 92, s_idx);
S_FROM_D(s_bits, tf->d_bits, 96, 108, s_idx);
S_FROM_D(s_bits, tf->d_bits, 112, 132, s_idx);
S_FROM_D(s_bits, tf->d_bits, 136, 148, s_idx);
break;
case AMR_5_15:
memcpy_inc(s_bits + s_idx, tf->d_bits + 46, 96 - 46, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 69, 92 - 69, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 114 - 95, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 117, 136 - 117, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 139, 158 - 139, &s_idx);
S_FROM_D(s_bits, tf->d_bits, 47, 69, s_idx);
S_FROM_D(s_bits, tf->d_bits, 70, 92, s_idx);
S_FROM_D(s_bits, tf->d_bits, 96, 114, s_idx);
S_FROM_D(s_bits, tf->d_bits, 118, 136, s_idx);
S_FROM_D(s_bits, tf->d_bits, 140, 158, s_idx);
break;
case AMR_5_90:
memcpy_inc(s_bits + s_idx, tf->d_bits + 41, 67 - 41, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 67, 92 - 67, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 116 - 95, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 119, 144 - 119, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 147, 168 - 147, &s_idx);
S_FROM_D(s_bits, tf->d_bits, 42, 67, s_idx);
S_FROM_D(s_bits, tf->d_bits, 68, 92, s_idx);
S_FROM_D(s_bits, tf->d_bits, 96, 116, s_idx);
S_FROM_D(s_bits, tf->d_bits, 120, 144, s_idx);
S_FROM_D(s_bits, tf->d_bits, 148, 168, s_idx);
break;
case AMR_6_70:
memcpy_inc(s_bits + s_idx, tf->d_bits + 37, 63 - 37, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 63, 92 - 63, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 120 - 95, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 123, 152 - 123, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 155, 180 - 155, &s_idx);
S_FROM_D(s_bits, tf->d_bits, 38, 63, s_idx);
S_FROM_D(s_bits, tf->d_bits, 64, 92, s_idx);
S_FROM_D(s_bits, tf->d_bits, 96, 120, s_idx);
S_FROM_D(s_bits, tf->d_bits, 124, 152, s_idx);
S_FROM_D(s_bits, tf->d_bits, 156, 180, s_idx);
break;
case AMR_7_40:
memcpy_inc(s_bits + s_idx, tf->d_bits + 34, 60 - 34, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 60, 92 - 60, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 124 - 95, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 127, 159 - 127, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 162, 191 - 162, &s_idx);
S_FROM_D(s_bits, tf->d_bits, 35, 60, s_idx);
S_FROM_D(s_bits, tf->d_bits, 61, 92, s_idx);
S_FROM_D(s_bits, tf->d_bits, 96, 124, s_idx);
S_FROM_D(s_bits, tf->d_bits, 128, 159, s_idx);
S_FROM_D(s_bits, tf->d_bits, 163, 191, s_idx);
break;
case AMR_7_95:
memcpy_inc(s_bits + s_idx, tf->d_bits + 31, 58 - 31, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 58, 92 - 58, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 127 - 95, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 130, 164 - 130, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 167, 199 - 167, &s_idx);
S_FROM_D(s_bits, tf->d_bits, 32, 58, s_idx);
S_FROM_D(s_bits, tf->d_bits, 59, 92, s_idx);
S_FROM_D(s_bits, tf->d_bits, 96, 127, s_idx);
S_FROM_D(s_bits, tf->d_bits, 131, 164, s_idx);
S_FROM_D(s_bits, tf->d_bits, 168, 199, s_idx);
break;
case AMR_10_2:
memcpy_inc(s_bits + s_idx, tf->d_bits + 20, 46 - 20, &s_idx); /* D21..D46 */
memcpy_inc(s_bits + s_idx, tf->d_bits + 46, 92 - 46, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 138 - 95, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 141, 187 - 141, &s_idx);
memcpy_inc(s_bits + s_idx, tf->d_bits + 190, 233 - 190, &s_idx);
S_FROM_D(s_bits, tf->d_bits, 21, 46, s_idx);
S_FROM_D(s_bits, tf->d_bits, 47, 92, s_idx);
S_FROM_D(s_bits, tf->d_bits, 96, 138, s_idx);
S_FROM_D(s_bits, tf->d_bits, 142, 187, s_idx);
S_FROM_D(s_bits, tf->d_bits, 191, 233, s_idx);
break;
case AMR_12_2:
memcpy_inc(s_bits + s_idx, tf->d_bits + 0, 38 - 0, &s_idx); /* D1..D38 */
memcpy_inc(s_bits + s_idx, tf->d_bits + 38, 91 - 38, &s_idx); /* D39..D91 */
memcpy_inc(s_bits + s_idx, tf->d_bits + 94, 144 - 94, &s_idx); /* D95..D144 */
memcpy_inc(s_bits + s_idx, tf->d_bits + 147, 200 - 147, &s_idx);/* D148..D200 */
memcpy_inc(s_bits + s_idx, tf->d_bits + 203, 253 - 203, &s_idx);/* D204..D253 */
S_FROM_D(s_bits, tf->d_bits, 1, 38, s_idx); /* D1..D38 */
S_FROM_D(s_bits, tf->d_bits, 39, 91, s_idx); /* D39..D91 */
S_FROM_D(s_bits, tf->d_bits, 95, 144, s_idx); /* D95..D144 */
S_FROM_D(s_bits, tf->d_bits, 148, 200, s_idx); /* D148..D200 */
S_FROM_D(s_bits, tf->d_bits, 204, 253, s_idx); /* D204..D253 */
break;
default:
osmo_panic("unknown AMR speech mode: %u", mode);
break;
}
return s_idx;
}
/* TS 48.060 Section 5.5.1.2.2 */
static int trau2rtp_16(uint8_t *out, const struct osmo_trau_frame *tf, enum osmo_amr_mode last_cmi)
#define D_FROM_S(dbits, sbits, d_from, d_to, idx) \
memcpy_inc(dbits + (d_from-1), sbits + idx, d_to - (d_from-1), &idx)
/* encode the AMR TRAU frame D-bits from the s-bits (codec parameters) */
static int amr_speech_encode_sbits(struct osmo_trau_frame *tf, const ubit_t *s_bits, enum osmo_amr_type mode)
{
enum osmo_amr_mode mode = last_cmi;
uint8_t frame_class = tf->c_bits[21] << 1 | tf->c_bits[20];
uint8_t cmr_cmi = tf->c_bits[23] << 2 | tf->c_bits[24] << 1 | tf->cb_bits[25];
uint8_t no_speech_cls;
uint8_t s_bits[242];
uint8_t d_bits[242];
unsigned int s_idx = 0;
ubit_t rif = FIXME;
switch (mode) {
case AMR_4_75:
D_FROM_S(tf->d_bits, s_bits, 45, 67, s_idx);
D_FROM_S(tf->d_bits, s_bits, 68, 92, s_idx);
D_FROM_S(tf->d_bits, s_bits, 96, 108, s_idx);
D_FROM_S(tf->d_bits, s_bits, 112, 132, s_idx);
D_FROM_S(tf->d_bits, s_bits, 136, 148, s_idx);
break;
case AMR_5_15:
D_FROM_S(tf->d_bits, s_bits, 47, 69, s_idx);
D_FROM_S(tf->d_bits, s_bits, 70, 92, s_idx);
D_FROM_S(tf->d_bits, s_bits, 96, 114, s_idx);
D_FROM_S(tf->d_bits, s_bits, 118, 136, s_idx);
D_FROM_S(tf->d_bits, s_bits, 140, 158, s_idx);
break;
case AMR_5_90:
D_FROM_S(tf->d_bits, s_bits, 42, 67, s_idx);
D_FROM_S(tf->d_bits, s_bits, 68, 92, s_idx);
D_FROM_S(tf->d_bits, s_bits, 96, 116, s_idx);
D_FROM_S(tf->d_bits, s_bits, 124, 152, s_idx);
D_FROM_S(tf->d_bits, s_bits, 156, 180, s_idx);
break;
case AMR_6_70:
D_FROM_S(tf->d_bits, s_bits, 38, 63, s_idx);
D_FROM_S(tf->d_bits, s_bits, 64, 92, s_idx);
D_FROM_S(tf->d_bits, s_bits, 96, 120, s_idx);
D_FROM_S(tf->d_bits, s_bits, 124, 152, s_idx);
D_FROM_S(tf->d_bits, s_bits, 156, 180, s_idx);
break;
case AMR_7_40:
D_FROM_S(tf->d_bits, s_bits, 35, 60, s_idx);
D_FROM_S(tf->d_bits, s_bits, 61, 92, s_idx);
D_FROM_S(tf->d_bits, s_bits, 96, 124, s_idx);
D_FROM_S(tf->d_bits, s_bits, 128, 159, s_idx);
D_FROM_S(tf->d_bits, s_bits, 163, 191, s_idx);
break;
case AMR_7_95:
D_FROM_S(tf->d_bits, s_bits, 32, 58, s_idx);
D_FROM_S(tf->d_bits, s_bits, 59, 92, s_idx);
D_FROM_S(tf->d_bits, s_bits, 96, 127, s_idx);
D_FROM_S(tf->d_bits, s_bits, 131, 164, s_idx);
D_FROM_S(tf->d_bits, s_bits, 168, 199, s_idx);
break;
case AMR_10_2:
D_FROM_S(tf->d_bits, s_bits, 21, 46, s_idx);
D_FROM_S(tf->d_bits, s_bits, 47, 92, s_idx);
D_FROM_S(tf->d_bits, s_bits, 96, 138, s_idx);
D_FROM_S(tf->d_bits, s_bits, 142, 187, s_idx);
D_FROM_S(tf->d_bits, s_bits, 191, 233, s_idx);
break;
case AMR_12_2:
D_FROM_S(tf->d_bits, s_bits, 1, 38, s_idx);
D_FROM_S(tf->d_bits, s_bits, 39, 91, s_idx);
D_FROM_S(tf->d_bits, s_bits, 95, 144, s_idx);
D_FROM_S(tf->d_bits, s_bits, 148, 200, s_idx);
D_FROM_S(tf->d_bits, s_bits, 204, 253, s_idx);
default:
osmo_panic("unknown AMR speech mode: %u", mode);
break;
}
}
/* Frame_Classification as per TS 48.060 Section 5.5.1.2.1 */
enum amr_frame_class {
AMR_FCLS_SPEECH_GOOD = 3,
AMR_FCLS_SPEECH_DEGRADED = 2,
AMR_FCLS_SPEECH_BAD = 1,
AMR_FCLS_NO_SPEECH = 0,
};
/* TS 48.060 Section 5.5.1.2.2 */
static int trau2rtp_16(uint8_t *out, const struct osmo_trau_frame *tf, struct osmo_trau2rtp_state *st)
{
uint8_t frame_class = (tf->c_bits[21-1] << 1) | tf->c_bits[20-1];
uint8_t cmr_cmi = (tf->c_bits[23-1] << 2) | (tf->c_bits[24-1] << 1) | tf->c_bits[25-1];
ubit_t rif = tf->c_bits[12-1]; /* Request (1) or Indication (0) Flag */
uint8_t tac_pac = (tf->c_bits[6-1] << 5) | (tf->c_bits[7-1] << 4) | (tf->c_bits[8-1] << 3) |
(tf->c_bits[9-1] << 2) | (tf->c_bits[10-1] << 1) | tf->c_bits[11-1];
uint8_t no_speech_cls;
uint8_t s_bits[244];
uint8_t d_bits[244];
bool bad_frame = false;
int n_sbits = 0;
if (tf->type != OSMO_TRAU16_FT_AMR)
return -EINVAL;
if (rif == 0)
mode = cmr_cmi;
if (rif == 0) {
/* peer (BTS) tells us CMI */
st->amr.last_cmi = cmr_cmi;
} else {
/* peer (BTS) tells us CMR */
st->amr.last_cmr = cmr_cmi;
}
if (tac_pac == 0x3d) {
/* FIXME: BTS requests us to invert CMI/CMR phase in downlink */
}
switch (frame_class) {
case 0: // no speech
no_speech_cls = tf->d_bits[32] << 2 | tf->d_bits[33] << 1 | tf->d_bits[34];
cmi_abs = tf->d_bits[35] << 2 | tf->d_bits[36] < 1 || tf->d_bits[37];
cmr_abs = tf->d_bits[38] << 2 | tf->d_bits[39] < 1 || tf->d_bits[40];
case AMR_FCLS_NO_SPEECH:
no_speech_cls = (tf->d_bits[32-1] << 2) | (tf->d_bits[33-1] << 1) | tf->d_bits[34-1];
st->amr.last_cmi = (tf->d_bits[35-1] << 2) | (tf->d_bits[36-1] < 1) || tf->d_bits[37-1];
st->amr.last_cmr = (tf->d_bits[38-1] << 2) | (tf->d_bits[39-1] < 1) || tf->d_bits[40-1];
switch (no_speech_cls) {
case 7: // sid first
break;
@ -597,25 +694,89 @@ static int trau2rtp_16(uint8_t *out, const struct osmo_trau_frame *tf, enum osmo
break;
case 0: // no_data
break;
/* TOOD: PAB to be treated as PAC */
/* TODO: Time Alignment Extension (TAE) */
}
break;
case 1: // speech bad
case AMR_FCLS_SPEECH_BAD:
bad_frame = true;
break;
case 2:
case 3:
case AMR_FCLS_SPEECH_GOOD:
case AMR_FCLS_SPEECH_DEGRADED:
/* Extract the s-bits from the TRAU frame */
amr_speech_extract_sbits(s_bits, tf, mode);
n_sbits = amr_speech_extract_sbits(s_bits, tf, st->amr.last_cmi);
/* Convert the s-bits to d-bits */
osmo_amr_s_to_d(d_bits, s_bits, mode);
osmo_amr_s_to_d(d_bits, s_bits, n_sbits, st->amr.last_cmi);
break;
}
/* generate octet-aligned RTP AMR header / RFC4867 */
struct amr_hdr *amrh = (struct amr_hdr *) out;
amrh->pad1 = 0;
amrh->cmr = st->amr.last_cmr;
amrh->pad2 = 0;
amrh->q = !bad_frame;
amrh->ft = st->amr.last_cmi;
amrh->f = 0;
/* return number of bytes generated */
return osmo_ubit2pbit(out + sizeof(*amrh), d_bits, n_sbits) + sizeof(*amrh);
}
int trau2rtp_amr(uint8_t *out, const struct osmo_trau_frame *tf, enum osmo_amr_mode last_cmi))
static int rtp2trau_amr(struct osmo_trau_frame *tf, const uint8_t *data, size_t data_len,
struct osmo_trau2rtp_state *st)
{
struct amr_hdr *amrh = (struct amr_hdr *) data;
ubit_t s_bits[244];
if (data_len < sizeof(*amrh))
return -EIO;
if (data_len > FIXME)
data_len = FIXM;
/* C1..C5: AMR */
tf->c_bits[1-1] = 0;
tf->c_bits[2-1] = 0;
tf->c_bits[3-1] = 1;
tf->c_bits[4-1] = 1;
tf->c_bits[5-1] = 0;
/* C6..C11: TAF: TAC / PAC */
memset(&tf->c_bits[6-1], 0, 6);
//tf->c_bits[12-1] = ; /* RIF */
tf->c_bits[13-1] = 1; /* UFE */
memset(&tf->c_bits[14-1], 0, 3); /* Config_Prot */
memset(&tf->c_bits[17-1], 0, 3); /* Message_No */
tf->c_bits[19-1] = 1; /* spare */
tf->c_bits[20-1] = 1; /* spare */
#if 0
tf->c_bits[21-1]
tf->c_bits[22-1]
/* CMI (RIF=0) or CMR (RIF=1) */
tf->c_bits[23-1]
tf->c_bits[24-1]
tf->c_bits[25-1]
#endif
/* TODO: convert s-bits to d-bits */
osmo_pbit2ubit(s_bits, data + sizeof(*amrh), data_len-sizeof(*amrh));
amr_speech_encode_sbits(tf, s_bits, mode)
/* TODO: compute CRC */
return 0;
}
int trau2rtp_amr(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf, struct osmo_trau2rtp_state *st)
{
switch (tf->type) {
case OSMO_TRAU16_FT_AMR:
return trau2rtp_16(out, tf, last_cmi);
return trau2rtp_16(out, tf, st);
case OSMO_TRAU8_AMR_LOW:
case OSMO_TRAU8_AMR_6k7:
case OSMO_TRAU8_AMR_7k4:
@ -623,7 +784,6 @@ int trau2rtp_amr(uint8_t *out, const struct osmo_trau_frame *tf, enum osmo_amr_m
return -EINVAL;
}
}
#endif
int osmo_trau2rtp(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf,
struct osmo_trau2rtp_state *st)
@ -635,6 +795,8 @@ int osmo_trau2rtp(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf
return trau2rtp_efr(out, out_len, tf);
case OSMO_TRAU16_FT_HR:
return trau2rtp_hr16(out, out_len, tf);
case OSMO_TRAU16_FT_AMR:
return trau2rtp_amr(out, out_len, tf, st);
default:
return -EINVAL;
}
@ -650,6 +812,8 @@ int osmo_rtp2trau(struct osmo_trau_frame *tf, const uint8_t *rtp, size_t rtp_len
return rtp2trau_efr(tf, rtp, rtp_len);
case OSMO_TRAU16_FT_HR:
return rtp2trau_hr16(tf, rtp, rtp_len);
case OSMO_TRAU16_FT_AMR:
//return rtp2trau_amr(tf, rtp, rtp_len, st);
default:
return -EINVAL;
}