[asterisk-commits] dvossel: branch dvossel/opus_codec_ftw r329737 - /team/dvossel/opus_codec_ftw...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Jul 27 13:23:18 CDT 2011
Author: dvossel
Date: Wed Jul 27 13:23:14 2011
New Revision: 329737
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=329737
Log:
opus translator
Added:
team/dvossel/opus_codec_ftw/codecs/codec_opus.c (with props)
Modified:
team/dvossel/opus_codec_ftw/codecs/Makefile
Modified: team/dvossel/opus_codec_ftw/codecs/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/opus_codec_ftw/codecs/Makefile?view=diff&rev=329737&r1=329736&r2=329737
==============================================================================
--- team/dvossel/opus_codec_ftw/codecs/Makefile (original)
+++ team/dvossel/opus_codec_ftw/codecs/Makefile Wed Jul 27 13:23:14 2011
@@ -63,3 +63,6 @@
$(if $(filter codec_resample,$(EMBEDDED_MODS)),modules.link,codec_resample.so): speex/resample.o
speex/resample.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,codec_resample) $(SPEEX_RESAMPLE_CFLAGS)
+
+$(if $(filter codec_opus,$(EMBEDDED_MODS)),modules.link,codec_opus.so): speex/resample.o /usr/local/lib/libopus.so
+speex/resample.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,codec_resample) $(SPEEX_RESAMPLE_CFLAGS)
Added: team/dvossel/opus_codec_ftw/codecs/codec_opus.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/opus_codec_ftw/codecs/codec_opus.c?view=auto&rev=329737
==============================================================================
--- team/dvossel/opus_codec_ftw/codecs/codec_opus.c (added)
+++ team/dvossel/opus_codec_ftw/codecs/codec_opus.c Wed Jul 27 13:23:14 2011
@@ -1,0 +1,404 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2011, Digium, Inc.
+ *
+ * David Vossel <dvossel at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Translate between signed linear and OPUS (Open Codec)
+ *
+ * \ingroup codecs
+ *
+ * \extref The OPUS library - http://www.opus-codec.org
+ *
+ */
+
+#include "asterisk.h"
+#include "speex/speex_resampler.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <opus/opus.h> /* TODO make build system aware of this header */
+
+#include "asterisk/translate.h"
+#include "asterisk/module.h"
+#include "asterisk/utils.h"
+#include "asterisk/linkedlists.h"
+
+#define OUTBUF_SIZE 8096
+
+#define MAX_ENC_RETURN_FRAMES 8
+
+#define DEFAULT_TIME_PERIOD 20
+
+static struct ast_translator *translators;
+static int trans_size;
+
+/* This is the list of signed linear formats we can
+ * translate OPUS to and from in one step */
+static int id_list[] = {
+ AST_FORMAT_SLINEAR,
+ AST_FORMAT_SLINEAR12,
+ AST_FORMAT_SLINEAR16,
+ AST_FORMAT_SLINEAR24,
+ AST_FORMAT_SLINEAR32,
+ AST_FORMAT_SLINEAR44,
+ AST_FORMAT_SLINEAR48,
+ AST_FORMAT_SLINEAR96,
+};
+
+struct opus_encoder_pvt {
+ int init;
+ OpusEncoder *enc;
+ SpeexResamplerState *resamp;
+
+ /* slin input buffer. Samples go into this buffer before being feed to encoder */
+ int16_t slin_buf[OUTBUF_SIZE];
+ /* Current number of samples in our slin input buffer */
+ unsigned slin_samples;
+ /* The number of slin samples to encode at a time */
+ unsigned int frame_size;
+ /* OPUS output sample rate */
+ unsigned int sample_rate;
+
+ /*! Number of current valid out frame buffers */
+ unsigned int frame_offsets_num;
+ /*! The current number of bytes stored in the frame offsets. */
+ unsigned int frame_offsets_numbytes;
+ /* Pointers to the beginning of each valid outframe */
+ struct {
+ unsigned char *buf;
+ unsigned int len;
+ } frame_offsets[MAX_ENC_RETURN_FRAMES];
+};
+struct opus_decoder_pvt {
+ int init;
+ OpusDecoder *dec;
+ SpeexResamplerState *resamp;
+ unsigned int frame_size;
+ int16_t slin_buf[OUTBUF_SIZE];
+ unsigned slin_samples;
+};
+
+static int opus_enc_set(struct ast_trans_pvt *pvt, struct ast_format *slin_src)
+{
+ struct opus_encoder_pvt *enc = pvt->pvt;
+ int slin_rate = ast_format_rate(slin_src);
+ int opus_rate = slin_rate;
+ int error = 0;
+
+ if (pvt->explicit_dst.id) {
+ opus_rate = ast_format_rate(&pvt->explicit_dst);
+ }
+
+ if (slin_rate != opus_rate) {
+ if (!(enc->resamp = speex_resampler_init(1, slin_rate, opus_rate, 5, &error))) {
+ return -1;
+ }
+ }
+
+ if (!(enc->enc = opus_encoder_create(slin_rate, 1, OPUS_APPLICATION_VOIP))) {
+ ast_log(LOG_WARNING, "Failed to create OPUS encoder\n");
+ speex_resampler_destroy(enc->resamp);
+ return -1;
+ }
+
+ enc->frame_size = opus_rate / (1000 / DEFAULT_TIME_PERIOD);
+ enc->sample_rate = opus_rate;
+
+ enc->init = 1;
+
+ return 0;
+}
+
+static int opus_dec_set(struct ast_trans_pvt *pvt, struct ast_format *opus_src)
+{
+ struct opus_decoder_pvt *dec = pvt->pvt;
+ int opus_rate = ast_format_rate(opus_src);
+ int slin_rate = ast_format_rate(&pvt->t->dst_format);
+ int error = 0;
+
+ if (slin_rate != opus_rate) {
+ if (!(dec->resamp = speex_resampler_init(1, opus_rate, slin_rate, 5, &error))) {
+ return -1;
+ }
+ }
+
+ if (!(dec->dec = opus_decoder_create(opus_rate, 1))) {
+ ast_log(LOG_WARNING, "Failed to create OPUS decoder.\n");
+ speex_resampler_destroy(dec->resamp);
+ return -1;
+ }
+
+ dec->frame_size = opus_rate / (1000 / DEFAULT_TIME_PERIOD);
+ dec->init = 1;
+
+ return 0;
+}
+
+static void opus_enc_destroy(struct ast_trans_pvt *pvt)
+{
+ struct opus_encoder_pvt *enc = pvt->pvt;
+
+ if (enc->enc) {
+ opus_encoder_destroy(enc->enc);
+ enc->enc = NULL;
+ }
+ if (enc->resamp) {
+ speex_resampler_destroy(enc->resamp);
+ }
+}
+
+static void opus_dec_destroy(struct ast_trans_pvt *pvt)
+{
+ struct opus_decoder_pvt *dec = pvt->pvt;
+
+ if (dec->dec) {
+ opus_decoder_destroy(dec->dec);
+ dec->dec = NULL;
+ }
+ if (dec->resamp) {
+ speex_resampler_destroy(dec->resamp);
+ }
+}
+
+static int opus_enc_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
+{
+ struct opus_encoder_pvt *enc = pvt->pvt;
+ int16_t *slin_data;
+ unsigned char *opus_data;
+ int num_bytes = 0;
+
+ if (!enc->init) {
+ opus_enc_set(pvt, &f->subclass.format);
+ }
+
+ if (!f->datalen) {
+ return -1;
+ }
+
+ /* bring the slin to the native opus rate we want to encode */
+ if (enc->resamp) {
+ unsigned int in_samples = f->samples;
+ unsigned int out_samples = OUTBUF_SIZE - enc->slin_samples;
+ speex_resampler_process_int(enc->resamp,
+ 0,
+ f->data.ptr,
+ &in_samples,
+ enc->slin_buf + enc->slin_samples,
+ &out_samples);
+
+ enc->slin_samples += out_samples;
+ } else {
+ memcpy(enc->slin_buf + enc->slin_samples, f->data.ptr, f->datalen);
+ enc->slin_samples += (f->datalen / 2);
+ }
+
+ slin_data = enc->slin_buf;
+ opus_data = (unsigned char *) pvt->outbuf.c;
+
+ for ( ; enc->slin_samples >= enc->frame_size; enc->slin_samples -= enc->frame_size) {
+ num_bytes = opus_encode(enc->enc, slin_data, enc->frame_size, opus_data, enc->frame_offsets_numbytes);
+
+ if (num_bytes <= 0) {
+ /* err */
+ break;
+ }
+
+ if (enc->frame_offsets_num >= MAX_ENC_RETURN_FRAMES) {
+ break;
+ }
+
+ enc->frame_offsets[enc->frame_offsets_num].buf = opus_data;
+ enc->frame_offsets[enc->frame_offsets_num].len = num_bytes;
+ enc->frame_offsets_num++;
+ enc->frame_offsets_numbytes += num_bytes;
+
+ pvt->samples += enc->frame_size;
+
+ slin_data += enc->frame_size; /* increments by int16_t samples */
+ opus_data += num_bytes; /* increments by bytes */
+ }
+
+ return 0;
+}
+
+static struct ast_frame *opus_enc_frameout(struct ast_trans_pvt *pvt)
+{
+ struct opus_encoder_pvt *enc = pvt->pvt;
+ struct ast_frame *frame = NULL;
+ struct ast_frame *cur = NULL;
+ struct ast_frame tmp;
+ int i;
+
+ for (i = 0; i < enc->frame_offsets_num; i++) {
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.frametype = AST_FRAME_VOICE;
+ if (pvt->explicit_dst.id) {
+ ast_format_copy(&tmp.subclass.format, &pvt->explicit_dst);
+ } else {
+ ast_format_set(&tmp.subclass.format, AST_FORMAT_OPUS,
+ OPUS_ATTR_KEY_SAMP_RATE, enc->sample_rate);
+ }
+ tmp.datalen = enc->frame_offsets[i].len;
+ tmp.data.ptr = enc->frame_offsets[i].buf;
+ tmp.samples = enc->frame_size;
+ tmp.src = pvt->t->name;
+ tmp.offset = AST_FRIENDLY_OFFSET;
+
+ if (frame) {
+ AST_LIST_NEXT(cur, frame_list) = ast_frisolate(&tmp);
+ cur = AST_LIST_NEXT(cur, frame_list);
+ } else {
+ frame = ast_frisolate(&tmp);
+ cur = frame;
+ }
+ }
+
+
+ pvt->samples = 0;
+ memset(enc->frame_offsets, 0, sizeof(enc->frame_offsets));
+ enc->frame_offsets_num = 0;
+ return frame;
+}
+
+
+static int opus_dec_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
+{
+ struct opus_decoder_pvt *dec = pvt->pvt;
+ int error;
+
+ if (!dec->init) {
+ opus_dec_set(pvt, &f->subclass.format);
+ }
+
+ error = opus_decode(dec->dec, f->data.ptr, f->datalen, dec->slin_buf, dec->frame_size, 1);
+ if (error) {
+ ast_log(LOG_WARNING, "error decoding OPUS, error code %d\n", error);
+ return -1;
+ }
+
+ dec->slin_samples = dec->frame_size;
+ pvt->samples = dec->frame_size;
+
+ return 0;
+}
+
+
+static struct ast_frame *opus_dec_frameout(struct ast_trans_pvt *pvt)
+{
+ struct opus_decoder_pvt *dec = pvt->pvt;
+ struct ast_frame tmp;
+ int16_t *outslin = dec->slin_buf;
+ unsigned int samples = dec->slin_samples;
+
+
+ if (dec->resamp) {
+ unsigned int in_samples = samples;
+ unsigned int out_samples = OUTBUF_SIZE;
+ speex_resampler_process_int(dec->resamp,
+ 0,
+ dec->slin_buf,
+ &in_samples,
+ pvt->outbuf.i16,
+ &out_samples);
+ samples = out_samples;
+ outslin = pvt->outbuf.i16;
+ }
+
+ if (!samples) {
+ return NULL;
+ }
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.frametype = AST_FRAME_VOICE;
+ ast_format_copy(&tmp.subclass.format, &pvt->t->dst_format);
+ tmp.datalen = samples * 2;
+ tmp.data.ptr = outslin;
+ tmp.samples = samples;
+ tmp.src = pvt->t->name;
+ tmp.offset = AST_FRIENDLY_OFFSET;
+
+ pvt->samples = 0;
+ return ast_frdup(&tmp);
+}
+
+
+static int unload_module(void)
+{
+ int res = 0;
+ int idx;
+
+ for (idx = 0; idx < trans_size; idx++) {
+ res |= ast_unregister_translator(&translators[idx]);
+ }
+ ast_free(translators);
+
+ return res;
+}
+
+static int load_module(void)
+{
+ int res = 0;
+ int x, idx = 0;
+
+ /* We need a translator between every slin fmt to OPUS, and OPUS to every slin fmt */
+ trans_size = ARRAY_LEN(id_list) * 2;
+ if (!(translators = ast_calloc(1, sizeof(struct ast_translator) * trans_size))) {
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
+ for (x = 0; x < ARRAY_LEN(id_list); x++) {
+
+ /* SLIN to OPUS */
+ translators[idx].newpvt = NULL; /* ENC is created on first frame */
+ translators[idx].destroy = opus_enc_destroy;
+ translators[idx].framein = opus_enc_framein;
+ translators[idx].frameout = opus_enc_frameout;
+ translators[idx].desc_size = sizeof(struct opus_encoder_pvt);
+ translators[idx].buffer_samples = (OUTBUF_SIZE / sizeof(int16_t));
+ translators[idx].buf_size = OUTBUF_SIZE;
+ ast_format_set(&translators[idx].src_format, id_list[x], 0);
+ ast_format_set(&translators[idx].dst_format, AST_FORMAT_OPUS, 0);
+ snprintf(translators[idx].name, sizeof(translators[idx].name), "slin %dkhz -> OPUS",
+ ast_format_rate(&translators[idx].src_format));
+ res |= ast_register_translator(&translators[idx]);
+
+ idx++;
+
+ /* OPUS to SLIN */
+ translators[idx].newpvt = NULL; /* DEC is created on first frame */
+ translators[idx].destroy = opus_dec_destroy;
+ translators[idx].framein = opus_dec_framein;
+ translators[idx].frameout = opus_dec_frameout;
+ translators[idx].desc_size = sizeof(struct opus_decoder_pvt);
+ translators[idx].buffer_samples = (OUTBUF_SIZE / sizeof(int16_t));
+ translators[idx].buf_size = OUTBUF_SIZE;
+ ast_format_set(&translators[idx].src_format, AST_FORMAT_OPUS, 0);
+ ast_format_set(&translators[idx].dst_format, id_list[x], 0);
+ snprintf(translators[idx].name, sizeof(translators[idx].name), "OPUS -> slin %dkhz",
+ ast_format_rate(&translators[idx].dst_format));
+ res |= ast_register_translator(&translators[idx]);
+
+ idx++;
+ }
+
+ return res;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "OPUS Coder/Decoder",
+ .load = load_module,
+ .unload = unload_module,
+);
Propchange: team/dvossel/opus_codec_ftw/codecs/codec_opus.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/dvossel/opus_codec_ftw/codecs/codec_opus.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/dvossel/opus_codec_ftw/codecs/codec_opus.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the asterisk-commits
mailing list