diff options
author | Harald Welte <laforge@gnumonks.org> | 2017-05-28 11:04:26 +0200 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2017-05-28 14:29:59 +0200 |
commit | 8b01f0ca05d92c593d9f33e40bae3f6dbb78a521 (patch) | |
tree | 1feb93efd06b9d1f920da49bcad764dc1f570b9f | |
parent | 494d92c3c7c2197381807f999d9d2a6ba23299e4 (diff) |
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
-rw-r--r-- | include/gapk/codecs.h | 1 | ||||
-rw-r--r-- | include/gapk/formats.h | 4 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/codec_amr.c | 121 | ||||
-rw-r--r-- | src/codecs.c | 2 | ||||
-rw-r--r-- | src/fmt_amr_opencore.c | 51 | ||||
-rw-r--r-- | src/fmt_rtp_amr.c | 60 | ||||
-rw-r--r-- | src/formats.c | 4 |
8 files changed, 245 insertions, 2 deletions
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 @@ enum codec_type { 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 @@ enum format_type { 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 @@ AM_LDFLAGS=$(LIBOSMOCODEC_LIBS) $(LIBOSMOCORE_LIBS) \ 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_pcm_desc; 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 @@ codec_get_from_type(enum codec_type type) 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_rawpcm_s16le; 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 @@ static const struct format_desc *supported_formats[_FMT_MAX] = { [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, }; |