aboutsummaryrefslogtreecommitdiffstats
path: root/src/codec/gsm610.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/codec/gsm610.c')
-rw-r--r--src/codec/gsm610.c160
1 files changed, 143 insertions, 17 deletions
diff --git a/src/codec/gsm610.c b/src/codec/gsm610.c
index a05eabab..5cc4f148 100644
--- a/src/codec/gsm610.c
+++ b/src/codec/gsm610.c
@@ -17,10 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
#include <stdint.h>
@@ -300,6 +296,35 @@ const uint16_t gsm610_bitorder[260] = {
29, /* LARc5:0 */
};
+/*
+ * Table 1 in section 6 of 3GPP TS 46.011 (substitution and muting of lost
+ * frames) specifies a silence frame in the form of GSM 06.10 parameters;
+ * the following const datum is this GSM 06.11 silence frame in GSM-FR
+ * RTP encoding.
+ */
+const uint8_t osmo_gsm611_silence_frame[GSM_FR_BYTES] = {
+ 0xDA, 0xA7, 0xAA, 0xA5, 0x1A,
+ 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B,
+ 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B,
+ 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B,
+ 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B,
+};
+
+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
@@ -309,16 +334,7 @@ const uint16_t gsm610_bitorder[260] = {
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)
@@ -327,10 +343,120 @@ bool osmo_fr_check_sid(const uint8_t *rtp_payload, size_t payload_len)
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 osmo_gsm631_sid_class, with symbolic values
+ * OSMO_GSM631_SID_CLASS_SPEECH, OSMO_GSM631_SID_CLASS_INVALID or
+ * OSMO_GSM631_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 osmo_gsm631_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 OSMO_GSM631_SID_CLASS_SPEECH;
+ }
+ if (n >= 2)
+ return OSMO_GSM631_SID_CLASS_INVALID;
+ else
+ return OSMO_GSM631_SID_CLASS_VALID;
+}
+
+/*! Reset the SID field and the unused bits of a potentially corrupted,
+ * but still valid GSM-FR SID frame in RTP encoding to their pristine state.
+ * \param[in] rtp_payload Buffer with RTP payload - must be writable!
+ *
+ * Per GSM 06.12 section 5.2, a freshly minted SID frame carries 60 bits
+ * of comfort noise parameters (LARc and 4 times Xmaxc), while the remaining
+ * 200 bits are all zeros; the latter 200 all-0 bits further break down into
+ * 95 bits of SID field (checked by receivers to detect SID) and 105 unused
+ * bits which receivers are told to ignore. Network elements that receive
+ * SID frames from call leg A uplink and need to retransmit them on leg B
+ * downlink should "rejuvenate" received SID frames prior to retransmission;
+ * this function does the job.
+ */
+void osmo_fr_sid_reset(uint8_t *rtp_payload)
+{
+ uint8_t *p, sub;
+
+ p = rtp_payload + 5; /* skip magic+LARc */
+ for (sub = 0; sub < 4; sub++) {
+ *p++ = 0;
+ *p++ &= 0x1F; /* upper 5 bits of Xmaxc field */
+ *p++ &= 0x80; /* and the lsb spilling into the next byte */
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ }
+}
+
+/*! 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 osmo_gsm631_sid_class sidc;
+
+ sidc = osmo_fr_sid_classify(rtp_payload);
+ switch (sidc) {
+ case OSMO_GSM631_SID_CLASS_SPEECH:
+ return true;
+ case OSMO_GSM631_SID_CLASS_INVALID:
+ return false;
+ case OSMO_GSM631_SID_CLASS_VALID:
+ /* "Rejuvenate" this SID frame, correcting any errors */
+ osmo_fr_sid_reset(rtp_payload);
+ return true;
+ default:
+ /* There are only 3 possible SID classifications per GSM 06.31
+ * section 6.1.1, thus any other return value is a grave error
+ * in the code. */
+ OSMO_ASSERT(0);
+ }
+}