summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlfred E. Heggestad <aeh@db.org>2016-04-24 16:06:20 +0200
committerAlfred E. Heggestad <aeh@db.org>2016-04-24 16:06:20 +0200
commit936a29e4eb8deac34fd902cd84653f5411f6f768 (patch)
tree248fb218393c4c42f0cfe266b922efe3767f5af5
parent488fa550651037a7e7f7ff21a4a11369ab3afec2 (diff)
parent1081461b418ef49943be1adae8752ad41052ef87 (diff)
Merge pull request #125 from choene/master
Added support for MPA coding
-rw-r--r--docs/README1
-rw-r--r--mk/modules.mk11
-rw-r--r--modules/mpa/decode.c199
-rw-r--r--modules/mpa/encode.c175
-rw-r--r--modules/mpa/module.mk14
-rw-r--r--modules/mpa/mpa.c201
-rw-r--r--modules/mpa/mpa.h35
-rw-r--r--modules/mpa/sdp.c55
-rw-r--r--src/audio.c47
9 files changed, 721 insertions, 17 deletions
diff --git a/docs/README b/docs/README
index d7d0a04..1a6f9be 100644
--- a/docs/README
+++ b/docs/README
@@ -69,6 +69,7 @@ Features:
- Opus
- Silk
- Speex
+ - MPA
* Audio-drivers:
- Advanced Linux Sound Architecture (ALSA) audio-driver
diff --git a/mk/modules.mk b/mk/modules.mk
index 8695814..1475247 100644
--- a/mk/modules.mk
+++ b/mk/modules.mk
@@ -30,6 +30,7 @@
# USE_ISAC iSAC audio codec
# USE_L16 L16 audio codec
# USE_LIBSRTP Secure RTP module using libsrtp
+# USE_MPA MPA audo codec
# USE_MPG123 Use mpg123
# USE_OPUS Opus audio codec
# USE_OSS OSS audio driver
@@ -147,6 +148,13 @@ ifeq ($(HAVE_SPEEXDSP),)
HAVE_SPEEXDSP := \
$(shell find $(SYSROOT)/lib -name libspeexdsp$(LIB_SUFFIX) 2>/dev/null)
endif
+ifneq ($(USE_MPG123),)
+ifneq ($(HAVE_SPEEXDSP),)
+USE_MPA := $(shell [ -f $(SYSROOT)/include/twolame.h ] || \
+ [ -f $(SYSROOT)/local/include/twolame.h ] || \
+ [ -f $(SYSROOT_ALT)/include/twolame.h ] && echo "yes")
+endif
+endif
USE_SPEEX := $(shell [ -f $(SYSROOT)/include/speex.h ] || \
[ -f $(SYSROOT)/include/speex/speex.h ] || \
[ -f $(SYSROOT)/local/include/speex.h ] || \
@@ -346,6 +354,9 @@ endif
ifneq ($(USE_OPUS),)
MODULES += opus
endif
+ifneq ($(USE_MPA),)
+MODULES += mpa
+endif
ifneq ($(USE_OSS),)
MODULES += oss
endif
diff --git a/modules/mpa/decode.c b/modules/mpa/decode.c
new file mode 100644
index 0000000..d62bd60
--- /dev/null
+++ b/modules/mpa/decode.c
@@ -0,0 +1,199 @@
+/**
+ * @file mpa/decode.c mpa Decode
+ *
+ * Copyright (C) 2016 Symonics GmbH
+ */
+
+#include <re.h>
+#include <baresip.h>
+#include <mpg123.h>
+#include <speex/speex_resampler.h>
+#include <string.h>
+#include "mpa.h"
+
+struct audec_state {
+ mpg123_handle *dec;
+ SpeexResamplerState *resampler;
+ int channels;
+ int16_t intermediate_buffer[MPA_FRAMESIZE*2];
+ int start;
+};
+
+
+static void destructor(void *arg)
+{
+ struct audec_state *ads = arg;
+
+ mpg123_close(ads->dec);
+ mpg123_delete(ads->dec);
+#ifdef DEBUG
+ debug("mpa: decoder destroyed\n");
+#endif
+}
+
+
+int mpa_decode_update(struct audec_state **adsp, const struct aucodec *ac,
+ const char *fmtp)
+{
+ struct audec_state *ads;
+ int result, err=0;
+
+ if (!adsp || !ac || !ac->ch)
+ return EINVAL;
+
+ ads = *adsp;
+
+#ifdef DEBUG
+ debug("mpa: decoder created %s\n",fmtp);
+#endif
+
+ if (ads)
+ mem_deref(ads);
+
+ ads = mem_zalloc(sizeof(*ads), destructor);
+ if (!ads)
+ return ENOMEM;
+ ads->channels = 0;
+ ads->resampler = NULL;
+ ads->start = 0;
+
+ ads->dec = mpg123_new(NULL,&result);
+ if (!ads->dec) {
+ error("mpa: decoder create: %s\n",
+ mpg123_plain_strerror(result));
+ err = ENOMEM;
+ goto out;
+ }
+
+#ifdef DEBUG
+ result = mpg123_param(ads->dec, MPG123_VERBOSE, 4, 4.);
+#else
+ result = mpg123_param(ads->dec, MPG123_VERBOSE, 0, 0.);
+#endif
+ if (result != MPG123_OK) {
+ error("MPA libmpg123 param error %s",
+ mpg123_plain_strerror(result));
+ err = EINVAL;
+ goto out;
+ }
+
+
+ result = mpg123_format_all(ads->dec);
+ if (result != MPG123_OK) {
+ error("MPA libmpg123 format error %s",
+ mpg123_plain_strerror(result));
+ err = EINVAL;
+ goto out;
+ }
+
+ result = mpg123_open_feed(ads->dec);
+ if (result != MPG123_OK) {
+ error("MPA libmpg123 open feed error %s",
+ mpg123_plain_strerror(result));
+ err = EINVAL;
+ goto out;
+ }
+
+
+ out:
+ if (err)
+ mem_deref(ads);
+ else
+ *adsp = ads;
+
+ return err;
+}
+
+
+int mpa_decode_frm(struct audec_state *ads, int16_t *sampv, size_t *sampc,
+ const uint8_t *buf, size_t len)
+{
+ int result, channels, encoding, i;
+ long samplerate;
+ size_t n;
+ spx_uint32_t intermediate_len;
+ spx_uint32_t out_len;
+
+ if (!ads || !sampv || !sampc || !buf || len<=4)
+ return EINVAL;
+
+ if(*(uint32_t*)buf != 0) {
+ error("MPA header is not zero %08X, not supported yet\n",
+ *(uint32_t*)buf);
+ return EPROTO;
+ }
+
+ if (ads->resampler) {
+ result = mpg123_decode(ads->dec, buf+4, len-4,
+ (unsigned char*)ads->intermediate_buffer,
+ sizeof(ads->intermediate_buffer), &n);
+ /* n counts bytes */
+ intermediate_len = n / 2 / ads->channels;
+ /* intermediate_len counts samples per channel */
+ out_len = *sampc;
+ result=speex_resampler_process_interleaved_int(
+ ads->resampler, ads->intermediate_buffer,
+ &intermediate_len, sampv, &out_len);
+ if (result!=RESAMPLER_ERR_SUCCESS) {
+ error("mpa: upsample error: %s %d %d\n",
+ strerror(result), out_len, *sampc/2);
+ return EPROTO;
+ }
+#ifdef DEBUG
+ info("mpa decode %d %d %d %d\n",intermediate_len,*sampc,
+ out_len,n);
+#endif
+ *sampc = out_len * ads->channels;
+ }
+ else {
+ result = mpg123_decode(ads->dec, buf+4, len-4,
+ (unsigned char*)sampv, *sampc*2, &n);
+#ifdef DEBUG
+ info("mpa decode %d %d\n",*sampc,n);
+#endif
+ *sampc = n / 2;
+ }
+
+ if (ads->start<100) { /* mpg123 needs some to sync */
+ ads->start++;
+ *sampc=0;
+ }
+ if (ads->channels==1) {
+ for (i=*sampc-1;i>=0;i--)
+ sampv[i+i+1]=sampv[i+i]=sampv[i];
+ *sampc *= 2;
+ }
+
+ if (result == MPG123_NEW_FORMAT) {
+ mpg123_getformat(ads->dec, &samplerate, &channels, &encoding);
+ info("MPA libmpg123 format change %d %d %04X\n",samplerate
+ ,channels,encoding);
+
+ ads->channels = channels;
+ ads->start = 0;
+ if (samplerate != 48000) {
+ ads->resampler = speex_resampler_init(channels,
+ samplerate, 48000, 3, &result);
+ if (result!=RESAMPLER_ERR_SUCCESS
+ || ads->resampler==NULL) {
+ error("mpa: upsampler failed %d\n",result);
+ return EINVAL;
+ }
+ }
+ else
+ ads->resampler = NULL;
+ }
+ else if (result == MPG123_NEED_MORE)
+ return 0;
+ else if (result != MPG123_OK) {
+ error("MPA libmpg123 feed error %d %s", result,
+ mpg123_plain_strerror(result));
+ return EPROTO;
+ }
+
+#ifdef DEBUG
+ debug("mpa decode %d %d %d\n",*sampc,len,n);
+#endif
+ return 0;
+}
+
diff --git a/modules/mpa/encode.c b/modules/mpa/encode.c
new file mode 100644
index 0000000..6ed6493
--- /dev/null
+++ b/modules/mpa/encode.c
@@ -0,0 +1,175 @@
+/**
+ * @file mpa/encode.c mpa Encode
+ *
+ * Copyright (C) 2016 Symonics GmbH
+ */
+
+#include <re.h>
+#include <baresip.h>
+#include <twolame.h>
+#include <string.h>
+#include <speex/speex_resampler.h>
+#include "mpa.h"
+
+struct auenc_state {
+ twolame_options *enc;
+ int channels;
+ SpeexResamplerState *resampler;
+ int16_t intermediate_buffer[BARESIP_FRAMESIZE];
+};
+
+
+static void destructor(void *arg)
+{
+ struct auenc_state *aes = arg;
+
+ if (aes->enc)
+ twolame_close(&aes->enc);
+#ifdef DEBUG
+ debug("mpa: encoder destroyed\n");
+#endif
+}
+
+int mpa_encode_update(struct auenc_state **aesp, const struct aucodec *ac,
+ struct auenc_param *param, const char *fmtp)
+{
+ struct auenc_state *aes;
+ struct mpa_param prm;
+ int result,err=0;
+
+ (void)param;
+
+ if (!aesp || !ac || !ac->ch)
+ return EINVAL;
+
+ aes = *aesp;
+ if (aes) {
+ info("ever?");
+ mem_deref(aes);
+ }
+
+ aes = mem_zalloc(sizeof(*aes), destructor);
+ aes->enc = twolame_init();
+ if (!aes->enc) {
+ error("mpa: encoder create failed");
+ mem_deref(aes);
+ return ENOMEM;
+ }
+ aes->channels = ac->ch;
+#ifdef DEBUG
+ debug("mpa: encoder created %s\n",fmtp);
+#endif
+
+ prm.samplerate = 32000;
+ prm.bitrate = 128000;
+ prm.layer = 2;
+ prm.mode = SINGLE_CHANNEL;
+ mpa_decode_fmtp(&prm, fmtp);
+
+ result = 0;
+#ifdef DEBUG
+ result |= twolame_set_verbosity(aes->enc, 5);
+#else
+ result |= twolame_set_verbosity(aes->enc, 0);
+#endif
+
+ result |= twolame_set_mode(aes->enc,
+ prm.mode == SINGLE_CHANNEL ? TWOLAME_MONO :
+ prm.mode == DUAL_CHANNEL ? TWOLAME_DUAL_CHANNEL :
+ prm.mode == JOINT_STEREO ? TWOLAME_JOINT_STEREO :
+ prm.mode == STEREO ? TWOLAME_STEREO : TWOLAME_AUTO_MODE);
+ result |= twolame_set_version(aes->enc,
+ prm.samplerate < 32000 ? TWOLAME_MPEG2 : TWOLAME_MPEG1);
+ result |= twolame_set_bitrate(aes->enc, prm.bitrate/1000);
+ result |= twolame_set_in_samplerate(aes->enc, prm.samplerate);
+ result |= twolame_set_out_samplerate(aes->enc, prm.samplerate);
+ result |= twolame_set_num_channels(aes->enc, 2);
+ if (result!=0) {
+ error("mpa: encoder set failed\n");
+ err=EINVAL;
+ goto out;
+ }
+
+ result = twolame_init_params(aes->enc);
+ if (result!=0) {
+ error("mpa: encoder init params failed\n");
+ err=EINVAL;
+ goto out;
+ }
+
+ twolame_print_config(aes->enc);
+
+ if (prm.samplerate != 48000) {
+ aes->resampler = speex_resampler_init(2, 48000,
+ prm.samplerate, 3, &result);
+ if (result!=RESAMPLER_ERR_SUCCESS) {
+ error("mpa: resampler init failed %d\n",result);
+ err=EINVAL;
+ goto out;
+ }
+
+ }
+ else
+ aes->resampler = NULL;
+
+out:
+ if (err)
+ mem_deref(aes);
+ else
+ *aesp = aes;
+
+ return err;
+}
+
+
+int mpa_encode_frm(struct auenc_state *aes, uint8_t *buf, size_t *len,
+ const int16_t *sampv, size_t sampc)
+{
+ int n;
+ spx_uint32_t intermediate_len,in_len;
+
+ if (!aes || !buf || !len || !sampv)
+ return EINVAL;
+
+ if (aes->resampler) {
+ in_len = sampc/2;
+ intermediate_len = sizeof(aes->intermediate_buffer)
+ / sizeof(aes->intermediate_buffer[0]);
+ n=speex_resampler_process_interleaved_int(aes->resampler,
+ sampv, &in_len, aes->intermediate_buffer,
+ &intermediate_len);
+ if (n!=RESAMPLER_ERR_SUCCESS || in_len != sampc/2) {
+ warning("mpa: downsample error: %s %d %d\n",
+ strerror(n), in_len, sampc/2);
+ return EPROTO;
+ }
+ n = twolame_encode_buffer_interleaved(aes->enc,
+ aes->intermediate_buffer, intermediate_len,
+ buf+4, (*len)-4);
+#ifdef DEBUG
+ debug("mpa encode %d %d %d %d %d\n",intermediate_len,sampc,
+ aes->channels,*len,n);
+#endif
+ }
+ else
+ n = twolame_encode_buffer_interleaved(aes->enc, sampv,
+ (int)(sampc/2), buf+4, (*len)-4);
+
+ if (n < 0) {
+ error("mpa: encode error: %s\n", strerror((int)n));
+ return EPROTO;
+ }
+
+ if (n > 0) {
+ *(uint32_t*)buf = 0;
+ *len = n+4;
+ }
+ else
+ *len = 0;
+
+#ifdef DEBUG
+ debug("mpa encode %d %d %d %d\n",sampc,aes->channels,*len,n);
+#endif
+ return 0;
+}
+
diff --git a/modules/mpa/module.mk b/modules/mpa/module.mk
new file mode 100644
index 0000000..b060f12
--- /dev/null
+++ b/modules/mpa/module.mk
@@ -0,0 +1,14 @@
+#
+# module.mk
+#
+# Copyright (C) 2016 Symonics GmbH
+#
+
+MOD := mpa
+$(MOD)_SRCS += mpa.c
+$(MOD)_SRCS += decode.c
+$(MOD)_SRCS += sdp.c
+$(MOD)_SRCS += encode.c
+$(MOD)_LFLAGS += -ltwolame -lmpg123 -lspeexdsp -lm
+
+include mk/mod.mk
diff --git a/modules/mpa/mpa.c b/modules/mpa/mpa.c
new file mode 100644
index 0000000..88ebfbe
--- /dev/null
+++ b/modules/mpa/mpa.c
@@ -0,0 +1,201 @@
+/**
+ * @file mpa.c mpa Audio Codec
+ *
+ * Copyright (C) 2016 Symonics GmbH
+ */
+
+#include <re.h>
+#include <baresip.h>
+#include <ctype.h>
+#include <string.h>
+#include "mpa.h"
+#include <mpg123.h>
+
+/**
+ * @defgroup mpa mpa
+ *
+ * The mpa audio codec
+ *
+ * Supported version:
+ * libmpg123 1.16.0 or later
+ * libtwolame 0.3.13 or later
+ *
+ * References:
+ *
+ * RFC 2250 RTP Payload Format for the mpa Speech and Audio Codec
+ *
+ */
+
+/*
+4.1.17. Registration of MIME media type audio/MPA
+
+ MIME media type name: audio
+
+ MIME subtype name: MPA (MPEG audio)
+
+ Required parameters: None
+
+ Optional parameters:
+ layer: which layer of MPEG audio encoding; permissible values
+ are 1, 2, 3.
+
+ samplerate: the rate at which audio is sampled. MPEG-1 audio
+ supports sampling rates of 32, 44.1, and 48 kHz; MPEG-2
+ supports sampling rates of 16, 22.05 and 24 kHz. This parameter
+ is separate from the RTP timestamp clock rate which is always
+ 90000 Hz for MPA.
+
+ mode: permissible values are "stereo", "joint_stereo",
+ "single_channel", "dual_channel". The "channels" parameter
+ does not apply to MPA. It is undefined to put a number of
+ channels in the SDP rtpmap attribute for MPA.
+
+ bitrate: the data rate for the audio bit stream.
+
+ ptime: RECOMMENDED duration of each packet in milliseconds.
+
+ maxptime: maximum duration of each packet in milliseconds.
+
+ Parameters which are omitted are left to the encoder to choose
+ based on the session bandwidth, configuration information, or
+ other constraints. The selected layer as well as the sampling
+ rate and mode are indicated in the payload so receivers can
+ process the data without these parameters being specified
+ externally.
+
+ Encoding considerations:
+ This type is only defined for transfer via RTP [RFC 3550].
+
+ Security considerations: See Section 5 of RFC 3555
+
+ Interoperability considerations: none
+
+ Published specification: RFC 3551
+
+ Applications which use this media type:
+ Audio and video streaming and conferencing tools.
+
+*/
+
+
+static struct aucodec mpa = {
+ .pt = NULL, /* for the time being, to cope
+with AVT AC1 interop problems, we do not use "14" here */
+ .name = "MPA",
+ .srate = 90000,
+ .ch = 1,
+ .fmtp = "",
+ .encupdh = mpa_encode_update,
+ .ench = mpa_encode_frm,
+ .decupdh = mpa_decode_update,
+ .dech = mpa_decode_frm,
+};
+
+
+static int module_init(void)
+{
+ struct conf *conf = conf_cur();
+ uint32_t value;
+ static char fmtp[256];
+ static char mode[30];
+ int res;
+
+ /** generate fmtp string based on config file */
+
+ strcpy(mode,mpa.fmtp);
+
+ if (0 == conf_get_u32(conf, "mpa_bitrate", &value)) {
+ if (value<8000 || value>384000) {
+ error("MPA bitrate between 8000 and "
+ "384000 are allowed.");
+ return -1;
+ }
+
+ (void)re_snprintf(fmtp+strlen(fmtp),
+ sizeof(fmtp)-strlen(fmtp),
+ "; bitrate=%d", value);
+ }
+ if (0 == conf_get_u32(conf, "mpa_layer", &value)) {
+ if (value<1 || value>4) {
+ error("MPA layer 1, 2 or 3 are allowed.");
+ return -1;
+ }
+ (void)re_snprintf(fmtp+strlen(fmtp),
+ sizeof(fmtp)-strlen(fmtp),
+ "; layer=%d", value);
+ }
+ if (0 == conf_get_u32(conf, "mpa_samplerate", &value)) {
+ switch (value) {
+ case 32000:
+ case 44100:
+ case 48000:
+ case 16000:
+ case 22050:
+ case 24000:
+ break;
+ default:
+ error("MPA samplerates of 16, 22.05, 24, 32, "
+ "44.1, and 48 kHz are allowed.");
+ return -1;
+ }
+ (void)re_snprintf(fmtp+strlen(fmtp),
+ sizeof(fmtp)-strlen(fmtp),
+ "; samplerate=%d", value);
+ }
+ if (0 == conf_get_str(conf, "mpa_mode", mode, sizeof(mode))) {
+ char *p = mode;
+ while (*p) {
+ *p = tolower(*p);
+ ++p;
+ }
+
+ if (strcmp(mode,"stereo")
+ && strcmp(mode,"joint_stereo")
+ && strcmp(mode,"single_channel")
+ && strcmp(mode,"dual_channel")) {
+ error("MPA mode: Permissible values are stereo, "
+ "joint_stereo, single_channel, dual_channel");
+ return -1;
+ }
+
+ (void)re_snprintf(fmtp+strlen(fmtp),
+ sizeof(fmtp)-strlen(fmtp),
+ "; mode=%s", mode);
+ }
+
+ if (fmtp[0]==';' && fmtp[1]==' ')
+ mpa.fmtp = fmtp+2;
+ else
+ mpa.fmtp = fmtp;
+
+ /* init decoder library */
+ res = mpg123_init();
+ if (res != MPG123_OK) {
+ error("MPA libmpg123 init error %s",
+ mpg123_plain_strerror(res));
+ return -1;
+ }
+
+ aucodec_register(&mpa);
+
+ return 0;
+}
+
+
+static int module_close(void)
+{
+ aucodec_unregister(&mpa);
+
+ mpg123_exit();
+
+ return 0;
+}
+
+
+EXPORT_SYM const struct mod_export DECL_EXPORTS(mpa) = {
+ "MPA",
+ "audio codec",
+ module_init,
+ module_close,
+};
+
diff --git a/modules/mpa/mpa.h b/modules/mpa/mpa.h
new file mode 100644
index 0000000..35055b6
--- /dev/null
+++ b/modules/mpa/mpa.h
@@ -0,0 +1,35 @@
+/**
+ * @file mpa.h Private mpa Interface
+ *
+ * Copyright (C) 2016 Symonics GmbH
+ */
+
+#define MPA_FRAMESIZE 1152
+#define BARESIP_FRAMESIZE (48000/50*2)
+
+#undef DEBUG
+
+struct mpa_param {
+ unsigned samplerate;
+ unsigned bitrate;
+ unsigned layer;
+ enum { AUTO=0, STEREO, JOINT_STEREO, SINGLE_CHANNEL, DUAL_CHANNEL }
+ mode;
+};
+
+
+/* Encode */
+int mpa_encode_update(struct auenc_state **aesp, const struct aucodec *ac,
+ struct auenc_param *prm, const char *fmtp);
+int mpa_encode_frm(struct auenc_state *aes, uint8_t *buf, size_t *len,
+ const int16_t *sampv, size_t sampc);
+
+
+/* Decode */
+int mpa_decode_update(struct audec_state **adsp, const struct aucodec *ac,
+ const char *fmtp);
+int mpa_decode_frm(struct audec_state *ads, int16_t *sampv, size_t *sampc,
+ const uint8_t *buf, size_t len);
+
+/* SDP */
+void mpa_decode_fmtp(struct mpa_param *prm, const char *fmtp);
diff --git a/modules/mpa/sdp.c b/modules/mpa/sdp.c
new file mode 100644
index 0000000..363b72c
--- /dev/null
+++ b/modules/mpa/sdp.c
@@ -0,0 +1,55 @@
+/**
+ * @file mpa/sdp.c mpa SDP Functions
+ *
+ * Copyright (C) 2016 Symonics GmbH
+ */
+
+#include <re.h>
+#include <baresip.h>
+#include <string.h>
+#include "mpa.h"
+
+
+static void assign_if (uint32_t *v, const struct pl *pl,
+ uint32_t min, uint32_t max)
+{
+ const uint32_t val = pl_u32(pl);
+
+ if (val < min || val > max)
+ return;
+
+ *v = val;
+}
+
+
+void mpa_decode_fmtp(struct mpa_param *prm, const char *fmtp)
+{
+ struct pl pl, val;
+
+ if (!prm || !fmtp)
+ return;
+
+ pl_set_str(&pl, fmtp);
+
+ if (fmt_param_get(&pl, "bitrate", &val))
+ assign_if (&prm->bitrate, &val, 8000, 384000);
+
+ if (fmt_param_get(&pl, "samplerate", &val))
+ assign_if (&prm->samplerate, &val, 16000, 48000);
+
+ if (fmt_param_get(&pl, "layer", &val))
+ assign_if (&prm->layer, &val, 1, 3);
+
+ if (fmt_param_get(&pl, "mode", &val)) {
+
+ if (!strncmp("stereo",pl.p,pl.l))
+ prm->mode = STEREO;
+ else if (!strncmp("joint_stereo",pl.p,pl.l))
+ prm->mode = JOINT_STEREO;
+ else if (!strncmp("single_channel",pl.p,pl.l))
+ prm->mode = SINGLE_CHANNEL;
+ else if (!strncmp("dual_channel",pl.p,pl.l))
+ prm->mode = DUAL_CHANNEL;
+ }
+}
+
diff --git a/src/audio.c b/src/audio.c
index c8996f2..47b4c36 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -53,7 +53,7 @@
*/
enum {
- AUDIO_SAMPSZ = 1920,
+ AUDIO_SAMPSZ = 6*1152,
};
@@ -92,6 +92,7 @@ struct autx {
size_t psize; /**< Packet size for sending */
bool marker; /**< Marker bit for outgoing RTP */
bool is_g722; /**< Set if encoder is G.722 codec */
+ bool is_mpa; /**< Set if encoder is MPA codec */
bool muted; /**< Audio source is muted */
int cur_key; /**< Currently transmitted event */
@@ -240,14 +241,25 @@ static inline uint32_t calc_nsamp(uint32_t srate, uint8_t channels,
/**
- * Get the DSP samplerate for an audio-codec (exception for G.722)
+ * Get the DSP samplerate for an audio-codec (exception for G.722 and MPA)
*/
static inline uint32_t get_srate(const struct aucodec *ac)
{
if (!ac)
return 0;
- return !str_casecmp(ac->name, "G722") ? 16000 : ac->srate;
+ return !str_casecmp(ac->name, "G722") ? 16000 : !str_casecmp(ac->name, "MPA") ? 48000 : ac->srate;
+}
+
+/**
+ * Get the DSP samplerate for an audio-codec (exception for G.722)
+ */
+static inline uint32_t get_ch(const struct aucodec *ac)
+{
+ if (!ac)
+ return 0;
+
+ return !str_casecmp(ac->name, "MPA") ? 2 : ac->ch;
}
@@ -257,7 +269,7 @@ static inline uint32_t get_framesize(const struct aucodec *ac,
if (!ac)
return 0;
- return calc_nsamp(get_srate(ac), ac->ch, ptime);
+ return calc_nsamp(get_srate(ac), get_ch(ac), ptime);
}
@@ -279,9 +291,9 @@ static int add_audio_codec(struct audio *a, struct sdp_media *m,
return 0;
}
- if (!in_range(&a->cfg.channels, ac->ch)) {
+ if (!in_range(&a->cfg.channels, get_ch(ac))) {
debug("audio: skip codec with %uch (audio range %uch-%uch)\n",
- ac->ch, a->cfg.channels.min, a->cfg.channels.max);
+ get_ch(ac), a->cfg.channels.min, a->cfg.channels.max);
return 0;
}
@@ -334,7 +346,7 @@ static void encode_rtp_send(struct audio *a, struct autx *tx,
/* The RTP clock rate used for generating the RTP timestamp is
* independent of the number of channels and the encoding
*/
- frame_size = (tx->is_g722 ? sampc/2 : sampc) / tx->ac->ch;
+ frame_size = (tx->is_g722 ? sampc/2 : tx->is_mpa ? sampc*90/48 : sampc) / get_ch(tx->ac);
tx->ts += (uint32_t)frame_size;
@@ -793,7 +805,7 @@ static void aufilt_param_set(struct aufilt_prm *prm,
}
prm->srate = get_srate(ac);
- prm->ch = ac->ch;
+ prm->ch = get_ch(ac);
prm->ptime = ptime;
}
@@ -922,7 +934,7 @@ static int start_player(struct aurx *rx, struct audio *a)
if (!ac)
return 0;
- channels_dsp = ac->ch;
+ channels_dsp = get_ch(ac);
if (a->cfg.srate_play && a->cfg.srate_play != srate_dsp) {
resamp = true;
@@ -938,14 +950,14 @@ static int start_player(struct aurx *rx, struct audio *a)
info("audio: enable auplay resampler:"
" %uHz/%uch --> %uHz/%uch\n",
- get_srate(ac), ac->ch, srate_dsp, channels_dsp);
+ get_srate(ac), get_ch(ac), srate_dsp, channels_dsp);
rx->sampv_rs = mem_zalloc(AUDIO_SAMPSZ * 2, NULL);
if (!rx->sampv_rs)
return ENOMEM;
err = auresamp_setup(&rx->resamp,
- get_srate(ac), ac->ch,
+ get_srate(ac), get_ch(ac),
srate_dsp, channels_dsp);
if (err) {
warning("audio: could not setup auplay resampler"
@@ -1000,7 +1012,7 @@ static int start_source(struct autx *tx, struct audio *a)
if (!ac)
return 0;
- channels_dsp = ac->ch;
+ channels_dsp = get_ch(ac);
if (a->cfg.srate_src && a->cfg.srate_src != srate_dsp) {
resamp = true;
@@ -1016,7 +1028,7 @@ static int start_source(struct autx *tx, struct audio *a)
info("audio: enable ausrc resampler:"
" %uHz/%uch <-- %uHz/%uch\n",
- get_srate(ac), ac->ch, srate_dsp, channels_dsp);
+ get_srate(ac), get_ch(ac), srate_dsp, channels_dsp);
tx->sampv_rs = mem_zalloc(AUDIO_SAMPSZ * 2, NULL);
if (!tx->sampv_rs)
@@ -1024,7 +1036,7 @@ static int start_source(struct autx *tx, struct audio *a)
err = auresamp_setup(&tx->resamp,
srate_dsp, channels_dsp,
- get_srate(ac), ac->ch);
+ get_srate(ac), get_ch(ac));
if (err) {
warning("audio: could not setup ausrc resampler"
" (%m)\n", err);
@@ -1169,7 +1181,7 @@ int audio_encoder_set(struct audio *a, const struct aucodec *ac,
if (ac != tx->ac) {
info("audio: Set audio encoder: %s %uHz %dch\n",
- ac->name, get_srate(ac), ac->ch);
+ ac->name, get_srate(ac), get_ch(ac));
/* Audio source must be stopped first */
if (reset) {
@@ -1177,6 +1189,7 @@ int audio_encoder_set(struct audio *a, const struct aucodec *ac,
}
tx->is_g722 = (0 == str_casecmp(ac->name, "G722"));
+ tx->is_mpa = (0 == str_casecmp(ac->name, "MPA"));
tx->enc = mem_deref(tx->enc);
tx->ac = ac;
}
@@ -1221,7 +1234,7 @@ int audio_decoder_set(struct audio *a, const struct aucodec *ac,
if (ac != rx->ac) {
info("audio: Set audio decoder: %s %uHz %dch\n",
- ac->name, get_srate(ac), ac->ch);
+ ac->name, get_srate(ac), get_ch(ac));
rx->pt = pt_rx;
rx->ac = ac;
@@ -1370,7 +1383,7 @@ static int aucodec_print(struct re_printf *pf, const struct aucodec *ac)
if (!ac)
return 0;
- return re_hprintf(pf, "%s %uHz/%dch", ac->name, get_srate(ac), ac->ch);
+ return re_hprintf(pf, "%s %uHz/%dch", ac->name, get_srate(ac), get_ch(ac));
}