falconia has submitted this change. (
https://gerrit.osmocom.org/c/libosmo-abis/+/39622?usp=email )
Change subject: rtp2trau HR: add support for TRAU-8k-UL frame output
......................................................................
rtp2trau HR: add support for TRAU-8k-UL frame output
When osmo_rtp2trau() function is used to pass traffic to an E1 BTS,
it only needs to generate TRAU-DL frames, not TRAU-UL. OTOH,
ability to generate TRAU-UL frames is needed for TFO, i.e., for
software implementation of TFO-capable speech transcoders.
osmo_rtp2trau() already supports TRAU-UL frame output for FR and
EFR codecs, but not for HR codec in TRAU-8k framing - add the
missing support. (Out of the two possible TRAU frame formats for
GSM-HR codec, TFO always uses TRAU-8k format.)
Change-Id: I288cfa7d467125f7732ef1d0ef83b933e41da536
---
M src/trau/trau_rtp_conv.c
M tests/Makefile.am
M tests/testsuite.at
A tests/trau_conv/hr_speech_invsid_bits.hex
A tests/trau_conv/hr_speech_twts002.hex
A tests/trau_conv/rtp2trau_hr_ul1.ok
A tests/trau_conv/rtp2trau_hr_ul2.ok
A tests/trau_conv/rtp2trau_hr_ul3.ok
8 files changed, 241 insertions(+), 11 deletions(-)
Approvals:
laforge: Looks good to me, but someone else must approve
falconia: Looks good to me, approved
pespin: Looks good to me, but someone else must approve
Jenkins Builder: Verified
diff --git a/src/trau/trau_rtp_conv.c b/src/trau/trau_rtp_conv.c
index 328221e..d5ac1fa 100644
--- a/src/trau/trau_rtp_conv.c
+++ b/src/trau/trau_rtp_conv.c
@@ -756,7 +756,7 @@
return 0;
}
-static int rtp2trau_hr8(struct osmo_trau_frame *tf, const uint8_t *data, size_t
data_len)
+static int rtp2trau_hr8_dl(struct osmo_trau_frame *tf, const uint8_t *data, size_t
data_len)
{
/* accept both TS 101 318 and RFC 5993 payloads */
switch (data_len) {
@@ -773,12 +773,6 @@
return -EINVAL;
}
- /* FIXME: implement TRAU-UL frame generation if and when
- * someone actually needs it in a program that uses
- * this library. */
- if (tf->dir != OSMO_TRAU_DIR_DL)
- return -ENOTSUP;
-
tf->type = OSMO_TRAU8_SPEECH;
/* C1..C5 */
@@ -819,6 +813,130 @@
return 0;
}
+/* compute the odd parity bit of the given input bit sequence */
+static ubit_t compute_odd_parity(const ubit_t *in, unsigned int num_bits)
+{
+ int i;
+ unsigned int sum = 0;
+
+ for (i = 0; i < num_bits; i++) {
+ if (in[i])
+ sum++;
+ }
+ return !(sum & 1);
+}
+
+static int rtp2trau_hr8_ul(struct osmo_trau_frame *tf, const uint8_t *data, size_t
data_len)
+{
+ uint8_t ft, xc1_4;
+ bool data_bits_req, have_taf;
+
+ /* In TRAU-UL direction we require/expect TW-TS-002 RTP payload format;
+ * RFC 5993 is also accepted because it is a subset of TW-TS-002.
+ * TS 101 318 input is not supported for TRAU-UL output! */
+ if (data_len < 1)
+ return -EINVAL;
+ ft = data[0] >> 4;
+ switch (ft) {
+ case FT_GOOD_SPEECH:
+ xc1_4 = 0;
+ data_bits_req = true;
+ have_taf = false;
+ break;
+ case FT_INVALID_SID:
+ xc1_4 = 4;
+ data_bits_req = false;
+ have_taf = true;
+ break;
+ case FT_GOOD_SID:
+ xc1_4 = 1;
+ data_bits_req = true;
+ have_taf = false;
+ break;
+ case FT_BFI_WITH_DATA:
+ xc1_4 = 6;
+ data_bits_req = true;
+ have_taf = true;
+ break;
+ case FT_NO_DATA:
+ xc1_4 = 6;
+ data_bits_req = false;
+ have_taf = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* If the frame type is one that includes data bits, the payload length
+ * per RFC 5993 and TW-TS-002 is 15 bytes. If the frame type is one
+ * that does not include data bits, then the payload length per the
+ * same specs is only 1 byte - but we also accept 15-byte payloads
+ * in this case to make life easier for applications that pass the
+ * content of a buffer.
+ *
+ * When we make a TRAU-UL frame from FT=1 or FT=7, we fill all Dn bits
+ * with zeros if we got a short (1 byte) payload. However, if the
+ * application passed us a long (15 byte) payload despite FT being
+ * 1 or 7, we fill Dn bits with application-provided payload.
+ */
+ switch (data_len) {
+ case GSM_HR_BYTES_RTP_RFC5993:
+ break;
+ case 1:
+ if (data_bits_req)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tf->type = OSMO_TRAU8_SPEECH;
+
+ /* C1..C5 */
+ tf->c_bits[0] = 0;
+ tf->c_bits[1] = 0;
+ tf->c_bits[2] = 0;
+ tf->c_bits[3] = 1;
+ tf->c_bits[4] = 0;
+ /* C6..C8: spare bits */
+ memset(tf->c_bits + 5, 1, 3);
+ /* C9 is DTXd */
+ tf->c_bits[8] = (data[0] & 0x08) >> 3;
+
+ /* XC1..XC6 */
+ tf->xc_bits[0] = (xc1_4 >> 3) & 1;
+ tf->xc_bits[1] = (xc1_4 >> 2) & 1;
+ tf->xc_bits[2] = (xc1_4 >> 1) & 1;
+ if (have_taf)
+ tf->xc_bits[3] = (data[0] & 0x01) >> 0;
+ else
+ tf->xc_bits[3] = (xc1_4 >> 0) & 1;
+ tf->xc_bits[4] = (data[0] & 0x02) >> 1; /* UFI */
+ tf->xc_bits[5] = compute_odd_parity(tf->xc_bits, 5);
+
+ memset(&tf->t_bits[0], 1, 2);
+
+ if (data_len > 1)
+ osmo_pbit2ubit(tf->d_bits, data + 1, GSM_HR_BYTES * 8);
+ else
+ memset(tf->d_bits, 0, GSM_HR_BYTES * 8);
+ /* CRC is *not* computed by TRAU frame encoder - we have to do it */
+ osmo_crc8gen_set_bits(&gsm0860_efr_crc3, tf->d_bits, 44, tf->crc_bits);
+
+ return 0;
+}
+
+static int rtp2trau_hr8(struct osmo_trau_frame *tf, const uint8_t *data, size_t
data_len)
+{
+ switch (tf->dir) {
+ case OSMO_TRAU_DIR_DL:
+ return rtp2trau_hr8_dl(tf, data, data_len);
+ case OSMO_TRAU_DIR_UL:
+ return rtp2trau_hr8_ul(tf, data, data_len);
+ default:
+ return -EINVAL;
+ }
+}
+
/* TS 48.060 Section 5.5.1.1.2 */
static int rtp2trau_efr(struct osmo_trau_frame *tf, const uint8_t *data, size_t
data_len)
{
@@ -1571,9 +1689,9 @@
* TRAU-UL (TFO) is TW-TS-001 - the basic RTP format of TS 101 318 or
* RFC 3551 lacks the necessary metadata flags.
*
- * - TRAU-UL output for HR codec is not currently implemented; when we do
- * implement it in the future, TW-TS-002 will be required in this path
- * for the same reason as above.
+ * - For HRv1 codec, for the same reason as above, the only correct RTP
+ * format for conversion to TRAU-UL is TW-TS-002. RFC 5993 payloads are
+ * also accepted (because it is a subset of TW-TS-002), but not TS 101 318.
*
* - TRAU-UL output for CSD 14.4 kbit/s mode is not currently implemented
* (C-bits are always set according to the rules for TRAU-DL) - but the
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4645b7e..73341a2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -99,13 +99,15 @@
trau_conv/fr_speech_basic.hex trau_conv/fr_speech_twts001_good.hex \
trau_conv/fr_speech_twts001_mix.hex \
trau_conv/hr_speech_rfc5993.hex trau_conv/hr_speech_ts101318.hex \
+ trau_conv/hr_speech_twts002.hex trau_conv/hr_speech_invsid_bits.hex \
trau_conv/rtp2trau_efr_dl1.ok trau_conv/rtp2trau_efr_dl2.ok \
trau_conv/rtp2trau_efr_ul1.ok trau_conv/rtp2trau_efr_ul2.ok \
trau_conv/rtp2trau_efr_ul3.ok \
trau_conv/rtp2trau_fr_dl1.ok trau_conv/rtp2trau_fr_dl2.ok \
trau_conv/rtp2trau_fr_ul1.ok trau_conv/rtp2trau_fr_ul2.ok \
trau_conv/rtp2trau_fr_ul3.ok \
- trau_conv/rtp2trau_hr_dl.ok \
+ trau_conv/rtp2trau_hr_dl.ok trau_conv/rtp2trau_hr_ul1.ok \
+ trau_conv/rtp2trau_hr_ul2.ok trau_conv/rtp2trau_hr_ul3.ok \
trau_conv/trau16_efr.in trau_conv/trau16_efr_std.ok \
trau_conv/trau16_efr_twts001.ok \
trau_conv/trau16_fr.in trau_conv/trau16_fr_std.ok \
diff --git a/tests/testsuite.at b/tests/testsuite.at
index a5cf070..b3c2764 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -162,3 +162,21 @@
cat $abs_srcdir/trau_conv/rtp2trau_hr_dl.ok > expout
AT_CHECK([$abs_top_builddir/tests/trau_conv/rtp2trau_gen
$abs_srcdir/trau_conv/hr_speech_rfc5993.hex hr dl], [0], [expout], [ignore])
AT_CLEANUP
+
+AT_SETUP([rtp2trau_hr_ul1])
+AT_KEYWORDS([rtp2trau_hr_ul1])
+cat $abs_srcdir/trau_conv/rtp2trau_hr_ul1.ok > expout
+AT_CHECK([$abs_top_builddir/tests/trau_conv/rtp2trau_gen
$abs_srcdir/trau_conv/hr_speech_rfc5993.hex hr ul], [0], [expout], [ignore])
+AT_CLEANUP
+
+AT_SETUP([rtp2trau_hr_ul2])
+AT_KEYWORDS([rtp2trau_hr_ul2])
+cat $abs_srcdir/trau_conv/rtp2trau_hr_ul2.ok > expout
+AT_CHECK([$abs_top_builddir/tests/trau_conv/rtp2trau_gen
$abs_srcdir/trau_conv/hr_speech_twts002.hex hr ul], [0], [expout], [ignore])
+AT_CLEANUP
+
+AT_SETUP([rtp2trau_hr_ul3])
+AT_KEYWORDS([rtp2trau_hr_ul3])
+cat $abs_srcdir/trau_conv/rtp2trau_hr_ul3.ok > expout
+AT_CHECK([$abs_top_builddir/tests/trau_conv/rtp2trau_gen
$abs_srcdir/trau_conv/hr_speech_invsid_bits.hex hr ul], [0], [expout], [ignore])
+AT_CLEANUP
diff --git a/tests/trau_conv/hr_speech_invsid_bits.hex
b/tests/trau_conv/hr_speech_invsid_bits.hex
new file mode 100644
index 0000000..3ac5172
--- /dev/null
+++ b/tests/trau_conv/hr_speech_invsid_bits.hex
@@ -0,0 +1,14 @@
+# This TW-TS-005 hex file contains an input to osmo_rtp2trau() for GSM-HR
+# codec that is *not* a valid RTP payload per TW-TS-002: an invalid SID
+# frame for conversion to TRAU-UL that begins as defined in TW-TS-002
+# (FT=1 to signify invalid SID), but then contrary to the spec, does
+# include the payload data bits. Such concoction is not valid in RTP
+# flight between network elements, but osmo_rtp2trau() supports such
+# extended usage in order to allow TFO applications to set the fill bit
+# pattern in the TRAU-UL frame to something other than all zeros.
+#
+# In the present example, this fill bit pattern consists of R0+LPC
+# parameters (33 bits) from a valid SID frame, followed by alternating
+# 1s and 0s in the 79-bit SID field.
+
+1000D9EA65D5555555555555555555
diff --git a/tests/trau_conv/hr_speech_twts002.hex
b/tests/trau_conv/hr_speech_twts002.hex
new file mode 100644
index 0000000..e0e6321
--- /dev/null
+++ b/tests/trau_conv/hr_speech_twts002.hex
@@ -0,0 +1,43 @@
+# This hex file (TW-TS-005 Annex B format) contains some RTP payloads for
+# GSM-HR codec, using the super-5993 RTP payload format of TW-TS-002,
+# semantically corresponding to the uplink direction of a GSM call leg.
+#
+# The present example contains a mix of good and bad frames, the same kind
+# of mix that can be represented in a TRAU-UL frame stream. This example
+# has been constructed by hand: some frames were taken from GSM 06.07 test
+# sequences and then tweaked, other are outright concoctions. The setting
+# of DTXd bit is also exercised.
+
+# good speech frame (DHF)
+000371AF61C8F2802531C000000000
+
+# good speech frame (regular)
+00B77916FC7D902F9372B569F5D17F
+# same with TAF
+01B77916FC7D902F9372B569F5D17F
+# same with UFI
+02B77916FC7D902F9372B569F5D17F
+
+# valid SID frame (first SID from dtx06.cod)
+2000D9EA65FFFFFFFFFFFFFFFFFFFF
+# same with TAF
+2100D9EA65FFFFFFFFFFFFFFFFFFFF
+# same with UFI
+2200D9EA65FFFFFFFFFFFFFFFFFFFF
+
+# BFI with data
+608FE9B77000000000000000000000
+# same with TAF
+618FE9B77000000000000000000000
+
+# short TW-TS-002 payloads (ToC octet only)
+10 # invalid SID frame
+11 # same with TAF
+13 # TAF+UFI
+70 # BFI-no-data
+71 # same with TAF
+
+# some of these same frames with DTXd=1
+08B77916FC7D902F9372B569F5D17F
+2800D9EA65FFFFFFFFFFFFFFFFFFFF
+688FE9B77000000000000000000000
diff --git a/tests/trau_conv/rtp2trau_hr_ul1.ok b/tests/trau_conv/rtp2trau_hr_ul1.ok
new file mode 100644
index 0000000..1fd3f3b
--- /dev/null
+++ b/tests/trau_conv/rtp2trau_hr_ul1.ok
@@ -0,0 +1,17 @@
+00884486f1d7d8b98ff2c089a69c8080808080bb
+00884486f1d7d8b98ff2c089a69c8080808080bb
+0088469fe9dbdc8080d0808080808080808080bb
+0088469fe3eedf90dd9c9dddc7f193a9e5c587bb
+008845fef4fd9ba986ddabfceac589d38ab3febb
+008846bfe3eedab7e4aed7eb88b4a4a4f997ccfb
+008846eef98bbf8fd9a097e4eeababa7ebd1bffb
+00884486f1d7d8b98ff2c089a69c8080808080bb
+00884486f1d7d8b98ff2c089a69c8080808080bb
+00884481d9f599b9c9cce0b8ccb6c099e9f1f6fb
+00884481d9f599b18c9df0b0cdb68099d9f5f6fb
+00884481d9f599b18c9df0b2cdb28099d9f5f6fb
+00884481d9f599b18c9df0b2cdb28099d9f5f6fb
+00884481d9f599b18c9df0b2cdb28099d9f5f6fb
+00884481d9f599b18c9df0b2cdb28099d9f5f6fb
+00884481d9f599b18c9df0b2cdb28099d9f5f6fb
+00885081d9f599bffffffffffffffffffffffffb
diff --git a/tests/trau_conv/rtp2trau_hr_ul2.ok b/tests/trau_conv/rtp2trau_hr_ul2.ok
new file mode 100644
index 0000000..01ba3e4
--- /dev/null
+++ b/tests/trau_conv/rtp2trau_hr_ul2.ok
@@ -0,0 +1,17 @@
+00884486f1d7d8b98ff2c089a69c8080808080bb
+008846eef98bbf8fd9a097e4eeababa7ebd1bffb
+008846eef98bbf8fd9a097e4eeababa7ebd1bffb
+00884aeef98bbf8fd9a097e4eeababa7ebd1bffb
+00885081d9f599bffffffffffffffffffffffffb
+00885081d9f599bffffffffffffffffffffffffb
+00885c81d9f599bffffffffffffffffffffffffb
+0089669fe9dbdc8080d0808080808080808080bb
+0089729fe9dbdc8080d0808080808080808080bb
+008940808080808080f0808080808080808080bb
+008954808080808080f0808080808080808080bb
+008958808080808080f0808080808080808080bb
+008964808080808080f0808080808080808080bb
+008970808080808080f0808080808080808080bb
+008846eef98bbf8fd9a097e4eeababa7ebd1bfff
+00885081d9f599bfffffffffffffffffffffffff
+0089669fe9dbdc8080d0808080808080808080bf
diff --git a/tests/trau_conv/rtp2trau_hr_ul3.ok b/tests/trau_conv/rtp2trau_hr_ul3.ok
new file mode 100644
index 0000000..a6d657c
--- /dev/null
+++ b/tests/trau_conv/rtp2trau_hr_ul3.ok
@@ -0,0 +1 @@
+00894081d9f599bad5a5aad5aad5aad5aad5aafb
--
To view, visit
https://gerrit.osmocom.org/c/libosmo-abis/+/39622?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: libosmo-abis
Gerrit-Branch: master
Gerrit-Change-Id: I288cfa7d467125f7732ef1d0ef83b933e41da536
Gerrit-Change-Number: 39622
Gerrit-PatchSet: 1
Gerrit-Owner: falconia <falcon(a)freecalypso.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: falconia <falcon(a)freecalypso.org>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>