Add AMR codec support

After merging this change, there is support for the AMR codec (by means
of libopencore-amr, which is already used for EFR).

In terms of gapk formats, we introdude
* the "amr-opencore" format, which serves both as the canonical format,
  and as the input format to opencore-amrnb itself.
* the "rtp-amr" format, which is the payload of RFC4867 octet-aligned mode

You can use the following command for a real-time RTP playback for AMR
frames:
  ./gapk -I 0.0.0.0/30000 -f rtp-amr -A default -g rawpcm-s16le
diff --git a/include/gapk/codecs.h b/include/gapk/codecs.h
index 00c34b5..f62cb25 100644
--- a/include/gapk/codecs.h
+++ b/include/gapk/codecs.h
@@ -33,6 +33,7 @@
 	CODEC_HR,	/* GSM Half Rate codec GSM 06.20 */
 	CODEC_FR,	/* GSM Full Rate codec GSM 06.10 */
 	CODEC_EFR,	/* GSM Enhanced Full Rate codec GSM 06.60 */
+	CODEC_AMR,	/* GSM Adaptive Multi Rate codec GSM 26.071 */
 	_CODEC_MAX,
 };
 
diff --git a/include/gapk/formats.h b/include/gapk/formats.h
index 4b2418a..e010713 100644
--- a/include/gapk/formats.h
+++ b/include/gapk/formats.h
@@ -48,6 +48,10 @@
 	FMT_TI_FR,
 	FMT_TI_EFR,
 
+	/* AMR encoded data, variable length */
+	FMT_AMR_OPENCORE,
+	FMT_RTP_AMR,
+
 	_FMT_MAX,
 };
 
diff --git a/src/Makefile.am b/src/Makefile.am
index e33a490..07f1d51 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,8 +6,8 @@
 
 COM_SOURCES = procqueue.c pq_file.c pq_format.c pq_codec.c pq_rtp.c pq_alsa.c \
 		formats.c fmt_amr.c fmt_gsm.c fmt_hr_ref.c fmt_racal.c \
-			fmt_rawpcm.c fmt_ti.c benchmark.c \
-		codecs.c codec_pcm.c codec_hr.c codec_fr.c codec_efr.c
+		fmt_amr_opencore.c fmt_rtp_amr.c fmt_rawpcm.c fmt_ti.c benchmark.c \
+		codecs.c codec_pcm.c codec_hr.c codec_fr.c codec_efr.c codec_amr.c
 
 bin_PROGRAMS = gapk
 
diff --git a/src/codec_amr.c b/src/codec_amr.c
new file mode 100644
index 0000000..9922ece
--- /dev/null
+++ b/src/codec_amr.c
@@ -0,0 +1,121 @@
+/* AMR (GSM 06.90) codec */
+/* (C) 2017 Harald Welte <laforge@gnumonks.org> */
+
+/*
+ * This file is part of gapk (GSM Audio Pocket Knife).
+ *
+ * gapk 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gapk 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 gapk.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gapk/codecs.h>
+#include <gapk/benchmark.h>
+
+#include "config.h"
+
+
+#ifdef HAVE_OPENCORE_AMRNB
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <opencore-amrnb/interf_dec.h>
+#include <opencore-amrnb/interf_enc.h>
+
+struct codec_amr_state {
+	void *encoder;
+	void *decoder;
+};
+
+
+static void *
+codec_amr_init(void)
+{
+	struct codec_amr_state *st;
+
+	st = calloc(1, sizeof(*st));
+	if (!st)
+		return NULL;
+
+	st->encoder = Encoder_Interface_init(0);
+	st->decoder = Decoder_Interface_init();
+
+	return (void *)st;
+}
+
+static void
+codec_amr_exit(void *state)
+{
+	struct codec_amr_state *st = state;
+
+	Decoder_Interface_exit(st->decoder);
+	Encoder_Interface_exit(st->encoder);
+
+	return;
+}
+
+static int
+codec_amr_encode(void *state, uint8_t *cod, const uint8_t *pcm, unsigned int pcm_len)
+{
+	struct codec_amr_state *st = state;
+	int rv;
+
+	BENCHMARK_START;
+	rv = Encoder_Interface_Encode(
+		st->encoder,
+		MR122,
+		(const short*) pcm,
+		(unsigned char*) cod,
+		1
+	);
+	BENCHMARK_STOP(CODEC_EFR, 1);
+
+	return rv;
+}
+
+static int
+codec_amr_decode(void *state, uint8_t *pcm, const uint8_t *cod, unsigned int cod_len)
+{
+	struct codec_amr_state *st = state;
+
+	printf("%s(): %u bytes in\n", __func__, cod_len);
+
+	BENCHMARK_START;
+	Decoder_Interface_Decode(
+		st->decoder,
+		(const unsigned char*) cod,
+		(short *) pcm,
+		0
+	);
+	BENCHMARK_STOP(CODEC_EFR, 0);
+
+	return PCM_CANON_LEN;
+}
+
+#endif /* HAVE_OPENCORE_AMRNB */
+
+
+const struct codec_desc codec_amr_desc = {
+	.type = CODEC_AMR,
+	.name = "amr",
+	.description = "GSM 26.071 Adaptive Multi Rate codec",
+	.canon_frame_len = 0,
+#ifdef HAVE_OPENCORE_AMRNB
+	.codec_enc_format_type = FMT_AMR_OPENCORE,
+	.codec_dec_format_type = FMT_AMR_OPENCORE,
+	.codec_init = codec_amr_init,
+	.codec_exit = codec_amr_exit,
+	.codec_encode = codec_amr_encode,
+	.codec_decode = codec_amr_decode,
+#endif
+};
diff --git a/src/codecs.c b/src/codecs.c
index 7a9a6d3..623e80c 100644
--- a/src/codecs.c
+++ b/src/codecs.c
@@ -26,6 +26,7 @@
 extern const struct codec_desc codec_hr_desc;
 extern const struct codec_desc codec_fr_desc;
 extern const struct codec_desc codec_efr_desc;
+extern const struct codec_desc codec_amr_desc;
 
 
 const struct codec_desc *
@@ -36,6 +37,7 @@
 	case CODEC_HR:	return &codec_hr_desc;
 	case CODEC_FR:	return &codec_fr_desc;
 	case CODEC_EFR:	return &codec_efr_desc;
+	case CODEC_AMR:	return &codec_amr_desc;
 	default:
 		return NULL;
 	}
diff --git a/src/fmt_amr_opencore.c b/src/fmt_amr_opencore.c
new file mode 100644
index 0000000..3fa547b
--- /dev/null
+++ b/src/fmt_amr_opencore.c
@@ -0,0 +1,51 @@
+/* Input format to libopencore-amrnb: Exactly like our canonical AMR */
+/* (C) 2017 Harald Welte <laforge@gnumonks.org> */
+
+/*
+ * This file is part of gapk (GSM Audio Pocket Knife).
+ *
+ * gapk 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gapk 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 gapk.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <gapk/codecs.h>
+#include <gapk/formats.h>
+#include <gapk/utils.h>
+
+static int
+amr_opencore_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
+{
+	memcpy(dst, src, src_len);
+	return src_len;
+}
+
+static int
+amr_opencore_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
+{
+	memcpy(dst, src, src_len);
+	return src_len;
+}
+
+const struct format_desc fmt_amr_opencore = {
+	.type			= FMT_AMR_OPENCORE,
+	.codec_type		= CODEC_AMR,
+	.name			= "amr-opencore",
+	.description		= "Input format to libopencore-amrnb",
+
+	.frame_len		= 0,
+	.conv_from_canon	= amr_opencore_from_canon,
+	.conv_to_canon		= amr_opencore_to_canon,
+};
diff --git a/src/fmt_rtp_amr.c b/src/fmt_rtp_amr.c
new file mode 100644
index 0000000..1d5357d
--- /dev/null
+++ b/src/fmt_rtp_amr.c
@@ -0,0 +1,60 @@
+/* AMR RTP Payload according to RFC4867. Only one codec frame per RTP */
+/* (C) 2017 by Harald Welte <laforge@gnumonks.org> */
+
+/*
+ * This file is part of gapk (GSM Audio Pocket Knife).
+ *
+ * gapk 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gapk 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 gapk.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <osmocom/codec/codec.h>
+
+#include <gapk/codecs.h>
+#include <gapk/formats.h>
+#include <gapk/utils.h>
+
+/* conversion function: RTP payload -> canonical format */
+static int
+rtp_amr_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
+{
+	/* add Payload Header according to RFC4867 4.4.1 */
+	dst[0] = 0xf0;	/* no request */
+	memcpy(dst+1, src, src_len);
+
+	return src_len+1;
+}
+
+/* conversion function: canonical format -> RTP payload */
+static int
+rtp_amr_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
+{
+	/* skip Payload Header according to RFC4867 4.4.1 */
+	memcpy(dst, src+1, src_len-1);
+
+	return src_len-1;
+}
+
+const struct format_desc fmt_rtp_amr = {
+	.type			= FMT_RTP_AMR,
+	.codec_type		= CODEC_AMR,
+	.name			= "rtp-amr",
+	.description		= "RTP payload for AMR according to RFC4867",
+
+	.frame_len		= 0,
+	.conv_from_canon	= rtp_amr_from_canon,
+	.conv_to_canon		= rtp_amr_to_canon,
+};
diff --git a/src/formats.c b/src/formats.c
index c776115..0d4c4a0 100644
--- a/src/formats.c
+++ b/src/formats.c
@@ -34,6 +34,8 @@
 extern const struct format_desc fmt_ti_hr;
 extern const struct format_desc fmt_ti_fr;
 extern const struct format_desc fmt_ti_efr;
+extern const struct format_desc fmt_amr_opencore;
+extern const struct format_desc fmt_rtp_amr;
 
 static const struct format_desc *supported_formats[_FMT_MAX] = {
 	[FMT_INVALID]		= NULL,
@@ -48,6 +50,8 @@
 	[FMT_TI_HR]		= &fmt_ti_hr,
 	[FMT_TI_FR]		= &fmt_ti_fr,
 	[FMT_TI_EFR]		= &fmt_ti_efr,
+	[FMT_AMR_OPENCORE]	= &fmt_amr_opencore,
+	[FMT_RTP_AMR]		= &fmt_rtp_amr,
 };