falconia has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-abis/+/37156?usp=email )
Change subject: TRAU->RTP: add support for TW-TS-001 & TW-TS-002 ......................................................................
TRAU->RTP: add support for TW-TS-001 & TW-TS-002
The industry standard RTP payload formats of RFC 3551 and RFC 5993 drop valuable metadata from TRAU-UL frames of GSM 08.60 & 08.61, and disallow transport of marked-bad frames. Enhanced RTP transport formats of TW-TS-001 (FR & EFR) and TW-TS-002 (HR) restore these capabilities - however, because these formats are non-standard outside of Osmocom+Themyscira GSM networks, their use can only be optional.
Add rtp_extensions member to struct osmo_trau2rtp_state, specifying the mask of RTP extensions to be used, just like we defined for AoIP BSSMAP and Abis-IP RSL, and extend osmo_trau2rtp() to emit these enhanced RTP formats when they are enabled.
Related: OS#6448 Depends: I0eccfe5ddcf44f8f20440acb01e2d4870ec0cd91 (libosmocore) Change-Id: I7a6d13d406484c01210594bb6d2f0aff7c1341ab --- M TODO-RELEASE M include/osmocom/trau/trau_rtp.h M src/trau/trau_rtp_conv.c 3 files changed, 135 insertions(+), 29 deletions(-)
Approvals: fixeria: Looks good to me, but someone else must approve pespin: Looks good to me, approved Jenkins Builder: Verified
diff --git a/TODO-RELEASE b/TODO-RELEASE index d0852fc..e3ad20a 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -7,3 +7,5 @@ # 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) +libosmogsm >1.9.0 rtp_extensions.h new header diff --git a/include/osmocom/trau/trau_rtp.h b/include/osmocom/trau/trau_rtp.h index f02d43e..6b2110f 100644 --- a/include/osmocom/trau/trau_rtp.h +++ b/include/osmocom/trau/trau_rtp.h @@ -24,6 +24,7 @@
struct osmo_trau2rtp_state { enum osmo_trau_frame_type type; + uint8_t rtp_extensions; };
diff --git a/src/trau/trau_rtp_conv.c b/src/trau/trau_rtp_conv.c index b8f554c..d3d1cae 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/gsm/rtp_extensions.h>
#include <osmocom/trau/trau_frame.h> #include <osmocom/trau/trau_rtp.h> @@ -100,20 +101,34 @@ * \param[in] out_len length of out buffer in bytes * \param[in] fr input TRAU frame in decoded form * \returns number of bytes generated in 'out'; negative on error. */ -static int trau2rtp_fr(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf) +static int trau2rtp_fr(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf, bool emit_twts001) { + size_t req_out_len = emit_twts001 ? GSM_FR_BYTES+1 : GSM_FR_BYTES; int i, j, k, l, o;
if (tf->type != OSMO_TRAU16_FT_FR) return -EINVAL;
+ if (out_len < req_out_len) + return -ENOSPC; + /* FR Data Bits according to TS 48.060 Section 5.5.1.1.2 */
- if (tf->c_bits[11]) /* BFI */ - return 0; + /* Are we emitting TW-TS-001? If so, emit TRAU-like Extension Header */ + if (emit_twts001) { + uint8_t hdr_byte = 0xE0;
- if (out_len < GSM_FR_BYTES) - return -ENOSPC; + if (tf->c_bits[16]) /* DTXd */ + hdr_byte |= 0x08; + if (tf->c_bits[11]) /* BFI */ + hdr_byte |= 0x02; + if (tf->c_bits[14]) /* TAF */ + hdr_byte |= 0x01; + *out++ = hdr_byte; + } + + if (tf->c_bits[11] && !emit_twts001) /* BFI without TW-TS-001 */ + return 0;
out[0] = 0xd << 4; /* reassemble d-bits */ @@ -135,18 +150,30 @@ j++; }
- return GSM_FR_BYTES; + return req_out_len; }
-/* See Section 5.2 of RFC5993 */ -enum rtp_hr_ietf_ft { - FT_GOOD_SPEECH = 0, - FT_GOOD_SID = 2, - FT_NO_DATA = 7, +/* See Section 5.2 of RFC5993 and TW-TS-002 */ +enum super5993_ft { + FT_GOOD_SPEECH = 0, + FT_INVALID_SID = 1, + FT_GOOD_SID = 2, + FT_BFI_WITH_DATA = 6, + FT_NO_DATA = 7, };
static const uint8_t rtp_hr_sid[14] = { 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+static void twtw002_hr16_set_extra_flags(uint8_t *out, const struct osmo_trau_frame *tf) +{ + if (tf->c_bits[16]) /* DTXd */ + out[0] |= 0x08; + if (tf->ufi) /* UFI */ + out[0] |= 0x02; + if (tf->c_bits[14]) /* TAF */ + out[0] |= 0x01; +} + /*! Generate an RFC 5993 RTP payload for HR from a decoded 16k TRAU frame. * We previously emitted TS 101 318 format; however, RFC 5993 is the format * specified in TS 48.103 for AoIP, it can also be extended with TRAU-UL-like @@ -156,7 +183,7 @@ * \param[in] out_len length of out buffer in bytes * \param[in] tf input TRAU frame in decoded form * \returns number of bytes generated in 'out'; negative on error. */ -static int trau2rtp_hr16(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf) +static int trau2rtp_hr16(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf, bool emit_twts002) { enum osmo_gsm631_sid_class sidc;
@@ -175,26 +202,46 @@
/* Plain RFC 5993 without TW-TS-002 extensions does not allow * BFI or invalid SID packets. */ - if (tf->c_bits[11] || sidc == OSMO_GSM631_SID_CLASS_INVALID) + if (!emit_twts002 && + (tf->c_bits[11] || sidc == OSMO_GSM631_SID_CLASS_INVALID)) goto bad_frame;
+ /* BFI turns valid SID into invalid */ + if (tf->c_bits[11] && sidc == OSMO_GSM631_SID_CLASS_VALID) + sidc = OSMO_GSM631_SID_CLASS_INVALID; + /* RFC 5993 Frame Type is equal to GSM 06.41 SID classification, - * restricted to just speech or valid SID per above. */ + * restricted to just speech or valid SID per above. Or if we + * emit TW-TS-002, that restriction is lifted. */ out[0] = sidc << 4;
+ if (emit_twts002) { + if (tf->c_bits[11] && sidc == OSMO_GSM631_SID_CLASS_SPEECH) + out[0] = FT_BFI_WITH_DATA << 4; + twtw002_hr16_set_extra_flags(out, tf); + /* invalid SID frames are truncated in TW-TS-002 */ + if (sidc == OSMO_GSM631_SID_CLASS_INVALID) + return 1; + } + /* TS 101 318 Section 5.2: The order of occurrence of the codec parameters in the buffer is * the same as order of occurrence over the Abis as defined in annex B of ETS 300 969 * [which is 3GPP TS 46.020 */ osmo_ubit2pbit(out + 1, tf->d_bits, 112);
/* RFC 5993 requires SID frames to be perfect, error-free */ - if (sidc == OSMO_GSM631_SID_CLASS_VALID) + if (!emit_twts002 && sidc == OSMO_GSM631_SID_CLASS_VALID) osmo_hr_sid_reset(out + 1);
return GSM_HR_BYTES_RTP_RFC5993;
bad_frame: - return 0; + if (emit_twts002) { + out[0] = FT_NO_DATA << 4; + twtw002_hr16_set_extra_flags(out, tf); + return 1; + } else + return 0; }
/*! Generate the 31 bytes RTP payload for GSM-EFR from a decoded TRAU frame. @@ -202,25 +249,36 @@ * \param[in] out_len length of out buffer in bytes * \param[in] fr input TRAU frame in decoded form * \returns number of bytes generated in 'out'; negative on error. */ -static int trau2rtp_efr(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf) +static int trau2rtp_efr(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf, bool emit_twts001) { + size_t req_out_len = emit_twts001 ? GSM_EFR_BYTES+1 : GSM_EFR_BYTES; int i, j, rc; ubit_t check_bits[26]; + uint8_t *twts001_hdr; + + if (out_len < req_out_len) + return -ENOSPC;
if (tf->type != OSMO_TRAU16_FT_EFR) return -EINVAL;
/* FR Data Bits according to TS 48.060 Section 5.5.1.1.2 */
- if (tf->c_bits[11]) /* BFI */ + /* Are we emitting TW-TS-001? If so, emit TRAU-like Extension Header */ + if (emit_twts001) { + twts001_hdr = out++; + *twts001_hdr = 0xE0; + if (tf->c_bits[16]) /* DTXd */ + *twts001_hdr |= 0x08; + if (tf->c_bits[11]) /* BFI */ + *twts001_hdr |= 0x02; + if (tf->c_bits[14]) /* TAF */ + *twts001_hdr |= 0x01; + } + + if (tf->c_bits[11] && !emit_twts001) /* BFI without TW-TS-001 */ return 0;
- if (out_len < GSM_EFR_BYTES) - return -ENOSPC; - - if (tf->c_bits[11]) /* BFI */ - goto bad_frame; - out[0] = 0xc << 4; /* reassemble d-bits */ for (i = 1, j = 4; i < 39; i++, j++) @@ -259,9 +317,14 @@ if (rc) goto bad_frame;
- return GSM_EFR_BYTES; + return req_out_len; + bad_frame: - return 0; + if (emit_twts001) { + *twts001_hdr |= 0x06; /* BFI and No_Data flags */ + return 1; + } else + return 0; }
/* TS 48.060 Section 5.5.1.1.2 */ @@ -722,16 +785,32 @@ } #endif
+static inline bool check_twts001(struct osmo_trau2rtp_state *st) +{ + if (st->rtp_extensions & OSMO_RTP_EXT_TWTS001) + return true; + else + return false; +} + +static inline bool check_twts002(struct osmo_trau2rtp_state *st) +{ + if (st->rtp_extensions & OSMO_RTP_EXT_TWTS002) + return true; + else + return false; +} + int osmo_trau2rtp(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_FR: - return trau2rtp_fr(out, out_len, tf); + return trau2rtp_fr(out, out_len, tf, check_twts001(st)); case OSMO_TRAU16_FT_EFR: - return trau2rtp_efr(out, out_len, tf); + return trau2rtp_efr(out, out_len, tf, check_twts001(st)); case OSMO_TRAU16_FT_HR: - return trau2rtp_hr16(out, out_len, tf); + return trau2rtp_hr16(out, out_len, tf, check_twts002(st)); default: return -EINVAL; }