falconia has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/libosmo-abis/+/38133?usp=email )


Change subject: rtp2trau: add CSD support
......................................................................

rtp2trau: add CSD support

The previous patch in this series added CSD support to trau2rtp
converter; now add the same support in the opposite direction.

Change-Id: Ifa1a671f3797a22523bef4b5712d91d0131cdef7
---
M TODO-RELEASE
M include/osmocom/trau/trau_rtp.h
M src/trau/trau_rtp_conv.c
3 files changed, 222 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/libosmo-abis refs/changes/33/38133/1

diff --git a/TODO-RELEASE b/TODO-RELEASE
index 0ed7189..6160b28 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -7,3 +7,4 @@
 # If any interfaces have been added since the last public release: c:r:a + 1.
 # If any interfaces have been removed or changed since the last public 
release: c:r:0.
 #library       what                    description / commit summary line
+libosmotrau    struct osmo_trau2rtp_state extended (ABI break)
diff --git a/include/osmocom/trau/trau_rtp.h b/include/osmocom/trau/trau_rtp.h
index 6b2110f..3631b83 100644
--- a/include/osmocom/trau/trau_rtp.h
+++ b/include/osmocom/trau/trau_rtp.h
@@ -25,6 +25,7 @@
 struct osmo_trau2rtp_state {
        enum osmo_trau_frame_type type;
        uint8_t rtp_extensions;
+       bool interm_rate_16k;
 };


diff --git a/src/trau/trau_rtp_conv.c b/src/trau/trau_rtp_conv.c
index 9113f10..06979c6 100644
--- a/src/trau/trau_rtp_conv.c
+++ b/src/trau/trau_rtp_conv.c
@@ -1055,6 +1055,220 @@
        return RFC4040_RTP_PLEN;
 }

+/*
+ * CSD in the opposite direction: from clearmode RTP input
+ * to TRAU frame output.
+ *
+ * Important note about V.110 frame alignment: in the output from trau2rtp
+ * process or from OsmoBTS, the 2 or 4 V.110 frames that fit into a 20 ms
+ * RTP clearmode packet are always perfectly aligned in that packet.
+ * However, there does not seem to be any formally defined policy in
+ * Osmocom as to whether this alignment is required in RTP input to
+ * OsmoBTS or to the future RTP-to-E1 MGW (OsmoMGW extension or otherwise),
+ * or if these processes are required to hunt for arbitrary V.110 frame
+ * alignment in their RTP input.
+ *
+ * Given that the current CSD implementation in OsmoBTS requires perfect
+ * V.110 alignment in RTP input, and given that a stateful V.110 alignment
+ * hunt implementation cannot be fitted into osmo_rtp2trau API,
+ * the approach implemented here is to also require perfect alignment.
+ * If our RTP input is not a perfectly aligned pair or quadruple of
+ * V.110 frames, we emit an idle data frame (all bits set to 1) per
+ * TS 48.060 section 6.5.1 and TS 48.061 section 6.7.4.
+ *
+ * Also note: in the case of OSMO_TRAU16_FT_DATA output, the caller of
+ * osmo_rtp2trau() API must set st->interm_rate_16k (a Boolean flag)
+ * appropriately for 8 kbit/s or 16 kbit/s intermediate rate.
+ * In the absence of out-of-band information, this flag can be set
+ * from control bit C6 of the first received TRAU-UL frame - that is
+ * how traditional TRAUs do it.
+ */
+
+static bool check_v110_align(const ubit_t *ra_bits)
+{
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               if (ra_bits[i])
+                       return false;
+       }
+       for (i = 1; i < 10; i++) {
+               if (!ra_bits[i * 8])
+                       return false;
+       }
+       return true;
+}
+
+static void v110_to_63bits(ubit_t *out, const ubit_t *ra_bits)
+{
+       memcpy(out, ra_bits + 9, 7);
+       memcpy(out + 7, ra_bits + 17, 7);
+       memcpy(out + 14, ra_bits + 25, 7);
+       memcpy(out + 21, ra_bits + 33, 7);
+       memcpy(out + 28, ra_bits + 41, 7);
+       memcpy(out + 35, ra_bits + 49, 7);
+       memcpy(out + 42, ra_bits + 57, 7);
+       memcpy(out + 49, ra_bits + 65, 7);
+       memcpy(out + 56, ra_bits + 73, 7);
+}
+
+/* intermediate rate 8 kbit/s */
+static void rtp2trau_data_ir8(struct osmo_trau_frame *tf, const uint8_t *data,
+                             size_t data_len, unsigned second_offset)
+{
+       ubit_t ra_bits[80 * 2];
+       int i;
+
+       if (data_len != RFC4040_RTP_PLEN)
+               goto idle_fill;
+
+       /* reverse RA2 first */
+       for (i = 0; i < sizeof(ra_bits); i++)
+               ra_bits[i] = (data[i] >> 7) & 1;
+
+       /* enforce two properly aligned V.110 frames */
+       if (!check_v110_align(ra_bits))
+               goto idle_fill;
+       if (!check_v110_align(ra_bits + 80))
+               goto idle_fill;
+
+       /* all checks passed - copy the payload */
+       v110_to_63bits(tf->d_bits, ra_bits);
+       v110_to_63bits(tf->d_bits + second_offset, ra_bits + 80);
+       return;
+
+idle_fill:
+       memset(tf->d_bits, 1, 63);
+       memset(tf->d_bits + second_offset, 1, 63);
+}
+
+/* intermediate rate 16 kbit/s */
+static void rtp2trau_data_ir16(struct osmo_trau_frame *tf, const uint8_t *data,
+                              size_t data_len)
+{
+       ubit_t ra_bits[80 * 4];
+       int i, o;
+
+       if (data_len != RFC4040_RTP_PLEN)
+               goto idle_fill;
+
+       /* reverse RA2 first */
+       o = 0;
+       for (i = 0; i < RFC4040_RTP_PLEN; i++) {
+               ra_bits[o++] = (data[i] >> 7) & 1;
+               ra_bits[o++] = (data[i] >> 6) & 1;
+       }
+
+       /* enforce 4 properly aligned V.110 frames */
+       if (!check_v110_align(ra_bits))
+               goto idle_fill;
+       if (!check_v110_align(ra_bits + 80))
+               goto idle_fill;
+       if (!check_v110_align(ra_bits + 80 * 2))
+               goto idle_fill;
+       if (!check_v110_align(ra_bits + 80 * 3))
+               goto idle_fill;
+
+       /* all checks passed - copy the payload */
+       v110_to_63bits(tf->d_bits, ra_bits);
+       v110_to_63bits(tf->d_bits + 63, ra_bits + 80);
+       v110_to_63bits(tf->d_bits + 63 * 2, ra_bits + 80 * 2);
+       v110_to_63bits(tf->d_bits + 63 * 3, ra_bits + 80 * 3);
+       return;
+
+idle_fill:
+       memset(tf->d_bits, 1, 63 * 4);
+}
+
+static int rtp2trau_data_fr(struct osmo_trau_frame *tf, const uint8_t *data,
+                           size_t data_len, bool interm_rate_16k)
+{
+       tf->type = OSMO_TRAU16_FT_DATA;
+
+       if (tf->dir == OSMO_TRAU_DIR_UL) {
+               /* C1 .. C5: FR data UL */
+               tf->c_bits[0] = 0;
+               tf->c_bits[1] = 1;
+               tf->c_bits[2] = 0;
+               tf->c_bits[3] = 0;
+               tf->c_bits[4] = 0;
+       } else {
+               /* C1 .. C5: FR data DL */
+               tf->c_bits[0] = 1;
+               tf->c_bits[1] = 0;
+               tf->c_bits[2] = 1;
+               tf->c_bits[3] = 1;
+               tf->c_bits[4] = 0;
+       }
+
+       if (interm_rate_16k) {
+               tf->c_bits[5] = 1;
+               rtp2trau_data_ir16(tf, data, data_len);
+       } else {
+               tf->c_bits[5] = 0;
+               rtp2trau_data_ir8(tf, data, data_len, 63 * 2);
+               /* remaining data positions are unused in this format */
+               memset(tf->d_bits + 63, 1, 63);
+               memset(tf->d_bits + 63 * 3, 1, 63);
+       }
+
+       /* remaining C bits are unused */
+       memset(tf->c_bits + 6, 1, 9);
+
+       return 0;
+}
+
+static int rtp2trau_data_hr16(struct osmo_trau_frame *tf, const uint8_t *data,
+                             size_t data_len)
+{
+       tf->type = OSMO_TRAU16_FT_DATA_HR;
+
+       if (tf->dir == OSMO_TRAU_DIR_UL) {
+               /* C1 .. C5: HR data UL */
+               tf->c_bits[0] = 0;
+               tf->c_bits[1] = 1;
+               tf->c_bits[2] = 0;
+               tf->c_bits[3] = 0;
+               tf->c_bits[4] = 1;
+       } else {
+               /* C1 .. C5: HR data DL */
+               tf->c_bits[0] = 1;
+               tf->c_bits[1] = 0;
+               tf->c_bits[2] = 1;
+               tf->c_bits[3] = 1;
+               tf->c_bits[4] = 1;
+       }
+
+       tf->c_bits[5] = 0;
+       /* Note that Osmocom trau_frame decoding and encoding API
+        * puts the second reduced V.110 frame at d_bits position 63,
+        * unlike 8 kbit/s IR in FR-data frame type where it resides
+        * at d_bits position 63 * 2. */
+       rtp2trau_data_ir8(tf, data, data_len, 63);
+
+       /* remaining C bits are unused */
+       memset(tf->c_bits + 6, 1, 9);
+
+       return 0;
+}
+
+static int rtp2trau_data_hr8(struct osmo_trau_frame *tf, const uint8_t *data,
+                            size_t data_len)
+{
+       tf->type = OSMO_TRAU8_DATA;
+
+       /* C1 .. C5: HR data */
+       tf->c_bits[0] = 0;
+       tf->c_bits[1] = 0;
+       tf->c_bits[2] = 1;
+       tf->c_bits[3] = 1;
+       tf->c_bits[4] = 1;
+
+       rtp2trau_data_ir8(tf, data, data_len, 63);
+
+       return 0;
+}
+
 static inline bool check_twts001(struct osmo_trau2rtp_state *st)
 {
        if (st->rtp_extensions & OSMO_RTP_EXT_TWTS001)
@@ -1104,8 +1318,14 @@
                return rtp2trau_efr(tf, rtp, rtp_len);
        case OSMO_TRAU16_FT_HR:
                return rtp2trau_hr16(tf, rtp, rtp_len);
+       case OSMO_TRAU16_FT_DATA:
+               return rtp2trau_data_fr(tf, rtp, rtp_len, st->interm_rate_16k);
+       case OSMO_TRAU16_FT_DATA_HR:
+               return rtp2trau_data_hr16(tf, rtp, rtp_len);
        case OSMO_TRAU8_SPEECH:
                return rtp2trau_hr8(tf, rtp, rtp_len);
+       case OSMO_TRAU8_DATA:
+               return rtp2trau_data_hr8(tf, rtp, rtp_len);
        default:
                return -EINVAL;
        }

--
To view, visit https://gerrit.osmocom.org/c/libosmo-abis/+/38133?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: libosmo-abis
Gerrit-Branch: master
Gerrit-Change-Id: Ifa1a671f3797a22523bef4b5712d91d0131cdef7
Gerrit-Change-Number: 38133
Gerrit-PatchSet: 1
Gerrit-Owner: falconia <[email protected]>

Reply via email to