falconia has uploaded this change for review.

View Change

trau2rtp TW-TS-001: handle corner case of BFI with stale SID bits

Many BTS models will emit the previous content of their internal
buffer, perhaps corrupted in some peculiar way, when they need to
emit "BFI with no data" because they received FACCH, or because
they received nothing at all and no channel decoding attempt was
made. This situation is described in detail here:

https://osmocom.org/projects/retro-gsm/wiki/No-data_output

However, when these TRAU-UL BFIs (from Abis or from incoming TFO)
are to be converted to TW-TS-001 with osmo_trau2rtp(), a corner case
arises: if the BTS indicated SID=0 by way of C13 & C14 bits but the
stale payload bit content indicates SID != 0, the full decoder or
TFO transform on the receiving end of the RTP stream will get an
erroneous "invalid SID" indication (instead of "plain" BFI) if the
marked-bad payload is passed through without alteration.

Handle this corner case by modifying marked-bad (BFI=1) payloads
to make them non-SID in the special case when the BTS indicated SID=0,
but the bit pattern says otherwise.

Change-Id: I2800301f7ac25537c4d7fb14acefd73a80590d7c
---
M src/trau/trau_rtp_conv.c
M tests/trau_conv/trau16_efr_twts001.ok
M tests/trau_conv/trau16_fr_twts001.ok
3 files changed, 137 insertions(+), 15 deletions(-)

git pull ssh://gerrit.osmocom.org:29418/libosmo-abis refs/changes/82/38182/1
diff --git a/src/trau/trau_rtp_conv.c b/src/trau/trau_rtp_conv.c
index 1a200c7..24ea70c 100644
--- a/src/trau/trau_rtp_conv.c
+++ b/src/trau/trau_rtp_conv.c
@@ -98,6 +98,36 @@
//static const uint8_t c_bits_check_fr[] = { 0, 0, 0, 1, 0 };
//static const uint8_t c_bits_check_efr[] = { 1, 1, 0, 1, 0 };

+/*
+ * This little helper function modifies a marked-bad (BFI=1) GSM-FR payload
+ * so it would no longer classify as SID by the bit counting rules
+ * of GSM 06.31 section 6.1.1. It is needed at times when a BTS emits
+ * "BFI with no data", out-of-band SID bits (C13 & C14) are set to 0,
+ * but the stale bit pattern in the output buffer used by the BTS
+ * happens to be (usually invalid) SID.
+ *
+ * In order to reliably "break the SID", we need to set 16 bits in the
+ * SID field to values opposite of SID codeword, i.e., to 1 for GSM-FR.
+ * The SID field of GSM-FR includes the msb of every xMc pulse, and also
+ * the middle bit of most (but not all) xMc pulses. The pulses whose
+ * middle bit is not part of the SID field are the last 9 pulses of
+ * the last subframe. For simplicity, we produce the desired effect
+ * by setting the middle bit of pulses 0, 1, 2 and 3 in every subframe,
+ * for a total of 16 bits.
+ */
+static void make_fr_bfi_nonsid(uint8_t *fr_bytes)
+{
+ uint8_t *subf_bytes;
+ unsigned subn;
+
+ subf_bytes = fr_bytes + 5; /* skip signature and LARc bits */
+ for (subn = 0; subn < 4; subn++) {
+ subf_bytes[2] |= 0x24;
+ subf_bytes[3] |= 0x90;
+ subf_bytes += 7;
+ }
+}
+
/*! Generate the 33 bytes RTP payload for GSM-FR from a decoded TRAU frame.
* \param[out] out caller-provided output buffer
* \param[in] out_len length of out buffer in bytes
@@ -153,6 +183,36 @@
j++;
}

+ /*
+ * Many BTS models will emit the previous content of their internal
+ * buffer, perhaps corrupted in some peculiar way, when they need to
+ * emit "BFI with no data" because they received FACCH, or because
+ * they received nothing at all and no channel decoding attempt was
+ * made. When this situation occurs, the Rx DTX handler in the TRAU
+ * needs to be told "this is a regular BFI, not an invalid SID",
+ * and the BTS makes this indication by setting C12=1 (BFI),
+ * C13=0 and C14=0 (SID=0). However, the stale or corrupted frame
+ * payload bit content in the Abis output buffer will still sometimes
+ * indicate SID (usually invalid) by the bit counting rules of
+ * GSM 06.31 section 6.1.1! This situation creates a problem
+ * in the case of TW-TS-001 output: there are no out-of-band bits
+ * for C13 & C14, and when the remote transcoder or TFO transform
+ * calls osmo_fr_sid_classify() or its libgsmfr2 equivalent,
+ * it will detect an invalid SID (always invalid due to BFI=1)
+ * instead of intended-by-BTS "regular BFI". Solution: because
+ * there is no need to preserve all payload bits that are known
+ * to be bad or dummy, we can afford to corrupt some of them;
+ * as a workaround for the unintentional-SID problem, we "break"
+ * the SID field.
+ *
+ * Note that BFI=1 is a required condition for the logic below.
+ * Because standard RFC 3551 output does not support BFI,
+ * this logic applies only to TW-TS-001 output.
+ */
+ if (tf->c_bits[11] && !tf->c_bits[12] && !tf->c_bits[13] &&
+ osmo_fr_is_any_sid(out))
+ make_fr_bfi_nonsid(out);
+
return req_out_len;
}

@@ -356,6 +416,38 @@
}
}

+/*
+ * This little helper function modifies a marked-bad (BFI=1) GSM-EFR payload
+ * so it would no longer classify as SID by the bit counting rules
+ * of GSM 06.81 section 6.1.1. It is needed at times when a BTS emits
+ * "BFI with no data", out-of-band SID bits (C13 & C14) are set to 0,
+ * but the stale bit pattern in the output buffer used by the BTS
+ * happens to be (usually invalid) SID.
+ *
+ * In order to reliably "break the SID", we need to set 16 bits in the
+ * SID field to values opposite of SID codeword, i.e., to 0 for GSM-EFR.
+ * The SID field of GSM-EFR includes (in every subframe) some bits in
+ * LTP lag and LTP gain fields, and many bits in the fixed codebook
+ * excitation pulses portion. The reference decoder from ETSI makes use
+ * of the fixed codebook portion even in marked-bad frames, hence
+ * we prefer not to corrupt this portion - but we can still reliably
+ * break the SID by clearing some bits in LTP lag and gain fields.
+ * Let's clear the two lsbs of each LTP lag and LTP gain field,
+ * giving us the needed total of 16 bits.
+ */
+static void make_efr_bfi_nonsid(uint8_t *efr_bytes)
+{
+ /* subframe 0 */
+ efr_bytes[6] &= 0x99;
+ /* subframe 1 */
+ efr_bytes[12] &= 0xE6;
+ efr_bytes[13] &= 0x7F;
+ /* subframe 2 */
+ efr_bytes[19] &= 0x33;
+ /* subframe 3 */
+ efr_bytes[25] &= 0xCC;
+}
+
/*! Generate the 31 bytes RTP payload for GSM-EFR from a decoded TRAU frame.
* \param[out] out caller-provided output buffer
* \param[in] out_len length of out buffer in bytes
@@ -430,6 +522,36 @@
if (rc)
goto bad_frame;

+ /*
+ * Many BTS models will emit the previous content of their internal
+ * buffer, perhaps corrupted in some peculiar way, when they need to
+ * emit "BFI with no data" because they received FACCH, or because
+ * they received nothing at all and no channel decoding attempt was
+ * made. When this situation occurs, the Rx DTX handler in the TRAU
+ * needs to be told "this is a regular BFI, not an invalid SID",
+ * and the BTS makes this indication by setting C12=1 (BFI),
+ * C13=0 and C14=0 (SID=0). However, the stale or corrupted frame
+ * payload bit content in the Abis output buffer will still sometimes
+ * indicate SID (usually invalid) by the bit counting rules of
+ * GSM 06.81 section 6.1.1! This situation creates a problem
+ * in the case of TW-TS-001 output: there are no out-of-band bits
+ * for C13 & C14, and when the remote transcoder or TFO transform
+ * calls osmo_efr_sid_classify() or its libgsmefr equivalent,
+ * it will detect an invalid SID (always invalid due to BFI=1)
+ * instead of intended-by-BTS "regular BFI". Solution: because
+ * there is no need to preserve all payload bits that are known
+ * to be bad or dummy, we can afford to corrupt some of them;
+ * as a workaround for the unintentional-SID problem, we "break"
+ * the SID field.
+ *
+ * Note that BFI=1 is a required condition for the logic below.
+ * Because standard RFC 3551 output does not support BFI,
+ * this logic applies only to TW-TS-001 output.
+ */
+ if (tf->c_bits[11] && !tf->c_bits[12] && !tf->c_bits[13] &&
+ osmo_efr_is_any_sid(out))
+ make_efr_bfi_nonsid(out);
+
return req_out_len;

bad_frame:
diff --git a/tests/trau_conv/trau16_efr_twts001.ok b/tests/trau_conv/trau16_efr_twts001.ok
index 14dfe9d..761f03b 100644
--- a/tests/trau_conv/trau16_efr_twts001.ok
+++ b/tests/trau_conv/trau16_efr_twts001.ok
@@ -173,11 +173,11 @@
TW-TS-001 TEH octet: 0xE2
EFR frame:
LPC 15 202 265 142 28
- 339 0 15 15 15 15 12 2 2 2 2 4 19
- 60 15 15 15 15 15 12 4 5 5 0 0 19
- 144 10 7 15 15 15 14 0 0 1 0 0 19
- 63 15 15 12 15 15 12 0 2 2 2 0 19
- SID recompute: 1
+ 336 0 15 15 15 15 12 2 2 2 2 4 19
+ 60 12 15 15 15 15 12 4 5 5 0 0 19
+ 144 8 7 15 15 15 14 0 0 1 0 0 19
+ 60 12 15 12 15 15 12 0 2 2 2 0 19
+ SID recompute: 0
ID efr-dtx-dtmf.bin frame 0x53a51
0000ebead10eba68ada886f7fbfca494ca8cfffffe4ba04ac07ffffff0048491fffcffe0a485c2ff
TRAU frame type: EFR
@@ -197,8 +197,8 @@
TW-TS-001 TEH octet: 0xE2
EFR frame:
LPC 30 10 408 138 54
- 339 0 11 15 11 15 12 2 2 2 2 4 18
- 61 7 15 15 15 15 12 4 5 5 0 0 18
- 16 10 7 15 15 15 14 0 0 1 0 0 18
- 63 15 15 12 15 15 12 0 2 2 2 0 22
- SID recompute: 1
+ 336 0 11 15 11 15 12 2 2 2 2 4 18
+ 60 4 15 15 15 15 12 4 5 5 0 0 18
+ 16 8 7 15 15 15 14 0 0 1 0 0 18
+ 60 12 15 12 15 15 12 0 2 2 2 0 22
+ SID recompute: 0
diff --git a/tests/trau_conv/trau16_fr_twts001.ok b/tests/trau_conv/trau16_fr_twts001.ok
index a26439b..5cef573 100644
--- a/tests/trau_conv/trau16_fr_twts001.ok
+++ b/tests/trau_conv/trau16_fr_twts001.ok
@@ -149,8 +149,8 @@
TW-TS-001 TEH octet: 0xE2
FR frame:
LARc 59 36 12 24 13 4 3 0
- 64 1 0 49 3 2 1 0 0 0 0 0 0 0 0 0 0
- 96 3 0 34 0 1 7 3 1 0 0 0 0 0 0 0 0
- 64 1 1 10 0 0 0 0 1 1 1 0 0 0 0 0 0
- 0 0 0 33 5 1 1 0 0 0 0 1 0 0 0 2 2
- SID recompute: 1
+ 64 1 0 49 3 2 3 2 0 0 0 0 0 0 0 0 0
+ 96 3 0 34 2 3 7 3 1 0 0 0 0 0 0 0 0
+ 64 1 1 10 2 2 2 2 1 1 1 0 0 0 0 0 0
+ 0 0 0 33 7 3 3 2 0 0 0 1 0 0 0 2 2
+ SID recompute: 0

To view, visit change 38182. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: newchange
Gerrit-Project: libosmo-abis
Gerrit-Branch: master
Gerrit-Change-Id: I2800301f7ac25537c4d7fb14acefd73a80590d7c
Gerrit-Change-Number: 38182
Gerrit-PatchSet: 1
Gerrit-Owner: falconia <falcon@freecalypso.org>