falconia submitted this change.
trau: implement TFO frame encoding function
Most differences between regular TRAU frames of TS 48.060 & 48.061
and TFO frames of TS 28.062 matter only in the frame decoding
direction. In the encoding direction, regular osmo_trau_frame_encode()
would have been sufficient for both frame types if it weren't for
the quirk of setting C1..C5 bits. osmo_trau_frame_encode() sets
these bits per its own mind for most frame types, ignoring the bits
passed by the user in fr->c_bits[]. This API behavior cannot be
changed without breaking existing users, but it is bad for TFO.
Solution: implement new osmo_trau_frame_encode_tfo() function
for TFO applications. As an additional benefit, the output buffer
space requirement is reduced because there is no possibility of
output frame extension for timing alignment.
Change-Id: I6e0ab4e5115f0aa6979ce93955b0e95b09041091
---
M include/osmocom/trau/trau_frame.h
M src/trau/trau_frame.c
2 files changed, 120 insertions(+), 37 deletions(-)
diff --git a/include/osmocom/trau/trau_frame.h b/include/osmocom/trau/trau_frame.h
index 8bdeb73..dd14f27 100644
--- a/include/osmocom/trau/trau_frame.h
+++ b/include/osmocom/trau/trau_frame.h
@@ -151,6 +151,8 @@
/* TFO frames are slightly modified TRAU-UL frames, and thus require slightly
* modified encoding and decoding functions. */
+int osmo_trau_frame_encode_tfo(ubit_t *bits, size_t n_bits, const struct osmo_trau_frame *fr);
+
int osmo_trau_frame_decode_tfo_16k(struct osmo_trau_frame *fr, const ubit_t *bits);
int osmo_trau_frame_decode_tfo_hr1(struct osmo_trau_frame *fr, const ubit_t *bits);
int osmo_trau_frame_decode_tfo_amr_8k(struct osmo_trau_frame *fr, const ubit_t *bits);
diff --git a/src/trau/trau_frame.c b/src/trau/trau_frame.c
index df4404d..fb98247 100644
--- a/src/trau/trau_frame.c
+++ b/src/trau/trau_frame.c
@@ -238,30 +238,34 @@
}
/* TS 08.60 Section 3.1.1 */
-static int encode16_fr(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
+static int encode16_fr(ubit_t *trau_bits, const struct osmo_trau_frame *fr, bool is_tfo)
{
const ubit_t *cbits5;
int i;
int d_idx = 0;
- switch (fr->type) {
- case OSMO_TRAU16_FT_IDLE:
- if (fr->dir == OSMO_TRAU_DIR_UL)
- cbits5 = ft_idle_up_bits;
- else
- cbits5 = ft_idle_down_bits;
- break;
- case OSMO_TRAU16_FT_FR:
- if (fr->dir == OSMO_TRAU_DIR_UL)
- cbits5 = ft_fr_up_bits;
- else
- cbits5 = ft_fr_down_bits;
- break;
- case OSMO_TRAU16_FT_EFR:
- cbits5 = ft_efr_bits;
- break;
- default:
- return -EINVAL;
+ if (is_tfo) {
+ cbits5 = fr->c_bits;
+ } else {
+ switch (fr->type) {
+ case OSMO_TRAU16_FT_IDLE:
+ if (fr->dir == OSMO_TRAU_DIR_UL)
+ cbits5 = ft_idle_up_bits;
+ else
+ cbits5 = ft_idle_down_bits;
+ break;
+ case OSMO_TRAU16_FT_FR:
+ if (fr->dir == OSMO_TRAU_DIR_UL)
+ cbits5 = ft_fr_up_bits;
+ else
+ cbits5 = ft_fr_down_bits;
+ break;
+ case OSMO_TRAU16_FT_EFR:
+ cbits5 = ft_efr_bits;
+ break;
+ default:
+ return -EINVAL;
+ }
}
encode_sync16(trau_bits);
@@ -314,17 +318,21 @@
}
/* TS 08.60 Section 3.1.2 */
-static int encode16_amr(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
+static int encode16_amr(ubit_t *trau_bits, const struct osmo_trau_frame *fr, bool is_tfo)
{
- const ubit_t *cbits5 = ft_amr_bits;
int i, d_idx;
encode_sync16(trau_bits);
- /* C1 .. C5 */
- memcpy(trau_bits + 17, cbits5 + 0, 5);
- /* C6 .. C15 */
- memcpy(trau_bits + 17 + 5, fr->c_bits + 5, 15 - 5);
+ if (is_tfo) {
+ /* C1 .. C15 */
+ memcpy(trau_bits + 17, fr->c_bits, 15);
+ } else {
+ /* C1 .. C5 */
+ memcpy(trau_bits + 17, ft_amr_bits, 5);
+ /* C6 .. C15 */
+ memcpy(trau_bits + 17 + 5, fr->c_bits + 5, 15 - 5);
+ }
trau_bits[32] = 1;
/* C16 .. C25 */
@@ -549,7 +557,7 @@
fr_idle_frame.c_bits[11] = 1; /* C12 (UFE), good frame */
fr_idle_frame.c_bits[15] = 1; /* C16 (SP), no DTX */
- encode16_fr(encoded_idle_frame, &fr_idle_frame);
+ encode16_fr(encoded_idle_frame, &fr_idle_frame, false);
dbits_initted = 1; /* set it to 1 to not call it again */
}
return encoded_idle_frame;
@@ -843,7 +851,7 @@
}
/* TS 08.61 Section 5.2.1.1 */
-static int encode8_hr(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
+static int encode8_hr(ubit_t *trau_bits, const struct osmo_trau_frame *fr, bool is_tfo)
{
int i, d_idx = 0;
@@ -858,11 +866,15 @@
/* C1 .. C5 */
ubit_t *cbits_out = trau_bits + 1 * 8 + 1;
if (fr->dir == OSMO_TRAU_DIR_UL) {
- cbits_out[0] = 0;
- cbits_out[1] = 0;
- cbits_out[2] = 0;
- cbits_out[3] = 1;
- cbits_out[4] = 0;
+ if (is_tfo) {
+ memcpy(cbits_out, fr->c_bits, 5);
+ } else {
+ cbits_out[0] = 0;
+ cbits_out[1] = 0;
+ cbits_out[2] = 0;
+ cbits_out[3] = 1;
+ cbits_out[4] = 0;
+ }
} else {
cbits_out[0] = 0;
cbits_out[1] = 0;
@@ -1241,9 +1253,21 @@
/*! Encode a TRAU frame from its decoded representation to a sequence of unpacked bits.
* \param[out] bits caller-allocated buffer for unpacked outpud bits
- * \param[in] n_bits size of 'bits' oputput buffer in number of unpacked bits
+ * \param[in] n_bits size of 'bits' output buffer in number of unpacked bits
* \param[in] fr decoded representation of TRAU frame to be encoded
- * \return 0 number of unpacked output bits generated; negative in case of error */
+ * \return 0 number of unpacked output bits generated; negative in case of error
+ *
+ * This function exhibits a behavioral quirk which users need to be aware of:
+ * for many frame types, the first 5 bits out of user-provided fr->c_bits[]
+ * (corresponding to C1..C5) are ignored and replaced with internally supplied
+ * constant values, where the function "knows" what the correct frame type code
+ * should be. This behavioral quirk is arguably a design defect, but it cannot
+ * be changed without breaking some existing applications that rely on this
+ * behavior and skip setting those bits themselves. For TFO applications
+ * where C1..C5 may need to be modified (especially TFO-AMR where this C1..C5
+ * modification must be done before CRC computation), please use
+ * osmo_trau_frame_encode_tfo().
+ */
int osmo_trau_frame_encode(ubit_t *bits, size_t n_bits, const struct osmo_trau_frame *fr)
{
/* check for sufficient space provided by caller in output buffer */
@@ -1287,11 +1311,11 @@
switch (fr->type) {
case OSMO_TRAU16_FT_FR:
case OSMO_TRAU16_FT_EFR:
- return encode16_fr(bits, fr);
+ return encode16_fr(bits, fr, false);
case OSMO_TRAU16_FT_HR:
return encode16_hr(bits, fr);
case OSMO_TRAU16_FT_AMR:
- return encode16_amr(bits, fr);
+ return encode16_amr(bits, fr, false);
case OSMO_TRAU16_FT_OAM:
return encode16_oam(bits, fr);
case OSMO_TRAU16_FT_IDLE:
@@ -1305,7 +1329,7 @@
case OSMO_TRAU16_FT_EDATA:
return encode16_edata(bits, fr);
case OSMO_TRAU8_SPEECH:
- return encode8_hr(bits, fr);
+ return encode8_hr(bits, fr, false);
case OSMO_TRAU8_DATA:
return encode8_data(bits, fr);
case OSMO_TRAU8_OAM:
@@ -1322,6 +1346,63 @@
}
}
+/*! Encode a TFO frame from its decoded representation to a sequence of unpacked bits.
+ * \param[out] bits caller-allocated buffer for unpacked outpud bits
+ * \param[in] n_bits size of 'bits' output buffer in number of unpacked bits
+ * \param[in] fr decoded representation of TRAU frame to be encoded
+ * \return 0 number of unpacked output bits generated; negative in case of error
+ *
+ * Compared to regular osmo_trau_frame_encode(), this TFO-specific TRAU frame
+ * encoding function restricts the set of possible frame types to those that
+ * are valid for TFO, restricts the direction to TRAU-UL, reduces the output
+ * space requirement (there is no timing alignment extension) and always uses
+ * all fr->c_bits provided by the application.
+ */
+int osmo_trau_frame_encode_tfo(ubit_t *bits, size_t n_bits, const struct osmo_trau_frame *fr)
+{
+ /* TFO frames are TRAU-UL only */
+ if (fr->dir != OSMO_TRAU_DIR_UL)
+ return -EINVAL;
+
+ /* check for sufficient space provided by caller in output buffer */
+ /* there is no timing alignment in TRAU-UL direction! */
+ switch (fr->type) {
+ case OSMO_TRAU16_FT_FR:
+ case OSMO_TRAU16_FT_EFR:
+ case OSMO_TRAU16_FT_AMR:
+ if (n_bits < 1 * 40 * 8)
+ return -ENOSPC;
+ break;
+ case OSMO_TRAU8_SPEECH:
+ case OSMO_TRAU8_AMR_LOW:
+ case OSMO_TRAU8_AMR_6k7:
+ case OSMO_TRAU8_AMR_7k4:
+ if (n_bits < 1 * 20 * 8)
+ return -ENOSPC;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fr->type) {
+ case OSMO_TRAU16_FT_FR:
+ case OSMO_TRAU16_FT_EFR:
+ return encode16_fr(bits, fr, true);
+ case OSMO_TRAU16_FT_AMR:
+ return encode16_amr(bits, fr, true);
+ case OSMO_TRAU8_SPEECH:
+ return encode8_hr(bits, fr, true);
+ case OSMO_TRAU8_AMR_LOW:
+ return encode8_amr_low(bits, fr);
+ case OSMO_TRAU8_AMR_6k7:
+ return encode8_amr_67(bits, fr);
+ case OSMO_TRAU8_AMR_7k4:
+ return encode8_amr_74(bits, fr);
+ default:
+ return -EINVAL;
+ }
+}
+
/*! Decode/parse a 16k TRAU frame from unpacked bits to decoded format.
* \param[out] fr caller-allocated output data structure
* \param[in] bits unpacked bits containing raw TRAU frame; must be aligned
To view, visit change 39495. To unsubscribe, or for help writing mail filters, visit settings.