falconia has uploaded this change for review.
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 change 37156. To unsubscribe, or for help writing mail filters, visit settings.