Portability fix: Adding local partial copy of libosmocore (TODO: minimize it)
diff --git a/lib/decoding/osmocom/codec/CMakeLists.txt b/lib/decoding/osmocom/codec/CMakeLists.txt
new file mode 100644
index 0000000..d5c3997
--- /dev/null
+++ b/lib/decoding/osmocom/codec/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_sources(
+gsm610.c
+gsm620.c
+gsm660.c
+gsm690.c
+)
diff --git a/lib/decoding/osmocom/codec/codec.h b/lib/decoding/osmocom/codec/codec.h
new file mode 100644
index 0000000..6a1bf9f
--- /dev/null
+++ b/lib/decoding/osmocom/codec/codec.h
@@ -0,0 +1,81 @@
+/*! \file codec.h */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <osmocom/core/utils.h>
+
+/* TS 101318 Chapter 5.1: 260 bits + 4bit sig */
+#define GSM_FR_BYTES	33
+/* TS 101318 Chapter 5.2: 112 bits, no sig */
+#define GSM_HR_BYTES	14
+/* TS 101318 Chapter 5.3: 244 bits + 4bit sig */
+#define GSM_EFR_BYTES	31
+
+extern const uint16_t gsm610_bitorder[];	/* FR */
+extern const uint16_t gsm620_unvoiced_bitorder[]; /* HR unvoiced */
+extern const uint16_t gsm620_voiced_bitorder[];   /* HR voiced */
+extern const uint16_t gsm660_bitorder[];	/* EFR */
+
+extern const uint16_t gsm690_12_2_bitorder[];	/* AMR 12.2  kbits */
+extern const uint16_t gsm690_10_2_bitorder[];	/* AMR 10.2  kbits */
+extern const uint16_t gsm690_7_95_bitorder[];	/* AMR  7.95 kbits */
+extern const uint16_t gsm690_7_4_bitorder[];	/* AMR  7.4  kbits */
+extern const uint16_t gsm690_6_7_bitorder[];	/* AMR  6.7  kbits */
+extern const uint16_t gsm690_5_9_bitorder[];	/* AMR  5.9  kbits */
+extern const uint16_t gsm690_5_15_bitorder[];	/* AMR  5.15 kbits */
+extern const uint16_t gsm690_4_75_bitorder[];	/* AMR  4.75 kbits */
+
+extern const struct value_string osmo_amr_type_names[];
+
+enum osmo_amr_type {
+       AMR_4_75 = 0,
+       AMR_5_15 = 1,
+       AMR_5_90 = 2,
+       AMR_6_70 = 3,
+       AMR_7_40 = 4,
+       AMR_7_95 = 5,
+       AMR_10_2 = 6,
+       AMR_12_2 = 7,
+       AMR_SID = 8,
+       AMR_GSM_EFR_SID = 9,
+       AMR_TDMA_EFR_SID = 10,
+       AMR_PDC_EFR_SID = 11,
+       AMR_NO_DATA = 15,
+};
+
+enum osmo_amr_quality {
+       AMR_BAD = 0,
+       AMR_GOOD = 1
+};
+
+/*! Check if given AMR Frame Type is a speech frame
+ *  \param[in] ft AMR Frame Type
+ *  \returns true if AMR with given Frame Type contains voice, false otherwise
+ */
+static inline bool osmo_amr_is_speech(enum osmo_amr_type ft)
+{
+	switch (ft) {
+	case AMR_4_75:
+	case AMR_5_15:
+	case AMR_5_90:
+	case AMR_6_70:
+	case AMR_7_40:
+	case AMR_7_95:
+	case AMR_10_2:
+	case AMR_12_2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+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);
+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,
+		     int8_t *cmi, enum osmo_amr_type *ft,
+		     enum osmo_amr_quality *bfi, int8_t *sti);
diff --git a/lib/decoding/osmocom/codec/gsm610.c b/lib/decoding/osmocom/codec/gsm610.c
new file mode 100644
index 0000000..a05eaba
--- /dev/null
+++ b/lib/decoding/osmocom/codec/gsm610.c
@@ -0,0 +1,336 @@
+/*! \file gsm610.c
+ * GSM 06.10 - GSM FR codec. */
+/*
+ * (C) 2010 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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>
+#include <stdbool.h>
+
+#include <osmocom/core/bitvec.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/codec/codec.h>
+
+/* GSM FR - subjective importance bit ordering */
+	/* This array encodes GSM 05.03 Table 2.
+	 * It's also GSM 06.10 Table A.2.1a
+	 *
+	 * It converts between serial parameter output by the encoder and the
+	 * order needed before channel encoding.
+	 */
+const uint16_t gsm610_bitorder[260] = {
+	0,	/* LARc0:5 */
+	47,	/* Xmaxc0:5 */
+	103,	/* Xmaxc1:5 */
+	159,	/* Xmaxc2:5 */
+	215,	/* Xmaxc3:5 */
+	1,	/* LARc0:4 */
+	6,	/* LARc1:5 */
+	12,	/* LARc2:4 */
+	2,	/* LARc0:3 */
+	7,	/* LARc1:4 */
+	13,	/* LARc2:3 */
+	17,	/* LARc3:4 */
+	36,	/* Nc0:6 */
+	92,	/* Nc1:6 */
+	148,	/* Nc2:6 */
+	204,	/* Nc3:6 */
+	48,	/* Xmaxc0:4 */
+	104,	/* Xmaxc1:4 */
+	160,	/* Xmaxc2:4 */
+	216,	/* Xmaxc3:4 */
+	8,	/* LARc1:3 */
+	22,	/* LARc4:3 */
+	26,	/* LARc5:3 */
+	37,	/* Nc0:5 */
+	93,	/* Nc1:5 */
+	149,	/* Nc2:5 */
+	205,	/* Nc3:5 */
+	38,	/* Nc0:4 */
+	94,	/* Nc1:4 */
+	150,	/* Nc2:4 */
+	206,	/* Nc3:4 */
+	39,	/* Nc0:3 */
+	95,	/* Nc1:3 */
+	151,	/* Nc2:3 */
+	207,	/* Nc3:3 */
+	40,	/* Nc0:2 */
+	96,	/* Nc1:2 */
+	152,	/* Nc2:2 */
+	208,	/* Nc3:2 */
+	49,	/* Xmaxc0:3 */
+	105,	/* Xmaxc1:3 */
+	161,	/* Xmaxc2:3 */
+	217,	/* Xmaxc3:3 */
+	3,	/* LARc0:2 */
+	18,	/* LARc3:3 */
+	30,	/* LARc6:2 */
+	41,	/* Nc0:1 */
+	97,	/* Nc1:1 */
+	153,	/* Nc2:1 */
+	209,	/* Nc3:1 */
+	23,	/* LARc4:2 */
+	27,	/* LARc5:2 */
+	43,	/* bc0:1 */
+	99,	/* bc1:1 */
+	155,	/* bc2:1 */
+	211,	/* bc3:1 */
+	42,	/* Nc0:0 */
+	98,	/* Nc1:0 */
+	154,	/* Nc2:0 */
+	210,	/* Nc3:0 */
+	45,	/* Mc0:1 */
+	101,	/* Mc1:1 */
+	157,	/* Mc2:1 */
+	213,	/* Mc3:1 */
+	4,	/* LARc0:1 */
+	9,	/* LARc1:2 */
+	14,	/* LARc2:2 */
+	33,	/* LARc7:2 */
+	19,	/* LARc3:2 */
+	24,	/* LARc4:1 */
+	31,	/* LARc6:1 */
+	44,	/* bc0:0 */
+	100,	/* bc1:0 */
+	156,	/* bc2:0 */
+	212,	/* bc3:0 */
+	50,	/* Xmaxc0:2 */
+	106,	/* Xmaxc1:2 */
+	162,	/* Xmaxc2:2 */
+	218,	/* Xmaxc3:2 */
+	53,	/* xmc0_0:2 */
+	56,	/* xmc0_1:2 */
+	59,	/* xmc0_2:2 */
+	62,	/* xmc0_3:2 */
+	65,	/* xmc0_4:2 */
+	68,	/* xmc0_5:2 */
+	71,	/* xmc0_6:2 */
+	74,	/* xmc0_7:2 */
+	77,	/* xmc0_8:2 */
+	80,	/* xmc0_9:2 */
+	83,	/* xmc0_10:2 */
+	86,	/* xmc0_11:2 */
+	89,	/* xmc0_12:2 */
+	109,	/* xmc1_0:2 */
+	112,	/* xmc1_1:2 */
+	115,	/* xmc1_2:2 */
+	118,	/* xmc1_3:2 */
+	121,	/* xmc1_4:2 */
+	124,	/* xmc1_5:2 */
+	127,	/* xmc1_6:2 */
+	130,	/* xmc1_7:2 */
+	133,	/* xmc1_8:2 */
+	136,	/* xmc1_9:2 */
+	139,	/* xmc1_10:2 */
+	142,	/* xmc1_11:2 */
+	145,	/* xmc1_12:2 */
+	165,	/* xmc2_0:2 */
+	168,	/* xmc2_1:2 */
+	171,	/* xmc2_2:2 */
+	174,	/* xmc2_3:2 */
+	177,	/* xmc2_4:2 */
+	180,	/* xmc2_5:2 */
+	183,	/* xmc2_6:2 */
+	186,	/* xmc2_7:2 */
+	189,	/* xmc2_8:2 */
+	192,	/* xmc2_9:2 */
+	195,	/* xmc2_10:2 */
+	198,	/* xmc2_11:2 */
+	201,	/* xmc2_12:2 */
+	221,	/* xmc3_0:2 */
+	224,	/* xmc3_1:2 */
+	227,	/* xmc3_2:2 */
+	230,	/* xmc3_3:2 */
+	233,	/* xmc3_4:2 */
+	236,	/* xmc3_5:2 */
+	239,	/* xmc3_6:2 */
+	242,	/* xmc3_7:2 */
+	245,	/* xmc3_8:2 */
+	248,	/* xmc3_9:2 */
+	251,	/* xmc3_10:2 */
+	254,	/* xmc3_11:2 */
+	257,	/* xmc3_12:2 */
+	46,	/* Mc0:0 */
+	102,	/* Mc1:0 */
+	158,	/* Mc2:0 */
+	214,	/* Mc3:0 */
+	51,	/* Xmaxc0:1 */
+	107,	/* Xmaxc1:1 */
+	163,	/* Xmaxc2:1 */
+	219,	/* Xmaxc3:1 */
+	54,	/* xmc0_0:1 */
+	57,	/* xmc0_1:1 */
+	60,	/* xmc0_2:1 */
+	63,	/* xmc0_3:1 */
+	66,	/* xmc0_4:1 */
+	69,	/* xmc0_5:1 */
+	72,	/* xmc0_6:1 */
+	75,	/* xmc0_7:1 */
+	78,	/* xmc0_8:1 */
+	81,	/* xmc0_9:1 */
+	84,	/* xmc0_10:1 */
+	87,	/* xmc0_11:1 */
+	90,	/* xmc0_12:1 */
+	110,	/* xmc1_0:1 */
+	113,	/* xmc1_1:1 */
+	116,	/* xmc1_2:1 */
+	119,	/* xmc1_3:1 */
+	122,	/* xmc1_4:1 */
+	125,	/* xmc1_5:1 */
+	128,	/* xmc1_6:1 */
+	131,	/* xmc1_7:1 */
+	134,	/* xmc1_8:1 */
+	137,	/* xmc1_9:1 */
+	140,	/* xmc1_10:1 */
+	143,	/* xmc1_11:1 */
+	146,	/* xmc1_12:1 */
+	166,	/* xmc2_0:1 */
+	169,	/* xmc2_1:1 */
+	172,	/* xmc2_2:1 */
+	175,	/* xmc2_3:1 */
+	178,	/* xmc2_4:1 */
+	181,	/* xmc2_5:1 */
+	184,	/* xmc2_6:1 */
+	187,	/* xmc2_7:1 */
+	190,	/* xmc2_8:1 */
+	193,	/* xmc2_9:1 */
+	196,	/* xmc2_10:1 */
+	199,	/* xmc2_11:1 */
+	202,	/* xmc2_12:1 */
+	222,	/* xmc3_0:1 */
+	225,	/* xmc3_1:1 */
+	228,	/* xmc3_2:1 */
+	231,	/* xmc3_3:1 */
+	234,	/* xmc3_4:1 */
+	237,	/* xmc3_5:1 */
+	240,	/* xmc3_6:1 */
+	243,	/* xmc3_7:1 */
+	246,	/* xmc3_8:1 */
+	249,	/* xmc3_9:1 */
+	252,	/* xmc3_10:1 */
+	255,	/* xmc3_11:1 */
+	258,	/* xmc3_12:1 */
+	5,	/* LARc0:0 */
+	10,	/* LARc1:1 */
+	15,	/* LARc2:1 */
+	28,	/* LARc5:1 */
+	32,	/* LARc6:0 */
+	34,	/* LARc7:1 */
+	35,	/* LARc7:0 */
+	16,	/* LARc2:0 */
+	20,	/* LARc3:1 */
+	21,	/* LARc3:0 */
+	25,	/* LARc4:0 */
+	52,	/* Xmaxc0:0 */
+	108,	/* Xmaxc1:0 */
+	164,	/* Xmaxc2:0 */
+	220,	/* Xmaxc3:0 */
+	55,	/* xmc0_0:0 */
+	58,	/* xmc0_1:0 */
+	61,	/* xmc0_2:0 */
+	64,	/* xmc0_3:0 */
+	67,	/* xmc0_4:0 */
+	70,	/* xmc0_5:0 */
+	73,	/* xmc0_6:0 */
+	76,	/* xmc0_7:0 */
+	79,	/* xmc0_8:0 */
+	82,	/* xmc0_9:0 */
+	85,	/* xmc0_10:0 */
+	88,	/* xmc0_11:0 */
+	91,	/* xmc0_12:0 */
+	111,	/* xmc1_0:0 */
+	114,	/* xmc1_1:0 */
+	117,	/* xmc1_2:0 */
+	120,	/* xmc1_3:0 */
+	123,	/* xmc1_4:0 */
+	126,	/* xmc1_5:0 */
+	129,	/* xmc1_6:0 */
+	132,	/* xmc1_7:0 */
+	135,	/* xmc1_8:0 */
+	138,	/* xmc1_9:0 */
+	141,	/* xmc1_10:0 */
+	144,	/* xmc1_11:0 */
+	147,	/* xmc1_12:0 */
+	167,	/* xmc2_0:0 */
+	170,	/* xmc2_1:0 */
+	173,	/* xmc2_2:0 */
+	176,	/* xmc2_3:0 */
+	179,	/* xmc2_4:0 */
+	182,	/* xmc2_5:0 */
+	185,	/* xmc2_6:0 */
+	188,	/* xmc2_7:0 */
+	191,	/* xmc2_8:0 */
+	194,	/* xmc2_9:0 */
+	197,	/* xmc2_10:0 */
+	200,	/* xmc2_11:0 */
+	203,	/* xmc2_12:0 */
+	223,	/* xmc3_0:0 */
+	226,	/* xmc3_1:0 */
+	229,	/* xmc3_2:0 */
+	232,	/* xmc3_3:0 */
+	235,	/* xmc3_4:0 */
+	238,	/* xmc3_5:0 */
+	241,	/* xmc3_6:0 */
+	244,	/* xmc3_7:0 */
+	247,	/* xmc3_8:0 */
+	250,	/* xmc3_9:0 */
+	253,	/* xmc3_10:0 */
+	256,	/* xmc3_11:0 */
+	259,	/* xmc3_12:0 */
+	11,	/* LARc1:0 */
+	29,	/* LARc5:0 */
+};
+
+/*! 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
+ *  \param[in] payload_len Length of payload
+ *  \returns true if code word is found, false otherwise
+ */
+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 };
+
+	/* signature does not match Full Rate SID */
+	if ((rtp_payload[0] >> 4) != 0xD)
+		return false;
+
+	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)
+			return false;
+
+	return true;
+}
diff --git a/lib/decoding/osmocom/codec/gsm610_bits.h b/lib/decoding/osmocom/codec/gsm610_bits.h
new file mode 100644
index 0000000..cef4cf4
--- /dev/null
+++ b/lib/decoding/osmocom/codec/gsm610_bits.h
@@ -0,0 +1,272 @@
+/*! \file gsm610_bits.h */
+
+#pragma once
+
+/* This enumeration describs a GSM-FR (GSM 06.10) frame in ints RTP bit order
+ * representation. See also RFC 3551 Table 3: GSM payload format */
+enum gsm610_rtp_bit_offsets {
+	GSM610_RTP_SIGNATURE_0,
+	GSM610_RTP_SIGNATURE_1,
+	GSM610_RTP_SIGNATURE_2,
+	GSM610_RTP_SIGNATURE_3,
+	GSM610_RTP_LARC0_0,
+	GSM610_RTP_LARC0_1,
+	GSM610_RTP_LARC0_2,
+	GSM610_RTP_LARC0_3,
+	GSM610_RTP_LARC0_4,
+	GSM610_RTP_LARC0_5,
+	GSM610_RTP_LARC1_0,
+	GSM610_RTP_LARC1_1,
+	GSM610_RTP_LARC1_2,
+	GSM610_RTP_LARC1_3,
+	GSM610_RTP_LARC1_4,
+	GSM610_RTP_LARC1_5,
+	GSM610_RTP_LARC2_0,
+	GSM610_RTP_LARC2_1,
+	GSM610_RTP_LARC2_2,
+	GSM610_RTP_LARC2_3,
+	GSM610_RTP_LARC2_4,
+	GSM610_RTP_LARC3_0,
+	GSM610_RTP_LARC3_1,
+	GSM610_RTP_LARC3_2,
+	GSM610_RTP_LARC3_3,
+	GSM610_RTP_LARC3_4,
+	GSM610_RTP_LARC4_0,
+	GSM610_RTP_LARC4_1,
+	GSM610_RTP_LARC4_2,
+	GSM610_RTP_LARC4_3,
+	GSM610_RTP_LARC5_0,
+	GSM610_RTP_LARC5_1,
+	GSM610_RTP_LARC5_2,
+	GSM610_RTP_LARC5_3,
+	GSM610_RTP_LARC6_0,
+	GSM610_RTP_LARC6_1,
+	GSM610_RTP_LARC6_2,
+	GSM610_RTP_LARC7_0,
+	GSM610_RTP_LARC7_1,
+	GSM610_RTP_LARC7_2,
+	GSM610_RTP_NC0_0,
+	GSM610_RTP_NC0_1,
+	GSM610_RTP_NC0_2,
+	GSM610_RTP_NC0_3,
+	GSM610_RTP_NC0_4,
+	GSM610_RTP_NC0_5,
+	GSM610_RTP_NC0_6,
+	GSM610_RTP_BC0_0,
+	GSM610_RTP_BC0_1,
+	GSM610_RTP_MC0_0,
+	GSM610_RTP_MC0_1,
+	GSM610_RTP_XMAXC00,
+	GSM610_RTP_XMAXC01,
+	GSM610_RTP_XMAXC02,
+	GSM610_RTP_XMAXC03,
+	GSM610_RTP_XMAXC04,
+	GSM610_RTP_XMAXC05,
+	GSM610_RTP_XMC0_0,
+	GSM610_RTP_XMC0_1,
+	GSM610_RTP_XMC0_2,
+	GSM610_RTP_XMC1_0,
+	GSM610_RTP_XMC1_1,
+	GSM610_RTP_XMC1_2,
+	GSM610_RTP_XMC2_0,
+	GSM610_RTP_XMC2_1,
+	GSM610_RTP_XMC2_2,
+	GSM610_RTP_XMC3_0,
+	GSM610_RTP_XMC3_1,
+	GSM610_RTP_XMC3_2,
+	GSM610_RTP_XMC4_0,
+	GSM610_RTP_XMC4_1,
+	GSM610_RTP_XMC4_2,
+	GSM610_RTP_XMC5_0,
+	GSM610_RTP_XMC5_1,
+	GSM610_RTP_XMC5_2,
+	GSM610_RTP_XMC6_0,
+	GSM610_RTP_XMC6_1,
+	GSM610_RTP_XMC6_2,
+	GSM610_RTP_XMC7_0,
+	GSM610_RTP_XMC7_1,
+	GSM610_RTP_XMC7_2,
+	GSM610_RTP_XMC8_0,
+	GSM610_RTP_XMC8_1,
+	GSM610_RTP_XMC8_2,
+	GSM610_RTP_XMC9_0,
+	GSM610_RTP_XMC9_1,
+	GSM610_RTP_XMC9_2,
+	GSM610_RTP_XMC10_0,
+	GSM610_RTP_XMC10_1,
+	GSM610_RTP_XMC10_2,
+	GSM610_RTP_XMC11_0,
+	GSM610_RTP_XMC11_1,
+	GSM610_RTP_XMC11_2,
+	GSM610_RTP_XMC12_0,
+	GSM610_RTP_XMC12_1,
+	GSM610_RTP_XCM12_2,
+	GSM610_RTP_NC1_0,
+	GSM610_RTP_NC1_1,
+	GSM610_RTP_NC1_2,
+	GSM610_RTP_NC1_3,
+	GSM610_RTP_NC1_4,
+	GSM610_RTP_NC1_5,
+	GSM610_RTP_NC1_6,
+	GSM610_RTP_BC1_0,
+	GSM610_RTP_BC1_1,
+	GSM610_RTP_MC1_0,
+	GSM610_RTP_MC1_1,
+	GSM610_RTP_XMAXC10,
+	GSM610_RTP_XMAXC11,
+	GSM610_RTP_XMAXC12,
+	GSM610_RTP_XMAXC13,
+	GSM610_RTP_XMAXC14,
+	GSM610_RTP_XMAX15,
+	GSM610_RTP_XMC13_0,
+	GSM610_RTP_XMC13_1,
+	GSM610_RTP_XMC13_2,
+	GSM610_RTP_XMC14_0,
+	GSM610_RTP_XMC14_1,
+	GSM610_RTP_XMC14_2,
+	GSM610_RTP_XMC15_0,
+	GSM610_RTP_XMC15_1,
+	GSM610_RTP_XMC15_2,
+	GSM610_RTP_XMC16_0,
+	GSM610_RTP_XMC16_1,
+	GSM610_RTP_XMC16_2,
+	GSM610_RTP_XMC17_0,
+	GSM610_RTP_XMC17_1,
+	GSM610_RTP_XMC17_2,
+	GSM610_RTP_XMC18_0,
+	GSM610_RTP_XMC18_1,
+	GSM610_RTP_XMC18_2,
+	GSM610_RTP_XMC19_0,
+	GSM610_RTP_XMC19_1,
+	GSM610_RTP_XMC19_2,
+	GSM610_RTP_XMC20_0,
+	GSM610_RTP_XMC20_1,
+	GSM610_RTP_XMC20_2,
+	GSM610_RTP_XMC21_0,
+	GSM610_RTP_XMC21_1,
+	GSM610_RTP_XMC21_2,
+	GSM610_RTP_XMC22_0,
+	GSM610_RTP_XMC22_1,
+	GSM610_RTP_XMC22_2,
+	GSM610_RTP_XMC23_0,
+	GSM610_RTP_XMC23_1,
+	GSM610_RTP_XMC23_2,
+	GSM610_RTP_XMC24_0,
+	GSM610_RTP_XMC24_1,
+	GSM610_RTP_XMC24_2,
+	GSM610_RTP_XMC25_0,
+	GSM610_RTP_XMC25_1,
+	GSM610_RTP_XMC25_2,
+	GSM610_RTP_NC2_0,
+	GSM610_RTP_NC2_1,
+	GSM610_RTP_NC2_2,
+	GSM610_RTP_NC2_3,
+	GSM610_RTP_NC2_4,
+	GSM610_RTP_NC2_5,
+	GSM610_RTP_NC2_6,
+	GSM610_RTP_BC2_0,
+	GSM610_RTP_BC2_1,
+	GSM610_RTP_MC2_0,
+	GSM610_RTP_MC2_1,
+	GSM610_RTP_XMAXC20,
+	GSM610_RTP_XMAXC21,
+	GSM610_RTP_XMAXC22,
+	GSM610_RTP_XMAXC23,
+	GSM610_RTP_XMAXC24,
+	GSM610_RTP_XMAXC25,
+	GSM610_RTP_XMC26_0,
+	GSM610_RTP_XMC26_1,
+	GSM610_RTP_XMC26_2,
+	GSM610_RTP_XMC27_0,
+	GSM610_RTP_XMC27_1,
+	GSM610_RTP_XMC27_2,
+	GSM610_RTP_XMC28_0,
+	GSM610_RTP_XMC28_1,
+	GSM610_RTP_XMC28_2,
+	GSM610_RTP_XMC29_0,
+	GSM610_RTP_XMC29_1,
+	GSM610_RTP_XMC29_2,
+	GSM610_RTP_XMC30_0,
+	GSM610_RTP_XMC30_1,
+	GSM610_RTP_XMC30_2,
+	GSM610_RTP_XMC31_0,
+	GSM610_RTP_XMC31_1,
+	GSM610_RTP_XMC31_2,
+	GSM610_RTP_XMC32_0,
+	GSM610_RTP_XMC32_1,
+	GSM610_RTP_XMC32_2,
+	GSM610_RTP_XMC33_0,
+	GSM610_RTP_XMC33_1,
+	GSM610_RTP_XMC33_2,
+	GSM610_RTP_XMC34_0,
+	GSM610_RTP_XMC34_1,
+	GSM610_RTP_XMC34_2,
+	GSM610_RTP_XMC35_0,
+	GSM610_RTP_XMC35_1,
+	GSM610_RTP_XMC35_2,
+	GSM610_RTP_XMC36_0,
+	GSM610_RTP_XMC36_1,
+	GSM610_RTP_XMC36_2,
+	GSM610_RTP_XMC37_0,
+	GSM610_RTP_XMC37_1,
+	GSM610_RTP_XMC37_2,
+	GSM610_RTP_XMC38_0,
+	GSM610_RTP_XMC38_1,
+	GSM610_RTP_XMC38_2,
+	GSM610_RTP_NC3_0,
+	GSM610_RTP_NC3_1,
+	GSM610_RTP_NC3_2,
+	GSM610_RTP_NC3_3,
+	GSM610_RTP_NC3_4,
+	GSM610_RTP_NC3_5,
+	GSM610_RTP_NC3_6,
+	GSM610_RTP_BC3_0,
+	GSM610_RTP_BC3_1,
+	GSM610_RTP_MC3_0,
+	GSM610_RTP_MC3_1,
+	GSM610_RTP_XMAXC30,
+	GSM610_RTP_XMAXC31,
+	GSM610_RTP_XMAXC32,
+	GSM610_RTP_XMAXC33,
+	GSM610_RTP_XMAXC34,
+	GSM610_RTP_XMAXC35,
+	GSM610_RTP_XMC39_0,
+	GSM610_RTP_XMC39_1,
+	GSM610_RTP_XMC39_2,
+	GSM610_RTP_XMC40_0,
+	GSM610_RTP_XMC40_1,
+	GSM610_RTP_XMC40_2,
+	GSM610_RTP_XMC41_0,
+	GSM610_RTP_XMC41_1,
+	GSM610_RTP_XMC41_2,
+	GSM610_RTP_XMC42_0,
+	GSM610_RTP_XMC42_1,
+	GSM610_RTP_XMC42_2,
+	GSM610_RTP_XMC43_0,
+	GSM610_RTP_XMC43_1,
+	GSM610_RTP_XMC43_2,
+	GSM610_RTP_XMC44_0,
+	GSM610_RTP_XMC44_1,
+	GSM610_RTP_XMC44_2,
+	GSM610_RTP_XMC45_0,
+	GSM610_RTP_XMC45_1,
+	GSM610_RTP_XMC45_2,
+	GSM610_RTP_XMC46_0,
+	GSM610_RTP_XMC46_1,
+	GSM610_RTP_XMC46_2,
+	GSM610_RTP_XMC47_0,
+	GSM610_RTP_XMC47_1,
+	GSM610_RTP_XMC47_2,
+	GSM610_RTP_XMC48_0,
+	GSM610_RTP_XMC48_1,
+	GSM610_RTP_XMC48_2,
+	GSM610_RTP_XMC49_0,
+	GSM610_RTP_XMC49_1,
+	GSM610_RTP_XMC49_2,
+	GSM610_RTP_XMC50_0,
+	GSM610_RTP_XMC50_1,
+	GSM610_RTP_XMC50_2,
+	GSM610_RTP_XMC51_0,
+	GSM610_RTP_XMC51_1,
+	GSM610_RTP_XMC51_2
+};
diff --git a/lib/decoding/osmocom/codec/gsm620.c b/lib/decoding/osmocom/codec/gsm620.c
new file mode 100644
index 0000000..282781f
--- /dev/null
+++ b/lib/decoding/osmocom/codec/gsm620.c
@@ -0,0 +1,297 @@
+/*! \file gsm620.c
+ * GSM 06.20 - GSM HR codec. */
+/*
+ * (C) 2010 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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>
+#include <stdbool.h>
+
+#include <osmocom/core/bitvec.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/codec/codec.h>
+
+/* GSM HR unvoiced (mode=0) frames - subjective importance bit ordering */
+	/* This array encode mapping between GSM 05.03 Table 3a (bits
+	 * ordering before channel coding on TCH) and GSM 06.20 Table B.1
+	 * (bit ordering on A-bis */
+const uint16_t gsm620_unvoiced_bitorder[112] = {
+	3,	/* R0:1 */
+	25,	/* LPC 3:7 */
+	52,	/* GSP 0-1:2 */
+	71,	/* GSP 0-2:2 */
+	90,	/* GSP 0-3:2 */
+	109,	/* GSP 0-4:2 */
+	15,	/* LPC 1:0 */
+	19,	/* LPC 2:5 */
+	20,	/* LPC 2:4 */
+	21,	/* LPC 2:3 */
+	22,	/* LPC 2:2 */
+	23,	/* LPC 2:1 */
+	26,	/* LPC 3:6 */
+	27,	/* LPC 3:5 */
+	28,	/* LPC 3:4 */
+	29,	/* LPC 3:3 */
+	30,	/* LPC 3:2 */
+	31,	/* LPC 3:1 */
+	61,	/* Code 1-2:0 */
+	62,	/* Code 2-2:6 */
+	63,	/* Code 2-2:5 */
+	64,	/* Code 2-2:4 */
+	65,	/* Code 2-2:3 */
+	66,	/* Code 2-2:2 */
+	67,	/* Code 2-2:1 */
+	68,	/* Code 2-2:0 */
+	74,	/* Code 1-3:6 */
+	75,	/* Code 1-3:5 */
+	76,	/* Code 1-3:4 */
+	77,	/* Code 1-3:3 */
+	78,	/* Code 1-3:2 */
+	79,	/* Code 1-3:1 */
+	80,	/* Code 1-3:0 */
+	81,	/* Code 2-3:6 */
+	82,	/* Code 2-3:5 */
+	83,	/* Code 2-3:4 */
+	84,	/* Code 2-3:3 */
+	32,	/* LPC 3:0 */
+	4,	/* R0:0 */
+	33,	/* INT-LPC:0 */
+	60,	/* Code 1-2:1 */
+	59,	/* Code 1-2:2 */
+	58,	/* Code 1-2:3 */
+	57,	/* Code 1-2:4 */
+	56,	/* Code 1-2:5 */
+	55,	/* Code 1-2:6 */
+	49,	/* Code 2-1:0 */
+	48,	/* Code 2-1:1 */
+	47,	/* Code 2-1:2 */
+	46,	/* Code 2-1:3 */
+	45,	/* Code 2-1:4 */
+	44,	/* Code 2-1:5 */
+	43,	/* Code 2-1:6 */
+	42,	/* Code 1-1:0 */
+	41,	/* Code 1-1:1 */
+	40,	/* Code 1-1:2 */
+	39,	/* Code 1-1:3 */
+	38,	/* Code 1-1:4 */
+	37,	/* Code 1-1:5 */
+	36,	/* Code 1-1:6 */
+	111,	/* GSP 0-4:0 */
+	92,	/* GSP 0-3:0 */
+	73,	/* GSP 0-2:0 */
+	54,	/* GSP 0-1:0 */
+	24,	/* LPC 2:0 */
+	110,	/* GSP 0-4:1 */
+	91,	/* GSP 0-3:1 */
+	72,	/* GSP 0-2:1 */
+	53,	/* GSP 0-1:1 */
+	14,	/* LPC 1:1 */
+	13,	/* LPC 1:2 */
+	12,	/* LPC 1:3 */
+	11,	/* LPC 1:4 */
+	10,	/* LPC 1:5 */
+	108,	/* GSP 0-4:3 */
+	89,	/* GSP 0-3:3 */
+	70,	/* GSP 0-2:3 */
+	51,	/* GSP 0-1:3 */
+	16,	/* LPC 2:8 */
+	17,	/* LPC 2:7 */
+	18,	/* LPC 2:6 */
+	107,	/* GSP 0-4:4 */
+	88,	/* GSP 0-3:4 */
+	69,	/* GSP 0-2:4 */
+	50,	/* GSP 0-1:4 */
+	9,	/* LPC 1:6 */
+	8,	/* LPC 1:7 */
+	7,	/* LPC 1:8 */
+	6,	/* LPC 1:9 */
+	2,	/* R0:2 */
+	5,	/* LPC 1:10 */
+	1,	/* R0:3 */
+	0,	/* R0:4 */
+	35,	/* Mode:0 */
+	34,	/* Mode:1 */
+	106,	/* Code 2-4:0 */
+	105,	/* Code 2-4:1 */
+	104,	/* Code 2-4:2 */
+	103,	/* Code 2-4:3 */
+	102,	/* Code 2-4:4 */
+	101,	/* Code 2-4:5 */
+	100,	/* Code 2-4:6 */
+	99,	/* Code 1-4:0 */
+	98,	/* Code 1-4:1 */
+	97,	/* Code 1-4:2 */
+	96,	/* Code 1-4:3 */
+	95,	/* Code 1-4:4 */
+	94,	/* Code 1-4:5 */
+	93,	/* Code 1-4:6 */
+	87,	/* Code 2-3:0 */
+	86,	/* Code 2-3:1 */
+	85,	/* Code 2-3:2 */
+};
+
+/* GSM HR voiced (mode=1,2,3) frames - subjective importance bit ordering */
+	/* This array encode mapping between GSM 05.03 Table 3b (bits
+	 * ordering before channel coding on TCH) and GSM 06.20 Table B.2
+	 * (bit ordering on A-bis */
+const uint16_t gsm620_voiced_bitorder[112] = {
+	13,	/* LPC 1:2 */
+	14,	/* LPC 1:1 */
+	18,	/* LPC 2:6 */
+	19,	/* LPC 2:5 */
+	20,	/* LPC 2:4 */
+	53,	/* GSP 0-1:4 */
+	71,	/* GSP 0-2:4 */
+	89,	/* GSP 0-3:4 */
+	107,	/* GSP 0-4:4 */
+	54,	/* GSP 0-1:3 */
+	72,	/* GSP 0-2:3 */
+	90,	/* GSP 0-3:3 */
+	108,	/* GSP 0-4:3 */
+	55,	/* GSP 0-1:2 */
+	73,	/* GSP 0-2:2 */
+	91,	/* GSP 0-3:2 */
+	109,	/* GSP 0-4:2 */
+	44,	/* Code 1:8 */
+	45,	/* Code 1:7 */
+	46,	/* Code 1:6 */
+	47,	/* Code 1:5 */
+	48,	/* Code 1:4 */
+	49,	/* Code 1:3 */
+	50,	/* Code 1:2 */
+	51,	/* Code 1:1 */
+	52,	/* Code 1:0 */
+	62,	/* Code 2:8 */
+	63,	/* Code 2:7 */
+	64,	/* Code 2:6 */
+	65,	/* Code 2:5 */
+	68,	/* Code 2:2 */
+	69,	/* Code 2:1 */
+	70,	/* Code 2:0 */
+	80,	/* Code 3:8 */
+	66,	/* Code 2:4 */
+	67,	/* Code 2:3 */
+	56,	/* GSP 0-1:1 */
+	74,	/* GSP 0-2:1 */
+	92,	/* GSP 0-3:1 */
+	110,	/* GSP 0-4:1 */
+	57,	/* GSP 0-1:0 */
+	75,	/* GSP 0-2:0 */
+	93,	/* GSP 0-3:0 */
+	111,	/* GSP 0-4:0 */
+	33,	/* INT-LPC:0 */
+	24,	/* LPC 2:0 */
+	32,	/* LPC 3:0 */
+	97,	/* LAG 4:0 */
+	31,	/* LPC 3:1 */
+	23,	/* LPC 2:1 */
+	96,	/* LAG 4:1 */
+	79,	/* LAG 3:0 */
+	61,	/* LAG 2:0 */
+	43,	/* LAG 1:0 */
+	95,	/* LAG 4:2 */
+	78,	/* LAG 3:1 */
+	60,	/* LAG 2:1 */
+	42,	/* LAG 1:1 */
+	30,	/* LPC 3:2 */
+	29,	/* LPC 3:3 */
+	28,	/* LPC 3:4 */
+	22,	/* LPC 2:2 */
+	27,	/* LPC 3:5 */
+	26,	/* LPC 3:6 */
+	21,	/* LPC 2:3 */
+	4,	/* R0:0 */
+	25,	/* LPC 3:7 */
+	15,	/* LPC 1:0 */
+	94,	/* LAG 4:3 */
+	77,	/* LAG 3:2 */
+	59,	/* LAG 2:2 */
+	41,	/* LAG 1:2 */
+	3,	/* R0:1 */
+	76,	/* LAG 3:3 */
+	58,	/* LAG 2:3 */
+	40,	/* LAG 1:3 */
+	39,	/* LAG 1:4 */
+	17,	/* LPC 2:7 */
+	16,	/* LPC 2:8 */
+	12,	/* LPC 1:3 */
+	11,	/* LPC 1:4 */
+	10,	/* LPC 1:5 */
+	9,	/* LPC 1:6 */
+	2,	/* R0:2 */
+	38,	/* LAG 1:5 */
+	37,	/* LAG 1:6 */
+	36,	/* LAG 1:7 */
+	8,	/* LPC 1:7 */
+	7,	/* LPC 1:8 */
+	6,	/* LPC 1:9 */
+	5,	/* LPC 1:10 */
+	1,	/* R0:3 */
+	0,	/* R0:4 */
+	35,	/* Mode:0 */
+	34,	/* Mode:1 */
+	106,	/* Code 4:0 */
+	105,	/* Code 4:1 */
+	104,	/* Code 4:2 */
+	103,	/* Code 4:3 */
+	102,	/* Code 4:4 */
+	101,	/* Code 4:5 */
+	100,	/* Code 4:6 */
+	99,	/* Code 4:7 */
+	98,	/* Code 4:8 */
+	88,	/* Code 3:0 */
+	87,	/* Code 3:1 */
+	86,	/* Code 3:2 */
+	85,	/* Code 3:3 */
+	84,	/* Code 3:4 */
+	83,	/* Code 3:5 */
+	82,	/* Code 3:6 */
+	81,	/* Code 3:7 */
+};
+
+static inline uint16_t mask(const uint8_t msb)
+{
+	const uint16_t m = (uint16_t)1  << (msb - 1);
+	return (m - 1) ^ m;
+}
+
+/*! Check whether RTP frame contains HR SID code word according to
+ *  TS 101 318 §5.2.2
+ *  \param[in] rtp_payload Buffer with RTP payload
+ *  \param[in] payload_len Length of payload
+ *  \returns true if code word is found, false otherwise
+ */
+bool osmo_hr_check_sid(const uint8_t *rtp_payload, size_t payload_len)
+{
+	uint8_t i, bits[] = { 1, 2, 8, 9, 5, 4, 9, 5, 4, 9, 5, 4, 9, 5 };
+	struct bitvec bv;
+	bv.data = (uint8_t *) rtp_payload;
+	bv.data_len = payload_len;
+	bv.cur_bit = 33;
+
+	/* code word is all 1 at given bits, numbered from 1, MODE is always 3 */
+	for (i = 0; i < ARRAY_SIZE(bits); i++)
+		if (bitvec_get_uint(&bv, bits[i]) != mask(bits[i]))
+			return false;
+
+	return true;
+}
diff --git a/lib/decoding/osmocom/codec/gsm660.c b/lib/decoding/osmocom/codec/gsm660.c
new file mode 100644
index 0000000..4f7bb09
--- /dev/null
+++ b/lib/decoding/osmocom/codec/gsm660.c
@@ -0,0 +1,259 @@
+/*! \file gsm660.c
+ * GSM 06.60 - GSM EFR Codec. */
+/*
+ * (C) 2010 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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>
+#include <osmocom/codec/codec.h>
+
+/* GSM EFR - subjective importance bit ordering */
+	/* This array encodes GSM 05.03 Table 6.
+	 *
+	 * It converts between serial parameter output (as described in
+	 * GSM 06.60 Table 6 and GSM 05.03 Table 5) and the order needed
+	 * before channel encoding. CRC poly and bit repetition must be
+	 * applied prior to this table, as in GSM 05.03 3.1.1, to get 260
+	 * bits from a 244 bits raw EFR frame.
+	 */
+const uint16_t gsm660_bitorder[260] = {
+	 38,  39,  40,  41,  42,  43,		/*   0 -> LTP-LAG 1: b8..b3 */
+	145, 146, 147, 148, 149, 150,		/*   6 -> LTP-LAG 3: b8..b3 */
+	 93,  94,				/*  12 -> LTP-LAG 2: b5..b4 */
+	200, 201,				/*  14 -> LTP-LAG 4: b5..b4 */
+	 47,					/*  16 -> LTP-GAIN 1: b3    */
+	 88,					/*  17 -> FCB-GAIN 1: b4    */
+	 99,					/*  18 -> LTP-GAIN 2: b3    */
+	140,					/*  19 -> FCB-GAIN 2: b4    */
+	 44,					/*  20 -> LTP-LAG 1: b2     */
+	151,					/*  21 -> LTP-LAG 3: b2     */
+	 95,					/*  22 -> LTP-LAG 2: b3     */
+	202,					/*  23 -> LTP-LAG 4: b3     */
+	  1,   2,				/*  24 -> LPC 1: b5..b4     */
+	  7,					/*  26 -> LPC 2: b7         */
+	  9,					/*  27 -> LPC 2: b5         */
+	 17,  18,				/*  28 -> LPC 3: b6..b5     */
+	 23,					/*  30 -> LPC 3: b0         */
+	 45,  46,				/*  31 -> LTP-LAG 1: b1..b0 */
+	152, 153,				/*  33 -> LTP-LAG 3: b1..b0 */
+	 96,					/*  35 -> LTP-LAG 2: b2     */
+	203,					/*  36 -> LTP-LAG 4: b2     */
+	  3,   4,				/*  37 -> LPC 1: b3..b2     */
+	 10,  11,				/*  39 -> LPC 2: b4..b3     */
+	 15,					/*  41 -> LPC 3: b8         */
+	  8,					/*  42 -> LPC 2: b6         */
+	  5,   6,				/*  43 -> LPC 1: b1..b0     */
+	 12,					/*  45 -> LPC 2: b2         */
+	 16,					/*  46 -> LPC 3: b7         */
+	 19,					/*  47 -> LPC 3: b4         */
+	 97,					/*  48 -> LTP-LAG 2: b1     */
+	204,					/*  49 -> LTP-LAG 4: b1     */
+	  0,					/*  50 -> LPC 1: b6         */
+	 13,  14,				/*  51 -> LPC 2: b1..b0     */
+	 20,					/*  53 -> LPC 3: b3         */
+	 24,  25,				/*  54 -> LPC 4: b7..b6     */
+	 27,					/*  56 -> LPC 4: b4         */
+	154,					/*  57 -> LTP-GAIN 3: b3    */
+	206,					/*  58 -> LTP-GAIN 4: b3    */
+	195,					/*  59 -> FCB-GAIN 3: b4    */
+	247,					/*  60 -> FCB-GAIN 4: b4    */
+	 89,					/*  61 -> FCB-GAIN 1: b3    */
+	141,					/*  62 -> FCB-GAIN 2: b3    */
+	196,					/*  63 -> FCB-GAIN 3: b3    */
+	248,					/*  64 -> FCB-GAIN 4: b3    */
+	252, 253, 254, 255, 256, 257, 258, 259,	/*  65 -> CRC-POLY: b7..b0  */
+	 48,					/*  73 -> LTP-GAIN 1: b2    */
+	100,					/*  74 -> LTP-GAIN 2: b2    */
+	155,					/*  75 -> LTP-GAIN 3: b2    */
+	207,					/*  76 -> LTP-GAIN 4: b2    */
+	 21,  22,				/*  77 -> LPC 3: b2..b1     */
+	 26,					/*  79 -> LPC 4: b5         */
+	 28,					/*  80 -> LPC 4: b3         */
+	 51,					/*  81 -> PULSE 1_1: b3     */
+	 55,					/*  82 -> PULSE 1_2: b3     */
+	 59,					/*  83 -> PULSE 1_3: b3     */
+	 63,					/*  84 -> PULSE 1_4: b3     */
+	 67,					/*  85 -> PULSE 1_5: b3     */
+	103,					/*  86 -> PULSE 2_1: b3     */
+	107,					/*  87 -> PULSE 2_2: b3     */
+	111,					/*  88 -> PULSE 2_3: b3     */
+	115,					/*  89 -> PULSE 2_4: b3     */
+	119,					/*  90 -> PULSE 2_5: b3     */
+	158,					/*  91 -> PULSE 3_1: b3     */
+	162,					/*  92 -> PULSE 3_2: b3     */
+	166,					/*  93 -> PULSE 3_3: b3     */
+	170,					/*  94 -> PULSE 3_4: b3     */
+	174,					/*  95 -> PULSE 3_5: b3     */
+	210,					/*  96 -> PULSE 4_1: b3     */
+	214,					/*  97 -> PULSE 4_2: b3     */
+	218,					/*  98 -> PULSE 4_3: b3     */
+	222,					/*  99 -> PULSE 4_4: b3     */
+	226,					/* 100 -> PULSE 4_5: b3     */
+	 90,					/* 101 -> FCB-GAIN 1: b2    */
+	142,					/* 102 -> FCB-GAIN 2: b2    */
+	197,					/* 103 -> FCB-GAIN 3: b2    */
+	249,					/* 104 -> FCB-GAIN 4: b2    */
+	 49,					/* 105 -> LTP-GAIN 1: b1    */
+	101,					/* 106 -> LTP-GAIN 2: b1    */
+	156,					/* 107 -> LTP-GAIN 3: b1    */
+	208,					/* 108 -> LTP-GAIN 4: b1    */
+	 29,  30,  31,				/* 109 -> LPC 4: b2..b0     */
+	 32,  33,  34,  35,			/* 112 -> LPC 5: b5..b2     */
+	 98,					/* 116 -> LTP-LAG 2: b0     */
+	205,					/* 117 -> LTP-LAG 4: b0     */
+	 52,					/* 118 -> PULSE 1_1: b2     */
+	 56,					/* 119 -> PULSE 1_2: b2     */
+	 60,					/* 120 -> PULSE 1_3: b2     */
+	 64,					/* 121 -> PULSE 1_4: b2     */
+	 68,					/* 122 -> PULSE 1_5: b2     */
+	104,					/* 123 -> PULSE 2_1: b2     */
+	108,					/* 124 -> PULSE 2_2: b2     */
+	112,					/* 125 -> PULSE 2_3: b2     */
+	116,					/* 126 -> PULSE 2_4: b2     */
+	120,					/* 127 -> PULSE 2_5: b2     */
+	159,					/* 128 -> PULSE 3_1: b2     */
+	163,					/* 129 -> PULSE 3_2: b2     */
+	167,					/* 130 -> PULSE 3_3: b2     */
+	171,					/* 131 -> PULSE 3_4: b2     */
+	175,					/* 132 -> PULSE 3_5: b2     */
+	211,					/* 133 -> PULSE 4_1: b2     */
+	215,					/* 134 -> PULSE 4_2: b2     */
+	219,					/* 135 -> PULSE 4_3: b2     */
+	223,					/* 136 -> PULSE 4_4: b2     */
+	227,					/* 137 -> PULSE 4_5: b2     */
+	 53,					/* 138 -> PULSE 1_1: b1     */
+	 57,					/* 139 -> PULSE 1_2: b1     */
+	 61,					/* 140 -> PULSE 1_3: b1     */
+	 65,					/* 141 -> PULSE 1_4: b1     */
+	105,					/* 142 -> PULSE 2_1: b1     */
+	109,					/* 143 -> PULSE 2_2: b1     */
+	113,					/* 144 -> PULSE 2_3: b1     */
+	117,					/* 145 -> PULSE 2_4: b1     */
+	160,					/* 146 -> PULSE 3_1: b1     */
+	164,					/* 147 -> PULSE 3_2: b1     */
+	168,					/* 148 -> PULSE 3_3: b1     */
+	172,					/* 149 -> PULSE 3_4: b1     */
+	212,					/* 150 -> PULSE 4_1: b1     */
+	220,					/* 151 -> PULSE 4_3: b1     */
+	224,					/* 152 -> PULSE 4_4: b1     */
+	 91,					/* 153 -> FCB-GAIN 1: b1    */
+	143,					/* 154 -> FCB-GAIN 2: b1    */
+	198,					/* 155 -> FCB-GAIN 3: b1    */
+	250,					/* 156 -> FCB-GAIN 4: b1    */
+	 50,					/* 157 -> LTP-GAIN 1: b0    */
+	102,					/* 158 -> LTP-GAIN 2: b0    */
+	157,					/* 159 -> LTP-GAIN 3: b0    */
+	209,					/* 160 -> LTP-GAIN 4: b0    */
+	 92,					/* 161 -> FCB-GAIN 1: b0    */
+	144,					/* 162 -> FCB-GAIN 2: b0    */
+	199,					/* 163 -> FCB-GAIN 3: b0    */
+	251,					/* 164 -> FCB-GAIN 4: b0    */
+	 54,					/* 165 -> PULSE 1_1: b0     */
+	 58,					/* 166 -> PULSE 1_2: b0     */
+	 62,					/* 167 -> PULSE 1_3: b0     */
+	 66,					/* 168 -> PULSE 1_4: b0     */
+	106,					/* 169 -> PULSE 2_1: b0     */
+	110,					/* 170 -> PULSE 2_2: b0     */
+	114,					/* 171 -> PULSE 2_3: b0     */
+	118,					/* 172 -> PULSE 2_4: b0     */
+	161,					/* 173 -> PULSE 3_1: b0     */
+	165,					/* 174 -> PULSE 3_2: b0     */
+	169,					/* 175 -> PULSE 3_3: b0     */
+	173,					/* 176 -> PULSE 3_4: b0     */
+	213,					/* 177 -> PULSE 4_1: b0     */
+	221,					/* 178 -> PULSE 4_3: b0     */
+	225,					/* 179 -> PULSE 4_4: b0     */
+	 36,  37,				/* 180 -> LPC 5: b1..b0     */
+	 69,					/* 182 -> PULSE 1_5: b1     */
+	 71,  72,				/* 183 -> PULSE 1_5: b1..b1 */
+	121,					/* 185 -> PULSE 2_5: b1     */
+	123, 124,				/* 186 -> PULSE 2_5: b1..b1 */
+	176,					/* 188 -> PULSE 3_5: b1     */
+	178, 179,				/* 189 -> PULSE 3_5: b1..b1 */
+	228,					/* 191 -> PULSE 4_5: b1     */
+	230, 231,				/* 192 -> PULSE 4_5: b1..b1 */
+	216, 217,				/* 194 -> PULSE 4_2: b1..b0 */
+	 70,					/* 196 -> PULSE 1_5: b0     */
+	122,					/* 197 -> PULSE 2_5: b0     */
+	177,					/* 198 -> PULSE 3_5: b0     */
+	229,					/* 199 -> PULSE 4_5: b0     */
+	 73,					/* 200 -> PULSE 1_6: b2     */
+	 76,					/* 201 -> PULSE 1_7: b2     */
+	 79,					/* 202 -> PULSE 1_8: b2     */
+	 82,					/* 203 -> PULSE 1_9: b2     */
+	 85,					/* 204 -> PULSE 1_10: b2    */
+	125,					/* 205 -> PULSE 2_6: b2     */
+	128,					/* 206 -> PULSE 2_7: b2     */
+	131,					/* 207 -> PULSE 2_8: b2     */
+	134,					/* 208 -> PULSE 2_9: b2     */
+	137,					/* 209 -> PULSE 2_10: b2    */
+	180,					/* 210 -> PULSE 3_6: b2     */
+	183,					/* 211 -> PULSE 3_7: b2     */
+	186,					/* 212 -> PULSE 3_8: b2     */
+	189,					/* 213 -> PULSE 3_9: b2     */
+	192,					/* 214 -> PULSE 3_10: b2    */
+	232,					/* 215 -> PULSE 4_6: b2     */
+	235,					/* 216 -> PULSE 4_7: b2     */
+	238,					/* 217 -> PULSE 4_8: b2     */
+	241,					/* 218 -> PULSE 4_9: b2     */
+	244,					/* 219 -> PULSE 4_10: b2    */
+	 74,					/* 220 -> PULSE 1_6: b1     */
+	 77,					/* 221 -> PULSE 1_7: b1     */
+	 80,					/* 222 -> PULSE 1_8: b1     */
+	 83,					/* 223 -> PULSE 1_9: b1     */
+	 86,					/* 224 -> PULSE 1_10: b1    */
+	126,					/* 225 -> PULSE 2_6: b1     */
+	129,					/* 226 -> PULSE 2_7: b1     */
+	132,					/* 227 -> PULSE 2_8: b1     */
+	135,					/* 228 -> PULSE 2_9: b1     */
+	138,					/* 229 -> PULSE 2_10: b1    */
+	181,					/* 230 -> PULSE 3_6: b1     */
+	184,					/* 231 -> PULSE 3_7: b1     */
+	187,					/* 232 -> PULSE 3_8: b1     */
+	190,					/* 233 -> PULSE 3_9: b1     */
+	193,					/* 234 -> PULSE 3_10: b1    */
+	233,					/* 235 -> PULSE 4_6: b1     */
+	236,					/* 236 -> PULSE 4_7: b1     */
+	239,					/* 237 -> PULSE 4_8: b1     */
+	242,					/* 238 -> PULSE 4_9: b1     */
+	245,					/* 239 -> PULSE 4_10: b1    */
+	 75,					/* 240 -> PULSE 1_6: b0     */
+	 78,					/* 241 -> PULSE 1_7: b0     */
+	 81,					/* 242 -> PULSE 1_8: b0     */
+	 84,					/* 243 -> PULSE 1_9: b0     */
+	 87,					/* 244 -> PULSE 1_10: b0    */
+	127,					/* 245 -> PULSE 2_6: b0     */
+	130,					/* 246 -> PULSE 2_7: b0     */
+	133,					/* 247 -> PULSE 2_8: b0     */
+	136,					/* 248 -> PULSE 2_9: b0     */
+	139,					/* 249 -> PULSE 2_10: b0    */
+	182,					/* 250 -> PULSE 3_6: b0     */
+	185,					/* 251 -> PULSE 3_7: b0     */
+	188,					/* 252 -> PULSE 3_8: b0     */
+	191,					/* 253 -> PULSE 3_9: b0     */
+	194,					/* 254 -> PULSE 3_10: b0    */
+	234,					/* 255 -> PULSE 4_6: b0     */
+	237,					/* 256 -> PULSE 4_7: b0     */
+	240,					/* 257 -> PULSE 4_8: b0     */
+	243,					/* 258 -> PULSE 4_9: b0     */
+	246,					/* 259 -> PULSE 4_10: b0    */
+};
diff --git a/lib/decoding/osmocom/codec/gsm690.c b/lib/decoding/osmocom/codec/gsm690.c
new file mode 100644
index 0000000..1955716
--- /dev/null
+++ b/lib/decoding/osmocom/codec/gsm690.c
@@ -0,0 +1,318 @@
+/*! \file gsm690.c
+ * GSM 06.90 - GSM AMR Codec. */
+/*
+ * (C) 2010 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/codec/codec.h>
+/*
+ * These table map between the raw encoder parameter output and
+ * the format used before channel coding. Both in GSM and in various
+ * file/network format (same tables used in several specs).
+ */
+
+/* AMR 12.2 kbits - subjective importance bit ordering */
+	/* This array encodes GSM 05.03 Table 7
+	 * It's also TS 26.101 Table B.8
+	 */
+const uint16_t gsm690_12_2_bitorder[244] = {
+	  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
+	 10,  11,  12,  13,  14,  23,  15,  16,  17,  18,
+	 19,  20,  21,  22,  24,  25,  26,  27,  28,  38,
+	141,  39, 142,  40, 143,  41, 144,  42, 145,  43,
+	146,  44, 147,  45, 148,  46, 149,  47,  97, 150,
+	200,  48,  98, 151, 201,  49,  99, 152, 202,  86,
+	136, 189, 239,  87, 137, 190, 240,  88, 138, 191,
+	241,  91, 194,  92, 195,  93, 196,  94, 197,  95,
+	198,  29,  30,  31,  32,  33,  34,  35,  50, 100,
+	153, 203,  89, 139, 192, 242,  51, 101, 154, 204,
+	 55, 105, 158, 208,  90, 140, 193, 243,  59, 109,
+	162, 212,  63, 113, 166, 216,  67, 117, 170, 220,
+	 36,  37,  54,  53,  52,  58,  57,  56,  62,  61,
+	 60,  66,  65,  64,  70,  69,  68, 104, 103, 102,
+	108, 107, 106, 112, 111, 110, 116, 115, 114, 120,
+	119, 118, 157, 156, 155, 161, 160, 159, 165, 164,
+	163, 169, 168, 167, 173, 172, 171, 207, 206, 205,
+	211, 210, 209, 215, 214, 213, 219, 218, 217, 223,
+	222, 221,  73,  72,  71,  76,  75,  74,  79,  78,
+	 77,  82,  81,  80,  85,  84,  83, 123, 122, 121,
+	126, 125, 124, 129, 128, 127, 132, 131, 130, 135,
+	134, 133, 176, 175, 174, 179, 178, 177, 182, 181,
+	180, 185, 184, 183, 188, 187, 186, 226, 225, 224,
+	229, 228, 227, 232, 231, 230, 235, 234, 233, 238,
+	237, 236,  96, 199,
+};
+
+/* AMR 10.2 kbits - subjective importance bit ordering */
+	/* This array encodes GSM 05.03 Table 8
+	 * It's also TS 26.101 Table B.7
+	 */
+const uint16_t gsm690_10_2_bitorder[204] = {
+	  7,   6,   5,   4,   3,   2,   1,   0,  16,  15,
+	 14,  13,  12,  11,  10,   9,   8,  26,  27,  28,
+	 29,  30,  31, 115, 116, 117, 118, 119, 120,  72,
+	 73, 161, 162,  65,  68,  69, 108, 111, 112, 154,
+	157, 158, 197, 200, 201,  32,  33, 121, 122,  74,
+	 75, 163, 164,  66, 109, 155, 198,  19,  23,  21,
+	 22,  18,  17,  20,  24,  25,  37,  36,  35,  34,
+	 80,  79,  78,  77, 126, 125, 124, 123, 169, 168,
+	167, 166,  70,  67,  71, 113, 110, 114, 159, 156,
+	160, 202, 199, 203,  76, 165,  81,  82,  92,  91,
+	 93,  83,  95,  85,  84,  94, 101, 102,  96, 104,
+	 86, 103,  87,  97, 127, 128, 138, 137, 139, 129,
+	141, 131, 130, 140, 147, 148, 142, 150, 132, 149,
+	133, 143, 170, 171, 181, 180, 182, 172, 184, 174,
+	173, 183, 190, 191, 185, 193, 175, 192, 176, 186,
+	 38,  39,  49,  48,  50,  40,  52,  42,  41,  51,
+	 58,  59,  53,  61,  43,  60,  44,  54, 194, 179,
+	189, 196, 177, 195, 178, 187, 188, 151, 136, 146,
+	153, 134, 152, 135, 144, 145, 105,  90, 100, 107,
+	 88, 106,  89,  98,  99,  62,  47,  57,  64,  45,
+	 63,  46,  55,  56,
+};
+
+/* AMR 7.95 kbits - subjective importance bit ordering */
+	/* This array encodes GSM 05.03 Table 9
+	 * It's also TS 26.101 Table B.6
+	 */
+const uint16_t gsm690_7_95_bitorder[159] = {
+	  8,   7,   6,   5,   4,   3,   2,  14,  16,   9,
+	 10,  12,  13,  15,  11,  17,  20,  22,  24,  23,
+	 19,  18,  21,  56,  88, 122, 154,  57,  89, 123,
+	155,  58,  90, 124, 156,  52,  84, 118, 150,  53,
+	 85, 119, 151,  27,  93,  28,  94,  29,  95,  30,
+	 96,  31,  97,  61, 127,  62, 128,  63, 129,  59,
+	 91, 125, 157,  32,  98,  64, 130,   1,   0,  25,
+	 26,  33,  99,  34, 100,  65, 131,  66, 132,  54,
+	 86, 120, 152,  60,  92, 126, 158,  55,  87, 121,
+	153, 117, 116, 115,  46,  78, 112, 144,  43,  75,
+	109, 141,  40,  72, 106, 138,  36,  68, 102, 134,
+	114, 149, 148, 147, 146,  83,  82,  81,  80,  51,
+	 50,  49,  48,  47,  45,  44,  42,  39,  35,  79,
+	 77,  76,  74,  71,  67, 113, 111, 110, 108, 105,
+	101, 145, 143, 142, 140, 137, 133,  41,  73, 107,
+	139,  37,  69, 103, 135,  38,  70, 104, 136,
+};
+
+/* AMR 7.4 kbits - subjective importance bit ordering */
+	/* This array encodes GSM 05.03 Table 10
+	 * It's also TS 26.101 Table B.5
+	 */
+const uint16_t gsm690_7_4_bitorder[148] = {
+	  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
+	 10,  11,  12,  13,  14,  15,  16,  26,  87,  27,
+	 88,  28,  89,  29,  90,  30,  91,  51,  80, 112,
+	141,  52,  81, 113, 142,  54,  83, 115, 144,  55,
+	 84, 116, 145,  58, 119,  59, 120,  21,  22,  23,
+	 17,  18,  19,  31,  60,  92, 121,  56,  85, 117,
+	146,  20,  24,  25,  50,  79, 111, 140,  57,  86,
+	118, 147,  49,  78, 110, 139,  48,  77,  53,  82,
+	114, 143, 109, 138,  47,  76, 108, 137,  32,  33,
+	 61,  62,  93,  94, 122, 123,  41,  42,  43,  44,
+	 45,  46,  70,  71,  72,  73,  74,  75, 102, 103,
+	104, 105, 106, 107, 131, 132, 133, 134, 135, 136,
+	 34,  63,  95, 124,  35,  64,  96, 125,  36,  65,
+	 97, 126,  37,  66,  98, 127,  38,  67,  99, 128,
+	 39,  68, 100, 129,  40,  69, 101, 130,
+};
+
+/* AMR 6.7 kbits - subjective importance bit ordering */
+	/* This array encodes GSM 05.03 Table 11
+	 * It's also TS 26.101 Table B.4
+	 */
+const uint16_t gsm690_6_7_bitorder[134] = {
+	  0,   1,   4,   3,   5,   6,  13,   7,   2,   8,
+	  9,  11,  15,  12,  14,  10,  28,  82,  29,  83,
+	 27,  81,  26,  80,  30,  84,  16,  55, 109,  56,
+	110,  31,  85,  57, 111,  48,  73, 102, 127,  32,
+	 86,  51,  76, 105, 130,  52,  77, 106, 131,  58,
+	112,  33,  87,  19,  23,  53,  78, 107, 132,  21,
+	 22,  18,  17,  20,  24,  25,  50,  75, 104, 129,
+	 47,  72, 101, 126,  54,  79, 108, 133,  46,  71,
+	100, 125, 128, 103,  74,  49,  45,  70,  99, 124,
+	 42,  67,  96, 121,  39,  64,  93, 118,  38,  63,
+	 92, 117,  35,  60,  89, 114,  34,  59,  88, 113,
+	 44,  69,  98, 123,  43,  68,  97, 122,  41,  66,
+	 95, 120,  40,  65,  94, 119,  37,  62,  91, 116,
+	 36,  61,  90, 115,
+};
+
+/* AMR 5.9 kbits - subjective importance bit ordering */
+	/* This array encodes GSM 05.03 Table 12
+	 * It's also TS 26.101 Table B.3
+	 */
+const uint16_t gsm690_5_9_bitorder[118] = {
+	  0,   1,   4,   5,   3,   6,   7,   2,  13,  15,
+	  8,   9,  11,  12,  14,  10,  16,  28,  74,  29,
+	 75,  27,  73,  26,  72,  30,  76,  51,  97,  50,
+	 71,  96, 117,  31,  77,  52,  98,  49,  70,  95,
+	116,  53,  99,  32,  78,  33,  79,  48,  69,  94,
+	115,  47,  68,  93, 114,  46,  67,  92, 113,  19,
+	 21,  23,  22,  18,  17,  20,  24, 111,  43,  89,
+	110,  64,  65,  44,  90,  25,  45,  66,  91, 112,
+	 54, 100,  40,  61,  86, 107,  39,  60,  85, 106,
+	 36,  57,  82, 103,  35,  56,  81, 102,  34,  55,
+	 80, 101,  42,  63,  88, 109,  41,  62,  87, 108,
+	 38,  59,  84, 105,  37,  58,  83, 104,
+};
+
+/* AMR 5.15 kbits - subjective importance bit ordering */
+	/* This array encodes GSM 05.03 Table 13
+	 * It's also TS 26.101 Table B.2
+	 */
+const uint16_t gsm690_5_15_bitorder[103] = {
+	  7,   6,   5,   4,   3,   2,   1,   0,  15,  14,
+	 13,  12,  11,  10,   9,   8,  23,  24,  25,  26,
+	 27,  46,  65,  84,  45,  44,  43,  64,  63,  62,
+	 83,  82,  81, 102, 101, 100,  42,  61,  80,  99,
+	 28,  47,  66,  85,  18,  41,  60,  79,  98,  29,
+	 48,  67,  17,  20,  22,  40,  59,  78,  97,  21,
+	 30,  49,  68,  86,  19,  16,  87,  39,  38,  58,
+	 57,  77,  35,  54,  73,  92,  76,  96,  95,  36,
+	 55,  74,  93,  32,  51,  33,  52,  70,  71,  89,
+	 90,  31,  50,  69,  88,  37,  56,  75,  94,  34,
+	 53,  72,  91,
+};
+
+/* AMR 4.75 kbits - subjective importance bit ordering */
+	/* This array encodes GSM 05.03 Table 14
+	 * It's also TS 26.101 Table B.1
+	 */
+const uint16_t gsm690_4_75_bitorder[95] = {
+	  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
+	 10,  11,  12,  13,  14,  15,  23,  24,  25,  26,
+	 27,  28,  48,  49,  61,  62,  82,  83,  47,  46,
+	 45,  44,  81,  80,  79,  78,  17,  18,  20,  22,
+	 77,  76,  75,  74,  29,  30,  43,  42,  41,  40,
+	 38,  39,  16,  19,  21,  50,  51,  59,  60,  63,
+	 64,  72,  73,  84,  85,  93,  94,  32,  33,  35,
+	 36,  53,  54,  56,  57,  66,  67,  69,  70,  87,
+	 88,  90,  91,  34,  55,  68,  89,  37,  58,  71,
+	 92,  31,  52,  65,  86,
+};
+
+static const uint8_t amr_len_by_ft[16] = {
+	12, 13, 15, 17, 19, 20, 26, 31, 7,  0,  0,  0,  0,  0,  0,  0
+};
+
+const struct value_string osmo_amr_type_names[] = {
+	{ AMR_4_75,		"AMR 4,75 kbits/s" },
+	{ AMR_5_15,		"AMR 5,15 kbit/s" },
+	{ AMR_5_90,		"AMR 5,90 kbit/s" },
+	{ AMR_6_70,		"AMR 6,70 kbit/s (PDC-EFR)" },
+	{ AMR_7_40,		"AMR 7,40 kbit/s (TDMA-EFR)" },
+	{ AMR_7_95,		"AMR 7,95 kbit/s" },
+	{ AMR_10_2,		"AMR 10,2 kbit/s" },
+	{ AMR_12_2,		"AMR 12,2 kbit/s (GSM-EFR)" },
+	{ AMR_SID,		"AMR SID" },
+	{ AMR_GSM_EFR_SID,	"GSM-EFR SID" },
+	{ AMR_TDMA_EFR_SID,	"TDMA-EFR SID" },
+	{ AMR_PDC_EFR_SID,	"PDC-EFR SID" },
+	{ AMR_NO_DATA,		"No Data/NA" },
+	{ 0,			NULL },
+};
+
+/*! Decode various AMR parameters from RTP payload (RFC 4867) acording to
+ *         3GPP TS 26.101
+ *  \param[in] rtppayload Payload from RTP packet
+ *  \param[in] payload_len length of rtppayload
+ *  \param[out] cmr AMR Codec Mode Request, not filled if NULL
+ *  \param[out] cmi AMR Codec Mode Indicator, -1 if not applicable for this type,
+ *              not filled if NULL
+ *  \param[out] ft AMR Frame Type, not filled if NULL
+ *  \param[out] bfi AMR Bad Frame Indicator, not filled if NULL
+ *  \param[out] sti AMR SID Type Indicator, -1 if not applicable for this type,
+ *              not filled if NULL
+ *  \returns length of AMR data or negative value on error
+ */
+int osmo_amr_rtp_dec(const uint8_t *rtppayload, int payload_len, uint8_t *cmr,
+		     int8_t *cmi, enum osmo_amr_type *ft,
+		     enum osmo_amr_quality *bfi, int8_t *sti)
+{
+	if (payload_len < 2 || !rtppayload)
+		return -EINVAL;
+
+	/* RFC 4867 § 4.4.2 ToC - compound payloads are not supported: F = 0 */
+	uint8_t type = (rtppayload[1] >> 3) & 0xf;
+
+	/* compound payloads are not supported */
+	if (rtppayload[1] >> 7)
+		return -ENOTSUP;
+
+	if (payload_len < amr_len_by_ft[type])
+		return -ENOTSUP;
+
+	if (ft)
+		*ft = type;
+
+	if (cmr)
+		*cmr = rtppayload[0] >> 4;
+
+	if (bfi)
+		*bfi = (rtppayload[1] >> 2) & 1;
+
+	/* Table 6 in 3GPP TS 26.101 */
+	if (cmi)
+		*cmi = (type == AMR_SID) ? ((rtppayload[6] >> 1) & 7) : -1;
+
+	if (sti)
+		*sti = (type == AMR_SID) ? (rtppayload[6] & 0x10) : -1;
+
+	return 2 + amr_len_by_ft[type];
+}
+
+/*! Encode various AMR parameters from RTP payload (RFC 4867)
+ *  \param[out] payload Payload for RTP packet, contains speech data (if any)
+ *              except for have 2 first bytes where header will be built
+ *  \param[in] cmr AMR codec Mode Request
+ *  \param[in] ft AMR Frame Type
+ *  \param[in] bfi AMR Bad Frame Indicator
+ *  \returns length of AMR data (header + ToC + speech data) or negative value
+ *           on error
+ *
+ *  Note: only octet-aligned mode is supported so the header occupies 2 full
+ *  bytes. Optional interleaving header is not supported.
+ */
+int osmo_amr_rtp_enc(uint8_t *payload, uint8_t cmr, enum osmo_amr_type ft,
+		     enum osmo_amr_quality bfi)
+{
+	if (cmr > 15)
+		return -EINVAL;
+
+	if (ft > 15)
+		return -ENOTSUP;
+
+	/* RFC 4867 § 4.3.1 payload header */
+	payload[0] = cmr << 4;
+
+	/* RFC 4867 § 4.4.2 ToC - compound payloads are not supported: F = 0 */
+	payload[1] = (((uint8_t)ft) << 3) | (((uint8_t)bfi) << 2);
+
+	/* speech data */
+	return 2 + amr_len_by_ft[ft];
+}