aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2020-08-24 15:20:37 +0200
committerHarald Welte <laforge@osmocom.org>2020-09-17 23:34:28 +0200
commit71dce2a4e4bf111030ba4f88c571a80cdf4400c2 (patch)
tree3f2bef9f4fe4266575fde18a049b52ca1ce6bdb4
parent9319514041c2f9f8bea1736d3731bacb94cb041b (diff)
AMR: WIPlaforge/trau
-rw-r--r--contrib/trau2rtp/trau2rtp.c32
-rw-r--r--include/osmocom/trau/trau_rtp.h5
-rw-r--r--src/trau/trau_rtp_conv.c296
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 <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;
}
+#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;
}