[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