From 71dce2a4e4bf111030ba4f88c571a80cdf4400c2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 24 Aug 2020 15:20:37 +0200 Subject: AMR: WIP Change-Id: I09e3c6cc8139d7be042278775b8de0b223513d53 --- contrib/trau2rtp/trau2rtp.c | 32 +++-- include/osmocom/trau/trau_rtp.h | 5 + src/trau/trau_rtp_conv.c | 296 +++++++++++++++++++++++++++++++--------- 3 files changed, 258 insertions(+), 75 deletions(-) diff --git a/contrib/trau2rtp/trau2rtp.c b/contrib/trau2rtp/trau2rtp.c index fc9462d..7a29f4c 100644 --- a/contrib/trau2rtp/trau2rtp.c +++ b/contrib/trau2rtp/trau2rtp.c @@ -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]; diff --git a/include/osmocom/trau/trau_rtp.h b/include/osmocom/trau/trau_rtp.h index f02d43e..33a6705 100644 --- a/include/osmocom/trau/trau_rtp.h +++ b/include/osmocom/trau/trau_rtp.h @@ -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; }; diff --git a/src/trau/trau_rtp_conv.c b/src/trau/trau_rtp_conv.c index ebbdbef..84b1cad 100644 --- a/src/trau/trau_rtp_conv.c +++ b/src/trau/trau_rtp_conv.c @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -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; } +#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) +{ + unsigned int s_idx = 0; + + 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, enum osmo_amr_mode last_cmi) +static int trau2rtp_16(uint8_t *out, const struct osmo_trau_frame *tf, struct osmo_trau2rtp_state *st) { - 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 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[242]; - uint8_t d_bits[242]; - unsigned int s_idx = 0; - ubit_t rif = FIXME; + 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); +} + +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, const struct osmo_trau_frame *tf, enum osmo_amr_mode last_cmi)) +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; } -- cgit v1.2.3