falconia has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmocore/+/32184 )
Change subject: codec: add SID preening functions for FR & EFR
......................................................................
codec: add SID preening functions for FR & EFR
Those network elements which receive a stream of codec frames that
may come from the uplink of GSM call A and which are responsible
for preparing the frame stream for the downlink of GSM call B
(OsmoMGW feeding TRAU-DL, or OsmoBTS receiving RTP and feeding DL
to its PHY) must be prepared for the possibility that their
incoming frame stream may contain corrupted SID frames, presumably
from bit errors on radio link A. Per the rules of section 6.1.1
of GSM 06.31 for FR and GSM 06.81 for EFR, SID frames with just one
errored bit are still to be accepted as valid, whereas frames with
more corrupted bits which are still recognizable as SID are classified
as invalid SID.
In the case of a TrFO call, the entity switching from leg A UL to
leg B DL is responsible for *not* transmitting invalid SID frames
on the destination leg (they should be treated like BFIs), and any
deemed-valid SID frames that are forwarded should be preened,
correcting that one bit error they may exhibit. The functions
added here provide that functionality.
Change-Id: Iec5c1f2619a82499f61cb3e5a7cd03ff0f020ad8
---
M include/osmocom/codec/codec.h
M src/codec/gsm610.c
M src/codec/gsm660.c
3 files changed, 110 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/84/32184/1
diff --git a/include/osmocom/codec/codec.h b/include/osmocom/codec/codec.h
index ac7a8e9..b318e2f 100644
--- a/include/osmocom/codec/codec.h
+++ b/include/osmocom/codec/codec.h
@@ -94,6 +94,8 @@
enum etsi_sid_class osmo_fr_sid_classify(const uint8_t *rtp_payload);
enum etsi_sid_class osmo_efr_sid_classify(const uint8_t *rtp_payload);
+bool osmo_fr_sid_preen(uint8_t *rtp_payload);
+bool osmo_efr_sid_preen(uint8_t *rtp_payload);
int osmo_amr_rtp_enc(uint8_t *payload, uint8_t cmr, enum osmo_amr_type ft,
enum osmo_amr_quality bfi);
diff --git a/src/codec/gsm610.c b/src/codec/gsm610.c
index 81876d6..e3dff17 100644
--- a/src/codec/gsm610.c
+++ b/src/codec/gsm610.c
@@ -388,3 +388,42 @@
else
return ETSI_SID_CLASS_VALID;
}
+
+/*! Preen potentially-SID FR codec frame in RTP format, ensuring that it is
+ * either a speech frame or a valid SID, and if the latter, making it a
+ * perfect, error-free SID frame.
+ * \param[in] rtp_payload Buffer with RTP payload - must be writable!
+ * \returns true if the frame is good, false otherwise
+ */
+bool osmo_fr_sid_preen(uint8_t *rtp_payload)
+{
+ enum etsi_sid_class sidc;
+ uint8_t *p, sub;
+
+ sidc = osmo_fr_sid_classify(rtp_payload);
+ switch (sidc) {
+ case ETSI_SID_CLASS_SPEECH:
+ return true;
+ case ETSI_SID_CLASS_INVALID:
+ return false;
+ case ETSI_SID_CLASS_VALID:
+ /* "Rejuvenate" this SID frame, correcting any errors:
+ * zero out all bits that aren't LARc or Xmaxc, thereby
+ * clearing all SID code word bits and all unused/reserved
+ * bits. */
+ p = rtp_payload + 5; /* skip magic+LARc */
+ for (sub = 0; sub < 4; sub++) {
+ *p++ = 0;
+ *p++ &= 0x1F;
+ *p++ &= 0x80;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ }
+ return true;
+ }
+
+ /* should never be reached */
+ return false;
+}
diff --git a/src/codec/gsm660.c b/src/codec/gsm660.c
index def93d7..67c7731 100644
--- a/src/codec/gsm660.c
+++ b/src/codec/gsm660.c
@@ -350,3 +350,44 @@
else
return ETSI_SID_CLASS_VALID;
}
+
+/*! Preen potentially-SID EFR codec frame in RTP format, ensuring that it is
+ * either a speech frame or a valid SID, and if the latter, making it a
+ * perfect, error-free SID frame.
+ * \param[in] rtp_payload Buffer with RTP payload - must be writable!
+ * \returns true if the frame is good, false otherwise
+ */
+bool osmo_efr_sid_preen(uint8_t *rtp_payload)
+{
+ enum etsi_sid_class sidc;
+
+ sidc = osmo_efr_sid_classify(rtp_payload);
+ switch (sidc) {
+ case ETSI_SID_CLASS_SPEECH:
+ return true;
+ case ETSI_SID_CLASS_INVALID:
+ return false;
+ case ETSI_SID_CLASS_VALID:
+ /* "Rejuvenate" this SID frame, correcting any errors:
+ * set all 95 SID code word bits to 1. */
+ rtp_payload[6] |= 0x6F;
+ rtp_payload[7] = 0xFF;
+ rtp_payload[8] = 0xFF;
+ rtp_payload[9] |= 0x80;
+ rtp_payload[12] |= 0x3B;
+ rtp_payload[13] = 0xFF;
+ rtp_payload[14] = 0xFF;
+ rtp_payload[15] |= 0xE0;
+ rtp_payload[19] = 0xFF;
+ rtp_payload[20] = 0xFF;
+ rtp_payload[21] = 0xFF;
+ rtp_payload[25] = 0xFF;
+ rtp_payload[26] |= 0xFC;
+ rtp_payload[27] = 0xFF;
+ rtp_payload[28] |= 0xC0;
+ return true;
+ }
+
+ /* should never be reached */
+ return false;
+}
--
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/32184
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: Iec5c1f2619a82499f61cb3e5a7cd03ff0f020ad8
Gerrit-Change-Number: 32184
Gerrit-PatchSet: 1
Gerrit-Owner: falconia <falcon(a)freecalypso.org>
Gerrit-MessageType: newchange
falconia has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmocore/+/32183 )
Change subject: codec: add SID classification functions per GSM 06.31 & 06.81
......................................................................
codec: add SID classification functions per GSM 06.31 & 06.81
The existing osmo_{fr,efr}_check_sid() functions detect whether or not
the frame of bits passed to them constitutes an absolutely perfect
SID frame, with each of 95 SID code word bits set to 0 for FR or
1 for EFR. However, the rules of section 6.1.1 in GSM 06.31 & 06.81
allow up to one bit to be in error for the frame to be accepted as
valid SID, and the same rules also call out a third state (invalid SID)
in between valid SID frames and other frames that are classified as
speech. Support for these rules cannot be patched into those familiar
osmo_{fr,efr}_check_sid() functions because doing so would alter
behavior of existing programs, hence new functions need to be added.
The new functions that implement the exact rules of section 6.1.1 of
GSM 06.31 and 06.81 will need to be used if anyone needs to construct
an outgoing TRAU-UL frame (for example, as part of implementing
TS 28.062 TFO), and they are expected to be useful as part of more
sophisticated ECU implementations.
Change-Id: Ie91a52c6f04689082d8004311517d8ce0c544916
---
M include/osmocom/codec/codec.h
M src/codec/gsm610.c
M src/codec/gsm660.c
3 files changed, 174 insertions(+), 26 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/83/32183/1
diff --git a/include/osmocom/codec/codec.h b/include/osmocom/codec/codec.h
index 65de20d..ac7a8e9 100644
--- a/include/osmocom/codec/codec.h
+++ b/include/osmocom/codec/codec.h
@@ -81,9 +81,20 @@
}
}
+/* SID ternary classification per GSM 06.31 & 06.81 section 6.1.1 */
+enum etsi_sid_class {
+ ETSI_SID_CLASS_SPEECH = 0,
+ ETSI_SID_CLASS_INVALID = 1,
+ ETSI_SID_CLASS_VALID = 2,
+};
+
bool osmo_fr_check_sid(const uint8_t *rtp_payload, size_t payload_len);
bool osmo_hr_check_sid(const uint8_t *rtp_payload, size_t payload_len);
bool osmo_efr_check_sid(const uint8_t *rtp_payload, size_t payload_len);
+
+enum etsi_sid_class osmo_fr_sid_classify(const uint8_t *rtp_payload);
+enum etsi_sid_class osmo_efr_sid_classify(const uint8_t *rtp_payload);
+
int osmo_amr_rtp_enc(uint8_t *payload, uint8_t cmr, enum osmo_amr_type ft,
enum osmo_amr_quality bfi);
int osmo_amr_rtp_dec(const uint8_t *payload, int payload_len, uint8_t *cmr,
diff --git a/src/codec/gsm610.c b/src/codec/gsm610.c
index ff9952a..81876d6 100644
--- a/src/codec/gsm610.c
+++ b/src/codec/gsm610.c
@@ -296,6 +296,21 @@
29, /* LARc5:0 */
};
+static const uint16_t sid_code_word_bits[95] = {
+ /* bit numbers are relative to the RTP frame beginning,
+ * with signature bits included in the count. */
+ 57, 58, 60, 61, 63, 64, 66, 67, 69, 70, 72, 73,
+ 75, 76, 78, 79, 81, 82, 84, 85, 87, 88, 90, 91,
+ 93, 94, 113, 114, 116, 117, 119, 120, 122, 123,
+ 125, 126, 128, 129, 131, 132, 134, 135, 137,
+ 138, 140, 141, 143, 144, 146, 147, 149, 150,
+ 169, 170, 172, 173, 175, 176, 178, 179, 181,
+ 182, 184, 185, 187, 188, 190, 191, 193, 194,
+ 196, 197, 199, 200, 202, 203, 205, 206, 225,
+ 226, 228, 229, 231, 232, 234, 235, 237, 240,
+ 243, 246, 249, 252, 255, 258, 261
+};
+
/*! Check whether RTP frame contains FR SID code word according to
* TS 101 318 §5.1.2
* \param[in] rtp_payload Buffer with RTP payload
@@ -305,16 +320,7 @@
bool osmo_fr_check_sid(const uint8_t *rtp_payload, size_t payload_len)
{
struct bitvec bv;
- uint16_t i, z_bits[] = { 57, 58, 60, 61, 63, 64, 66, 67, 69, 70, 72, 73,
- 75, 76, 78, 79, 81, 82, 84, 85, 87, 88, 90, 91,
- 93, 94, 113, 114, 116, 117, 119, 120, 122, 123,
- 125, 126, 128, 129, 131, 132, 134, 135, 137,
- 138, 140, 141, 143, 144, 146, 147, 149, 150,
- 169, 170, 172, 173, 175, 176, 178, 179, 181,
- 182, 184, 185, 187, 188, 190, 191, 193, 194,
- 196, 197, 199, 200, 202, 203, 205, 206, 225,
- 226, 228, 229, 231, 232, 234, 235, 237, 240,
- 243, 246, 249, 252, 255, 258, 261 };
+ uint16_t i;
/* signature does not match Full Rate SID */
if ((rtp_payload[0] >> 4) != 0xD)
@@ -323,10 +329,62 @@
bv.data = (uint8_t *) rtp_payload;
bv.data_len = payload_len;
- /* code word is all 0 at given bits, numbered from 1 */
- for (i = 0; i < ARRAY_SIZE(z_bits); i++)
- if (bitvec_get_bit_pos(&bv, z_bits[i]) != ZERO)
+ /* code word is all 0 at given bits */
+ for (i = 0; i < ARRAY_SIZE(sid_code_word_bits); i++) {
+ if (bitvec_get_bit_pos(&bv, sid_code_word_bits[i]) != ZERO)
return false;
+ }
return true;
}
+
+/*! Classify potentially-SID FR codec frame in RTP format according
+ * to the rules of GSM 06.31 §6.1.1
+ * \param[in] rtp_payload Buffer with RTP payload
+ * \returns enum etsi_sid_class, with symbolic values ETSI_SID_CLASS_SPEECH,
+ * ETSI_SID_CLASS_INVALID or ETSI_SID_CLASS_VALID corresponding
+ * to the 3 possible bit-counting classifications prescribed by the spec.
+ *
+ * Differences between the more familiar osmo_fr_check_sid() and the present
+ * function are:
+ *
+ * 1. osmo_fr_check_sid() returns true only if the SID frame is absolutely
+ * perfect, with all 95 bits of the SID code word zeroed. However, the
+ * rules of GSM 06.31 §6.1.1 allow up to one bit to be in error,
+ * and the frame is still accepted as valid SID.
+ *
+ * 2. The third possible state of invalid SID is not handled at all by the
+ * simpler osmo_fr_check_sid() function.
+ *
+ * 3. osmo_fr_check_sid() includes a check for 0xD RTP signature, and returns
+ * false if that signature nibble is wrong. That check is not included
+ * in the present version because there is no place for it in the
+ * ETSI-prescribed classification, it is neither speech nor SID. The
+ * assumption is that this function is used to classify the bit content
+ * of received codec frames, not their RTP encoding - the latter needs
+ * to be validated beforehand.
+ *
+ * Which function should one use? The answer depends on the specific
+ * circumstances, and needs to be addressed on a case-by-case basis.
+ */
+enum etsi_sid_class osmo_fr_sid_classify(const uint8_t *rtp_payload)
+{
+ struct bitvec bv;
+ uint16_t i, n;
+
+ bv.data = (uint8_t *) rtp_payload;
+ bv.data_len = GSM_FR_BYTES;
+
+ /* count not-SID-matching bits per the spec */
+ n = 0;
+ for (i = 0; i < ARRAY_SIZE(sid_code_word_bits); i++) {
+ if (bitvec_get_bit_pos(&bv, sid_code_word_bits[i]) != ZERO)
+ n++;
+ if (n >= 16)
+ return ETSI_SID_CLASS_SPEECH;
+ }
+ if (n >= 2)
+ return ETSI_SID_CLASS_INVALID;
+ else
+ return ETSI_SID_CLASS_VALID;
+}
diff --git a/src/codec/gsm660.c b/src/codec/gsm660.c
index 46ecdac..def93d7 100644
--- a/src/codec/gsm660.c
+++ b/src/codec/gsm660.c
@@ -258,6 +258,21 @@
246, /* 259 -> PULSE 4_10: b0 */
};
+static const uint8_t sid_code_word_bits[95] = {
+ /* bit numbers are relative to "pure" EFR frame beginning,
+ * not counting the signature bits. */
+ 45, 46, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 94, 95, 96, 98, 99, 100, 101,
+ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 148, 149, 150,
+ 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
+ 161, 162, 163, 164, 165, 166, 167, 168, 169, 170,
+ 171, 196, 197, 198, 199, 200, 201, 202, 203, 204,
+ 205, 206, 207, 208, 209, 212, 213, 214, 215, 216,
+ 217, 218, 219, 220, 221
+};
+
/*! Check whether RTP frame contains EFR SID code word according to
* TS 101 318 §5.3.2
* \param[in] rtp_payload Buffer with RTP payload
@@ -268,19 +283,6 @@
{
struct bitvec bv;
uint16_t i;
- static const uint8_t sid_code_word_bits[95] = {
- /* bit numbers relative to "pure" EFR frame beginning,
- * not counting the signature bits. */
- 45, 46, 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
- 66, 67, 68, 94, 95, 96, 98, 99, 100, 101,
- 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 148, 149, 150,
- 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
- 161, 162, 163, 164, 165, 166, 167, 168, 169, 170,
- 171, 196, 197, 198, 199, 200, 201, 202, 203, 204,
- 205, 206, 207, 208, 209, 212, 213, 214, 215, 216,
- 217, 218, 219, 220, 221 };
/* signature does not match Enhanced Full Rate SID */
if ((rtp_payload[0] >> 4) != 0xC)
@@ -297,3 +299,54 @@
return true;
}
+
+/*! Classify potentially-SID EFR codec frame in RTP format according
+ * to the rules of GSM 06.81 §6.1.1
+ * \param[in] rtp_payload Buffer with RTP payload
+ * \returns enum etsi_sid_class, with symbolic values ETSI_SID_CLASS_SPEECH,
+ * ETSI_SID_CLASS_INVALID or ETSI_SID_CLASS_VALID corresponding
+ * to the 3 possible bit-counting classifications prescribed by the spec.
+ *
+ * Differences between the more familiar osmo_efr_check_sid() and the present
+ * function are:
+ *
+ * 1. osmo_efr_check_sid() returns true only if the SID frame is absolutely
+ * perfect, with all 95 bits of the SID code word set. However, the
+ * rules of GSM 06.81 §6.1.1 allow up to one bit to be in error,
+ * and the frame is still accepted as valid SID.
+ *
+ * 2. The third possible state of invalid SID is not handled at all by the
+ * simpler osmo_efr_check_sid() function.
+ *
+ * 3. osmo_efr_check_sid() includes a check for 0xC RTP signature, and returns
+ * false if that signature nibble is wrong. That check is not included
+ * in the present version because there is no place for it in the
+ * ETSI-prescribed classification, it is neither speech nor SID. The
+ * assumption is that this function is used to classify the bit content
+ * of received codec frames, not their RTP encoding - the latter needs
+ * to be validated beforehand.
+ *
+ * Which function should one use? The answer depends on the specific
+ * circumstances, and needs to be addressed on a case-by-case basis.
+ */
+enum etsi_sid_class osmo_efr_sid_classify(const uint8_t *rtp_payload)
+{
+ struct bitvec bv;
+ uint16_t i, n;
+
+ bv.data = (uint8_t *) rtp_payload;
+ bv.data_len = GSM_EFR_BYTES;
+
+ /* count not-SID-matching bits per the spec */
+ n = 0;
+ for (i = 0; i < ARRAY_SIZE(sid_code_word_bits); i++) {
+ if (bitvec_get_bit_pos(&bv, sid_code_word_bits[i]+4) != ONE)
+ n++;
+ if (n >= 16)
+ return ETSI_SID_CLASS_SPEECH;
+ }
+ if (n >= 2)
+ return ETSI_SID_CLASS_INVALID;
+ else
+ return ETSI_SID_CLASS_VALID;
+}
--
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/32183
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: Ie91a52c6f04689082d8004311517d8ce0c544916
Gerrit-Change-Number: 32183
Gerrit-PatchSet: 1
Gerrit-Owner: falconia <falcon(a)freecalypso.org>
Gerrit-MessageType: newchange