[Pkg-voip-commits] [asterisk] 22/34: Improve Opus and VP8 support: Add patch to add Opus codec module supporting transcoding. Add patch to add VP8 format module supporting read/write to file. Build-depend on libopus-dev. Closes: bug#786972.
Jonas Smedegaard
dr at jones.dk
Sun Mar 20 18:39:23 UTC 2016
This is an automated email from the git hooks/post-receive script.
js pushed a commit to branch master
in repository asterisk.
commit c0c61a6c3d1f64598b637c246c1f7cf60fbe4b0b
Author: Jonas Smedegaard <dr at jones.dk>
Date: Sun Mar 20 07:35:55 2016 +0100
Improve Opus and VP8 support: Add patch to add Opus codec module supporting transcoding. Add patch to add VP8 format module supporting read/write to file. Build-depend on libopus-dev. Closes: bug#786972.
---
debian/control | 1 +
debian/patches/opus.patch | 701 ++++++++++++++++++++++++++++++++++++++++++++++
debian/patches/series | 3 +
debian/patches/vp8.patch | 213 ++++++++++++++
4 files changed, 918 insertions(+)
diff --git a/debian/control b/debian/control
index e487dab..73b0d90 100644
--- a/debian/control
+++ b/debian/control
@@ -39,6 +39,7 @@ Build-Depends:
libnewt-dev,
libogg-dev,
libopenr2-dev [linux-any],
+ libopus-dev,
libpjproject-dev,
libpopt-dev,
libpq-dev,
diff --git a/debian/patches/opus.patch b/debian/patches/opus.patch
new file mode 100644
index 0000000..2addeaa
--- /dev/null
+++ b/debian/patches/opus.patch
@@ -0,0 +1,701 @@
+Description: Add Opus codec module supporting transcoding
+Origin: https://github.com/seanbright/asterisk-opus
+Author: Lorenzo Miniero <lorenzo at meetecho.com>
+Forwarded: yes
+Bug-Debian: http://bugs.debian.org/786972
+Last-Update: 2016-03-19
+
+--- a/main/Makefile
++++ b/main/Makefile
+@@ -40,6 +40,7 @@
+ AST_LIBS+=$(URIPARSER_LIB)
+ AST_LIBS+=$(UUID_LIB)
+ AST_LIBS+=$(CRYPT_LIB)
++AST_LIBS+=$(OPUS_LIB)
+ AST_LIBS+=$(AST_CLANG_BLOCKS_LIBS)
+
+ ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc kfreebsd-gnu),)
+@@ -160,6 +161,7 @@
+ bucket.o: _ASTCFLAGS+=$(URIPARSER_INCLUDE)
+ crypt.o: _ASTCFLAGS+=$(CRYPT_INCLUDE)
+ uuid.o: _ASTCFLAGS+=$(UUID_INCLUDE)
++codec_builtin.o: _ASTCFLAGS+=$(OPUS_INCLUDE)
+
+ ifneq ($(findstring ENABLE_UPLOADS,$(MENUSELECT_CFLAGS)),)
+ http.o: _ASTCFLAGS+=$(GMIME_INCLUDE)
+--- a/main/codec_builtin.c
++++ b/main/codec_builtin.c
+@@ -38,6 +38,8 @@
+ #include "asterisk/format_cache.h"
+ #include "asterisk/frame.h"
+
++#include <opus/opus.h>
++
+ enum frame_type {
+ TYPE_HIGH, /* 0x0 */
+ TYPE_LOW, /* 0x1 */
+@@ -698,6 +700,11 @@
+ .get_length = g719_length,
+ };
+
++static int opus_samples(struct ast_frame *frame)
++{
++ return opus_packet_get_nb_samples(frame->data.ptr, frame->datalen, 48000);
++}
++
+ static struct ast_codec opus = {
+ .name = "opus",
+ .description = "Opus Codec",
+@@ -707,6 +714,7 @@
+ .maximum_ms = 60,
+ .default_ms = 20,
+ .minimum_bytes = 10,
++ .samples_count = opus_samples,
+ };
+
+ static struct ast_codec jpeg = {
+--- /dev/null
++++ b/codecs/ex_opus.h
+@@ -0,0 +1,35 @@
++/*! \file
++ * \brief 8-bit data
++ *
++ * Copyright (C) 2014, Lorenzo Miniero
++ *
++ * Distributed under the terms of the GNU General Public License
++ *
++ */
++
++/* Opus, a 20ms sample */
++static uint8_t ex_opus[] = {
++ 0x4b, 0x41, 0x25, 0x0b, 0xe4, 0x55, 0xc6, 0x74,
++ 0xda, 0xbb, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++};
++
++static struct ast_frame *opus_sample(void)
++{
++ static struct ast_frame f = {
++ .frametype = AST_FRAME_VOICE,
++ .datalen = sizeof(ex_opus),
++ .samples = 960, // ARRAY_LEN(ex_opus),
++ .mallocd = 0,
++ .offset = 0,
++ .src = __PRETTY_FUNCTION__,
++ .data.ptr = ex_opus,
++ };
++
++ f.subclass.format = ast_format_opus;
++
++ return &f;
++}
+--- /dev/null
++++ b/codecs/codec_opus.c
+@@ -0,0 +1,604 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2014, Lorenzo Miniero
++ *
++ * Lorenzo Miniero <lorenzo at meetecho.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)
++ *
++ * \author Lorenzo Miniero <lorenzo at meetecho.com>
++ *
++ * \note This work was motivated by Mozilla
++ *
++ * \ingroup codecs
++ *
++ * \extref The Opus library - http://opus-codec.org
++ *
++ */
++
++/*** MODULEINFO
++ <depend>opus</depend>
++ <support_level>core</support_level>
++***/
++
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision: $")
++
++#include <opus/opus.h>
++
++#include "asterisk/translate.h"
++#include "asterisk/module.h"
++#include "asterisk/cli.h"
++#include "asterisk/config.h"
++#include "asterisk/utils.h"
++#include "asterisk/linkedlists.h"
++
++#define BUFFER_SAMPLES 8000
++#define OPUS_SAMPLES 160
++
++#define USE_FEC 0
++
++/* Sample frame data */
++#include "asterisk/slin.h"
++#include "ex_opus.h"
++
++static struct codec_usage {
++ int encoder_id;
++ int decoder_id;
++ int encoders;
++ int decoders;
++} usage;
++
++/* Private structures */
++struct opus_coder_pvt {
++ void *opus; /* May be encoder or decoder */
++ int sampling_rate;
++ int multiplier;
++ int fec;
++ int id;
++ int16_t buf[BUFFER_SAMPLES]; /* FIXME */
++ int framesize;
++};
++
++static int valid_sampling_rate(int rate)
++{
++ return rate == 8000
++ || rate == 12000
++ || rate == 16000
++ || rate == 24000
++ || rate == 48000;
++}
++
++/* Helper methods */
++static int opus_encoder_construct(struct ast_trans_pvt *pvt, int sampling_rate)
++{
++ struct opus_coder_pvt *opvt = pvt->pvt;
++ int error = 0;
++
++ if (!valid_sampling_rate(sampling_rate)) {
++ return -1;
++ }
++
++ opvt->sampling_rate = sampling_rate;
++ opvt->multiplier = 48000/sampling_rate;
++ opvt->fec = USE_FEC;
++
++ opvt->opus = opus_encoder_create(sampling_rate, 1, OPUS_APPLICATION_VOIP, &error);
++
++ if (error != OPUS_OK) {
++ ast_log(LOG_ERROR, "Error creating the Opus encoder: %s\n", opus_strerror(error));
++ return -1;
++ }
++
++ if (sampling_rate == 8000) {
++ opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
++ } else if (sampling_rate == 12000) {
++ opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
++ } else if (sampling_rate == 16000) {
++ opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
++ } else if (sampling_rate == 24000) {
++ opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
++ } else if (sampling_rate == 48000) {
++ opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
++ }
++
++ opus_encoder_ctl(opvt->opus, OPUS_SET_INBAND_FEC(opvt->fec));
++ opvt->framesize = sampling_rate/50;
++ opvt->id = ast_atomic_fetchadd_int(&usage.encoder_id, 1) + 1;
++
++ ast_atomic_fetchadd_int(&usage.encoders, +1);
++
++ ast_debug(3, "Created encoder #%d (%d -> opus)\n", opvt->id, sampling_rate);
++
++ return 0;
++}
++
++static int opus_decoder_construct(struct ast_trans_pvt *pvt, int sampling_rate)
++{
++ struct opus_coder_pvt *opvt = pvt->pvt;
++ int error = 0;
++
++ if (!valid_sampling_rate(sampling_rate)) {
++ return -1;
++ }
++
++ opvt->sampling_rate = sampling_rate;
++ opvt->multiplier = 48000/sampling_rate;
++ opvt->fec = USE_FEC; /* FIXME: should be triggered by chan_sip */
++
++ opvt->opus = opus_decoder_create(sampling_rate, 1, &error);
++
++ if (error != OPUS_OK) {
++ ast_log(LOG_ERROR, "Error creating the Opus decoder: %s\n", opus_strerror(error));
++ return -1;
++ }
++
++ opvt->id = ast_atomic_fetchadd_int(&usage.decoder_id, 1) + 1;
++
++ ast_atomic_fetchadd_int(&usage.decoders, +1);
++
++ ast_debug(3, "Created decoder #%d (opus -> %d)\n", opvt->id, sampling_rate);
++
++ return 0;
++}
++
++/* Translator callbacks */
++static int lintoopus_new(struct ast_trans_pvt *pvt)
++{
++ return opus_encoder_construct(pvt, pvt->t->src_codec.sample_rate);
++}
++
++static int opustolin_new(struct ast_trans_pvt *pvt)
++{
++ return opus_decoder_construct(pvt, pvt->t->dst_codec.sample_rate);
++}
++
++static int lintoopus_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
++{
++ struct opus_coder_pvt *opvt = pvt->pvt;
++
++ /* XXX We should look at how old the rest of our stream is, and if it
++ is too old, then we should overwrite it entirely, otherwise we can
++ get artifacts of earlier talk that do not belong */
++ memcpy(opvt->buf + pvt->samples, f->data.ptr, f->datalen);
++ pvt->samples += f->samples;
++
++ return 0;
++}
++
++static struct ast_frame *lintoopus_frameout(struct ast_trans_pvt *pvt)
++{
++ struct opus_coder_pvt *opvt = pvt->pvt;
++ struct ast_frame *result = NULL;
++ struct ast_frame *last = NULL;
++ int samples = 0; /* output samples */
++
++ while (pvt->samples >= opvt->framesize) {
++ /* status is either error or output bytes */
++ const int status = opus_encode(opvt->opus,
++ opvt->buf + samples,
++ opvt->framesize,
++ pvt->outbuf.uc,
++ BUFFER_SAMPLES);
++
++ ast_debug(3, "[Encoder #%d (%d)] %d samples, %d bytes\n",
++ opvt->id,
++ opvt->sampling_rate,
++ opvt->framesize,
++ opvt->framesize * 2);
++
++ samples += opvt->framesize;
++ pvt->samples -= opvt->framesize;
++
++ if (status < 0) {
++ ast_log(LOG_ERROR, "Error encoding the Opus frame: %s\n", opus_strerror(status));
++ } else {
++ struct ast_frame *current = ast_trans_frameout(pvt,
++ status,
++ opvt->multiplier * opvt->framesize);
++
++ ast_debug(3, "[Encoder #%d (%d)] >> Got %d samples, %d bytes\n",
++ opvt->id,
++ opvt->sampling_rate,
++ opvt->multiplier * opvt->framesize,
++ status);
++
++ if (!current) {
++ continue;
++ } else if (last) {
++ AST_LIST_NEXT(last, frame_list) = current;
++ } else {
++ result = current;
++ }
++ last = current;
++ }
++ }
++
++ /* Move the data at the end of the buffer to the front */
++ if (samples) {
++ memmove(opvt->buf, opvt->buf + samples, pvt->samples * 2);
++ }
++
++ return result;
++}
++
++static int opustolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
++{
++ struct opus_coder_pvt *opvt = pvt->pvt;
++ int samples = 0;
++
++ /* Decode */
++ ast_debug(3, "[Decoder #%d (%d)] %d samples, %d bytes\n",
++ opvt->id,
++ opvt->sampling_rate,
++ f->samples,
++ f->datalen);
++
++ if ((samples = opus_decode(opvt->opus, f->data.ptr, f->datalen, pvt->outbuf.i16, BUFFER_SAMPLES, opvt->fec)) < 0) {
++ ast_log(LOG_ERROR, "Error decoding the Opus frame: %s\n", opus_strerror(samples));
++ return -1;
++ }
++
++ pvt->samples += samples;
++ pvt->datalen += samples * 2;
++
++ ast_debug(3, "[Decoder #%d (%d)] >> Got %d samples, %d bytes\n",
++ opvt->id,
++ opvt->sampling_rate,
++ pvt->samples,
++ pvt->datalen);
++
++ return 0;
++}
++
++static void lintoopus_destroy(struct ast_trans_pvt *arg)
++{
++ struct opus_coder_pvt *opvt = arg->pvt;
++
++ if (!opvt || !opvt->opus) {
++ return;
++ }
++
++ opus_encoder_destroy(opvt->opus);
++ opvt->opus = NULL;
++
++ ast_atomic_fetchadd_int(&usage.encoders, -1);
++
++ ast_debug(3, "Destroyed encoder #%d (%d->opus)\n", opvt->id, opvt->sampling_rate);
++}
++
++static void opustolin_destroy(struct ast_trans_pvt *arg)
++{
++ struct opus_coder_pvt *opvt = arg->pvt;
++
++ if (!opvt || !opvt->opus) {
++ return;
++ }
++
++ opus_decoder_destroy(opvt->opus);
++ opvt->opus = NULL;
++
++ ast_atomic_fetchadd_int(&usage.decoders, -1);
++
++ ast_debug(3, "Destroyed decoder #%d (opus->%d)\n", opvt->id, opvt->sampling_rate);
++}
++
++static char *handle_cli_opus_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ struct codec_usage copy;
++
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "opus show";
++ e->usage =
++ "Usage: opus show\n"
++ " Displays Opus encoder/decoder utilization.\n";
++ return NULL;
++ case CLI_GENERATE:
++ return NULL;
++ }
++
++ if (a->argc != 2) {
++ return CLI_SHOWUSAGE;
++ }
++
++ copy = usage;
++
++ ast_cli(a->fd, "%d/%d encoders/decoders are in use.\n", copy.encoders, copy.decoders);
++
++ return CLI_SUCCESS;
++}
++
++/* Translators */
++static struct ast_translator opustolin = {
++ .name = "opustolin",
++ .src_codec = {
++ .name = "opus",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 48000,
++ },
++ .dst_codec = {
++ .name = "slin",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 8000,
++ },
++ .format = "slin",
++ .newpvt = opustolin_new,
++ .framein = opustolin_framein,
++ .destroy = opustolin_destroy,
++ .sample = opus_sample,
++ .desc_size = sizeof(struct opus_coder_pvt),
++ .buffer_samples = BUFFER_SAMPLES,
++ .buf_size = BUFFER_SAMPLES * 2,
++};
++
++static struct ast_translator lintoopus = {
++ .name = "lintoopus",
++ .src_codec = {
++ .name = "slin",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 8000,
++ },
++ .dst_codec = {
++ .name = "opus",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 48000,
++ },
++ .format = "opus",
++ .newpvt = lintoopus_new,
++ .framein = lintoopus_framein,
++ .frameout = lintoopus_frameout,
++ .destroy = lintoopus_destroy,
++ .sample = slin8_sample,
++ .desc_size = sizeof(struct opus_coder_pvt),
++ .buffer_samples = BUFFER_SAMPLES,
++ .buf_size = BUFFER_SAMPLES * 2,
++};
++
++static struct ast_translator opustolin12 = {
++ .name = "opustolin12",
++ .src_codec = {
++ .name = "opus",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 48000,
++ },
++ .dst_codec = {
++ .name = "slin",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 12000,
++ },
++ .format = "slin12",
++ .newpvt = opustolin_new,
++ .framein = opustolin_framein,
++ .destroy = opustolin_destroy,
++ .sample = opus_sample,
++ .desc_size = sizeof(struct opus_coder_pvt),
++ .buffer_samples = BUFFER_SAMPLES,
++ .buf_size = BUFFER_SAMPLES * 2,
++};
++
++static struct ast_translator lin12toopus = {
++ .name = "lin12toopus",
++ .src_codec = {
++ .name = "slin",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 12000,
++ },
++ .dst_codec = {
++ .name = "opus",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 48000,
++ },
++ .format = "opus",
++ .newpvt = lintoopus_new,
++ .framein = lintoopus_framein,
++ .frameout = lintoopus_frameout,
++ .destroy = lintoopus_destroy,
++ .desc_size = sizeof(struct opus_coder_pvt),
++ .buffer_samples = BUFFER_SAMPLES,
++ .buf_size = BUFFER_SAMPLES * 2,
++};
++
++static struct ast_translator opustolin16 = {
++ .name = "opustolin16",
++ .src_codec = {
++ .name = "opus",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 48000,
++ },
++ .dst_codec = {
++ .name = "slin",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 16000,
++ },
++ .format = "slin16",
++ .newpvt = opustolin_new,
++ .framein = opustolin_framein,
++ .destroy = opustolin_destroy,
++ .sample = opus_sample,
++ .desc_size = sizeof(struct opus_coder_pvt),
++ .buffer_samples = BUFFER_SAMPLES,
++ .buf_size = BUFFER_SAMPLES * 2,
++};
++
++static struct ast_translator lin16toopus = {
++ .name = "lin16toopus",
++ .src_codec = {
++ .name = "slin",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 16000,
++ },
++ .dst_codec = {
++ .name = "opus",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 48000,
++ },
++ .format = "opus",
++ .newpvt = lintoopus_new,
++ .framein = lintoopus_framein,
++ .frameout = lintoopus_frameout,
++ .destroy = lintoopus_destroy,
++ .sample = slin16_sample,
++ .desc_size = sizeof(struct opus_coder_pvt),
++ .buffer_samples = BUFFER_SAMPLES,
++ .buf_size = BUFFER_SAMPLES * 2,
++};
++
++static struct ast_translator opustolin24 = {
++ .name = "opustolin24",
++ .src_codec = {
++ .name = "opus",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 48000,
++ },
++ .dst_codec = {
++ .name = "slin",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 24000,
++ },
++ .format = "slin24",
++ .newpvt = opustolin_new,
++ .framein = opustolin_framein,
++ .destroy = opustolin_destroy,
++ .sample = opus_sample,
++ .desc_size = sizeof(struct opus_coder_pvt),
++ .buffer_samples = BUFFER_SAMPLES,
++ .buf_size = BUFFER_SAMPLES * 2,
++};
++
++static struct ast_translator lin24toopus = {
++ .name = "lin24toopus",
++ .src_codec = {
++ .name = "slin",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 24000,
++ },
++ .dst_codec = {
++ .name = "opus",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 48000,
++ },
++ .format = "opus",
++ .newpvt = lintoopus_new,
++ .framein = lintoopus_framein,
++ .frameout = lintoopus_frameout,
++ .destroy = lintoopus_destroy,
++ .desc_size = sizeof(struct opus_coder_pvt),
++ .buffer_samples = BUFFER_SAMPLES,
++ .buf_size = BUFFER_SAMPLES * 2,
++};
++
++static struct ast_translator opustolin48 = {
++ .name = "opustolin48",
++ .src_codec = {
++ .name = "opus",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 48000,
++ },
++ .dst_codec = {
++ .name = "slin",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 48000,
++ },
++ .format = "slin48",
++ .newpvt = opustolin_new,
++ .framein = opustolin_framein,
++ .destroy = opustolin_destroy,
++ .sample = opus_sample,
++ .desc_size = sizeof(struct opus_coder_pvt),
++ .buffer_samples = BUFFER_SAMPLES,
++ .buf_size = BUFFER_SAMPLES * 2,
++};
++
++static struct ast_translator lin48toopus = {
++ .name = "lin48toopus",
++ .src_codec = {
++ .name = "slin",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 48000,
++ },
++ .dst_codec = {
++ .name = "opus",
++ .type = AST_MEDIA_TYPE_AUDIO,
++ .sample_rate = 48000,
++ },
++ .format = "opus",
++ .newpvt = lintoopus_new,
++ .framein = lintoopus_framein,
++ .frameout = lintoopus_frameout,
++ .destroy = lintoopus_destroy,
++ .desc_size = sizeof(struct opus_coder_pvt),
++ .buffer_samples = BUFFER_SAMPLES,
++ .buf_size = BUFFER_SAMPLES * 2,
++};
++
++static struct ast_cli_entry cli[] = {
++ AST_CLI_DEFINE(handle_cli_opus_show, "Display Opus codec utilization.")
++};
++
++static int reload(void)
++{
++ /* Reload does nothing */
++ return AST_MODULE_LOAD_SUCCESS;
++}
++
++static int unload_module(void)
++{
++ int res;
++
++ res = ast_unregister_translator(&opustolin);
++ res |= ast_unregister_translator(&lintoopus);
++ res |= ast_unregister_translator(&opustolin12);
++ res |= ast_unregister_translator(&lin12toopus);
++ res |= ast_unregister_translator(&opustolin16);
++ res |= ast_unregister_translator(&lin16toopus);
++ res |= ast_unregister_translator(&opustolin24);
++ res |= ast_unregister_translator(&lin24toopus);
++ res |= ast_unregister_translator(&opustolin48);
++ res |= ast_unregister_translator(&lin48toopus);
++
++ ast_cli_unregister_multiple(cli, ARRAY_LEN(cli));
++
++ return res;
++}
++
++static int load_module(void)
++{
++ int res;
++
++ res = ast_register_translator(&opustolin);
++ res |= ast_register_translator(&lintoopus);
++ res |= ast_register_translator(&opustolin12);
++ res |= ast_register_translator(&lin12toopus);
++ res |= ast_register_translator(&opustolin16);
++ res |= ast_register_translator(&lin16toopus);
++ res |= ast_register_translator(&opustolin24);
++ res |= ast_register_translator(&lin24toopus);
++ res |= ast_register_translator(&opustolin48);
++ res |= ast_register_translator(&lin48toopus);
++
++ ast_cli_register_multiple(cli, ARRAY_LEN(cli));
++
++ return res;
++}
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Opus Coder/Decoder",
++ .load = load_module,
++ .unload = unload_module,
++ .reload = reload,
++ );
diff --git a/debian/patches/series b/debian/patches/series
index 3f65de7..e1bec45 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -25,3 +25,6 @@ systemd.patch
#test_framework.patch
configure-osarch
+
+opus.patch
+vp8.patch
diff --git a/debian/patches/vp8.patch b/debian/patches/vp8.patch
new file mode 100644
index 0000000..b7271da
--- /dev/null
+++ b/debian/patches/vp8.patch
@@ -0,0 +1,213 @@
+Description: Add VP8 format module supporting read/write to file
+Origin: https://github.com/seanbright/asterisk-opus
+Author: Lorenzo Miniero <lorenzo at meetecho.com>
+Forwarded: yes
+Bug-Debian: http://bugs.debian.org/786972
+Last-Update: 2016-03-19
+
+--- /dev/null
++++ b/formats/format_vp8.c
+@@ -0,0 +1,203 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2014, Lorenzo Miniero
++ *
++ * Lorenzo Miniero <lorenzo at meetecho.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 Save to raw, headerless VP8 data.
++ *
++ * \author Lorenzo Miniero <lorenzo at meetecho.com>
++ *
++ * \note Basically a "clone" of the H.264 passthrough format
++ *
++ * \arg File name extension: VP8
++ * \ingroup formats
++ * \arg See \ref AstVideo
++ */
++
++/*** MODULEINFO
++ <support_level>core</support_level>
++***/
++
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision: $")
++
++#include "asterisk/mod_format.h"
++#include "asterisk/module.h"
++#include "asterisk/endian.h"
++#include "asterisk/format_cache.h"
++
++/* VP8 passthrough */
++#define FRAME_ENDED 0x8000
++
++#define BUF_SIZE 4096
++struct vp8_desc {
++ unsigned int lastts;
++};
++
++static int vp8_open(struct ast_filestream *s)
++{
++ unsigned int ts;
++
++ if (fread(&ts, 1, sizeof(ts), s->f) < sizeof(ts)) {
++ ast_log(LOG_WARNING, "Empty file!\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++static struct ast_frame *vp8_read(struct ast_filestream *s, int *whennext)
++{
++ int res;
++ int mark = 0;
++ unsigned short len;
++ unsigned int ts;
++ struct vp8_desc *fs = (struct vp8_desc *) s->_private;
++
++ /* Send a frame from the file to the appropriate channel */
++ if ((res = fread(&len, 1, sizeof(len), s->f)) < 1) {
++ return NULL;
++ }
++
++ len = ntohs(len);
++ mark = (len & FRAME_ENDED) ? 1 : 0;
++ len &= 0x7fff;
++ if (len > BUF_SIZE) {
++ ast_log(LOG_WARNING, "Length %d is too long\n", len);
++ len = BUF_SIZE; /* XXX truncate */
++ }
++ s->fr.mallocd = 0;
++ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, len);
++ if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
++ if (res) {
++ ast_log(LOG_WARNING, "Short read (%d of %d) (%s)!\n", res, len, strerror(errno));
++ }
++ return NULL;
++ }
++ s->fr.samples = fs->lastts;
++ s->fr.datalen = len;
++ s->fr.subclass.frame_ending = mark;
++ s->fr.delivery.tv_sec = 0;
++ s->fr.delivery.tv_usec = 0;
++ if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) {
++ fs->lastts = ntohl(ts);
++ *whennext = fs->lastts * 4/45;
++ } else {
++ *whennext = 0;
++ }
++ return &s->fr;
++}
++
++static int vp8_write(struct ast_filestream *s, struct ast_frame *f)
++{
++ int res;
++ unsigned int ts;
++ unsigned short len;
++ int mark;
++
++ if (f->frametype != AST_FRAME_VIDEO) {
++ ast_log(LOG_WARNING, "Asked to write non-video frame!\n");
++ return -1;
++ }
++
++ mark = f->subclass.frame_ending ? FRAME_ENDED : 0;
++ ts = htonl(f->samples);
++ if ((res = fwrite(&ts, 1, sizeof(ts), s->f)) != sizeof(ts)) {
++ ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno));
++ return -1;
++ }
++
++ len = htons(f->datalen | mark);
++ if ((res = fwrite(&len, 1, sizeof(len), s->f)) != sizeof(len)) {
++ ast_log(LOG_WARNING, "Bad write (%d/2): %s\n", res, strerror(errno));
++ return -1;
++ }
++
++ if ((res = fwrite(f->data.ptr, 1, f->datalen, s->f)) != f->datalen) {
++ ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
++ return -1;
++ }
++
++ return 0;
++}
++
++static int vp8_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
++{
++ /* No way Jose */
++ return -1;
++}
++
++static int vp8_trunc(struct ast_filestream *fs)
++{
++ int fd;
++ off_t cur;
++
++ if ((fd = fileno(fs->f)) < 0) {
++ ast_log(LOG_WARNING, "Unable to determine file descriptor for VP8 filestream %p: %s\n", fs, strerror(errno));
++ return -1;
++ }
++
++ if ((cur = ftello(fs->f)) < 0) {
++ ast_log(LOG_WARNING, "Unable to determine current position in VP8 filestream %p: %s\n", fs, strerror(errno));
++ return -1;
++ }
++
++ /* Truncate file to current length */
++ return ftruncate(fd, cur);
++}
++
++static off_t vp8_tell(struct ast_filestream *fs)
++{
++ off_t offset = ftell(fs->f);
++ return offset; /* XXX totally bogus, needs fixing */
++}
++
++static struct ast_format_def vp8_f = {
++ .name = "VP8",
++ .exts = "vp8",
++ .open = vp8_open,
++ .write = vp8_write,
++ .seek = vp8_seek,
++ .trunc = vp8_trunc,
++ .tell = vp8_tell,
++ .read = vp8_read,
++ .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
++ .desc_size = sizeof(struct vp8_desc),
++};
++
++static int load_module(void)
++{
++ vp8_f.format = ast_format_vp8;
++ if (ast_format_def_register(&vp8_f)) {
++ return AST_MODULE_LOAD_FAILURE;
++ }
++
++ return AST_MODULE_LOAD_SUCCESS;
++}
++
++static int unload_module(void)
++{
++ return ast_format_def_unregister(vp8_f.name);
++}
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw VP8 data",
++ .load = load_module,
++ .unload = unload_module,
++ .load_pri = AST_MODPRI_APP_DEPEND
++ );
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/asterisk.git
More information about the Pkg-voip-commits
mailing list