diff options
Diffstat (limited to 'modules/mpa/encode.c')
-rw-r--r-- | modules/mpa/encode.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/modules/mpa/encode.c b/modules/mpa/encode.c new file mode 100644 index 0000000..1195844 --- /dev/null +++ b/modules/mpa/encode.c @@ -0,0 +1,141 @@ +/** + * @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; +}; + + +static void destructor(void *arg) +{ + struct auenc_state *aes = arg; + + if (aes->enc) + twolame_close(&aes->enc); +} + +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; + const struct aucodec *auc = aucodec_find("MPA", 90000, 1); + int mpares; + + (void)param; + + if (!aesp || !ac || !ac->ch) + return EINVAL; + + aes = *aesp; + + if (!aes) { + aes = mem_zalloc(sizeof(*aes), destructor); + aes->enc = twolame_init(); + if (!aes->enc) { + warning("mpa: encoder create failed"); + mem_deref(aes); + return ENOMEM; + } + aes->channels = auc->ch; + *aesp = aes; + } + + prm.samplerate = 32000; + prm.bitrate = 128000; + prm.layer = 2; + prm.mode = STEREO; + mpa_decode_fmtp(&prm, fmtp); + + mpares = 0; + mpares |= twolame_set_verbosity(aes->enc, 5); + mpares |= 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); + mpares |= twolame_set_version(aes->enc, prm.samplerate < 32000 ? TWOLAME_MPEG2 : TWOLAME_MPEG1); + mpares |= twolame_set_bitrate(aes->enc, prm.bitrate/1000); + mpares |= twolame_set_in_samplerate(aes->enc, prm.samplerate); + mpares |= twolame_set_out_samplerate(aes->enc, prm.samplerate); + mpares |= twolame_set_num_channels(aes->enc, 2); + if(mpares!=0) { + warning("mpa: encoder set failed\n"); + return EINVAL; + } + + twolame_print_config(aes->enc); + + mpares = twolame_init_params(aes->enc); + if(mpares!=0) { + warning("mpa: encoder init params failed\n"); + return EINVAL; + } + + if(prm.samplerate != 48000) { + aes->resampler = speex_resampler_init(2, 48000, prm.samplerate, 3, &mpares); + if(mpares!=RESAMPLER_ERR_SUCCESS) { + warning("mpa: resampler init failed %d\n",mpares); + return EINVAL; + } + + } + else + aes->resampler = NULL; + return 0; +} + + +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 ds_len,in_len; + static int16_t ds[1920]; + + if (!aes || !buf || !len || !sampv) + return EINVAL; + + if(aes->resampler) { + in_len = sampc/2; + n=speex_resampler_process_interleaved_int(aes->resampler, sampv, &in_len, ds, &ds_len); + if (n!=RESAMPLER_ERR_SUCCESS || in_len != sampc/2) { + warning("mpa: downsample error: %s\n", strerror(n)); + return EPROTO; + } + n = twolame_encode_buffer_interleaved(aes->enc, ds, ds_len/2, + buf+4, (*len)-4); + warning("mpa encode %d %d %d %d %d\n",ds_len,sampc,aes->channels,*len,n); + } + else + n = twolame_encode_buffer_interleaved(aes->enc, sampv, (int)(sampc/2), + buf+4, (*len)-4); + + if (n < 0) { + warning("mpa: encode error: %s\n", strerror((int)n)); + return EPROTO; + } + + if(n > 0) { + *(uint32_t*)buf = 0; + *len = n+4; + } + else + *len = 0; + +// warning("mpa encode %d %d %d %d\n",sampc,aes->channels,*len,n); + return 0; +} + |