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