diff options
author | Alfred E. Heggestad <aeh@db.org> | 2016-04-24 16:06:20 +0200 |
---|---|---|
committer | Alfred E. Heggestad <aeh@db.org> | 2016-04-24 16:06:20 +0200 |
commit | 936a29e4eb8deac34fd902cd84653f5411f6f768 (patch) | |
tree | 248fb218393c4c42f0cfe266b922efe3767f5af5 | |
parent | 488fa550651037a7e7f7ff21a4a11369ab3afec2 (diff) | |
parent | 1081461b418ef49943be1adae8752ad41052ef87 (diff) |
Merge pull request #125 from choene/master
Added support for MPA coding
-rw-r--r-- | docs/README | 1 | ||||
-rw-r--r-- | mk/modules.mk | 11 | ||||
-rw-r--r-- | modules/mpa/decode.c | 199 | ||||
-rw-r--r-- | modules/mpa/encode.c | 175 | ||||
-rw-r--r-- | modules/mpa/module.mk | 14 | ||||
-rw-r--r-- | modules/mpa/mpa.c | 201 | ||||
-rw-r--r-- | modules/mpa/mpa.h | 35 | ||||
-rw-r--r-- | modules/mpa/sdp.c | 55 | ||||
-rw-r--r-- | src/audio.c | 47 |
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)); } |