falconia has uploaded this change for review. ( 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. Depends: I0eccfe5ddcf44f8f20440acb01e2d4870ec0cd91 (libosmocore) Related: OS#6448 Change-Id: I7a6d13d406484c01210594bb6d2f0aff7c1341ab --- M include/osmocom/trau/trau_rtp.h M src/trau/trau_rtp_conv.c 2 files changed, 136 insertions(+), 35 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmo-abis refs/changes/56/37156/1 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 e4aa885..d92cc0d 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; + uint8_t hdr_byte; 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) { + hdr_byte = 0xE0; + 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 (out_len < GSM_FR_BYTES) - return -ENOSPC; + 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,37 @@ * \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 hdr_byte; + bool crc_bfi = false; + + 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) { + hdr_byte = 0xE0; + 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; - 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++) @@ -229,39 +288,40 @@ rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 26, tf->d_bits + 39); if (rc) - goto bad_frame; + crc_bfi = true; for (i = 42, j = 42; i < 95; i++, j++) out[j/8] |= (tf->d_bits[i] << (7-(j%8))); efr_parity_bits_2(check_bits, tf->d_bits); rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12, tf->d_bits + 95); if (rc) - goto bad_frame; + crc_bfi = true; for (i = 98, j = 95; i < 148; i++, j++) out[j/8] |= (tf->d_bits[i] << (7-(j%8))); efr_parity_bits_3(check_bits, tf->d_bits); rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8, tf->d_bits + 148); if (rc) - goto bad_frame; + crc_bfi = true; for (i = 151, j = 145; i < 204; i++, j++) out[j/8] |= (tf->d_bits[i] << (7-(j%8))); efr_parity_bits_4(check_bits, tf->d_bits); rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12, tf->d_bits + 204); if (rc) - goto bad_frame; + crc_bfi = true; for (i = 207, j = 198; i < 257; i++, j++) out[j/8] |= (tf->d_bits[i] << (7-(j%8))); efr_parity_bits_5(check_bits, tf->d_bits); rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8, tf->d_bits + 257); if (rc) - goto bad_frame; + crc_bfi = true; - return GSM_EFR_BYTES; -bad_frame: - return 0; + if (crc_bfi && !emit_twts001) + return 0; + + return req_out_len; } /* TS 48.060 Section 5.5.1.1.2 */ @@ -721,16 +781,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; } -- To view, visit https://gerrit.osmocom.org/c/libosmo-abis/+/37156?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: libosmo-abis Gerrit-Branch: master Gerrit-Change-Id: I7a6d13d406484c01210594bb6d2f0aff7c1341ab Gerrit-Change-Number: 37156 Gerrit-PatchSet: 1 Gerrit-Owner: falconia <fal...@freecalypso.org> Gerrit-MessageType: newchange