retitle 786972 asterisk: please apply unofficial Opus transcoding patch
thanks

Quoting Jonas Smedegaard (2015-05-27 15:13:50)
> Quoting Tzafrir Cohen (2015-05-27 13:13:05)
>> On Wed, May 27, 2015 at 12:06:13PM +0200, Jonas Smedegaard wrote:
>>> Recent Asterisk supports the Opus audio codec, either as only 
>>> identifier when negotiating a pass-through connection,
>>
>> Right,
>>
>>> or decoding/encoding when mixing audio.
>>
>> Are you sure?
>
> No I am guessing, based on a) my undertanding that pass-through codec 
> negotiation reequire no library linking, and b) noticing that autoconf 
> checks not just library existence but for opus_encoder_create 
> function.

...and I guessed wrong: Simply adding build-dependency makes autotools 
detect it but isn't really used for anything, apparently.

A patch exist to implement Opus transcoding support.  That patch is not 
adopted upstream due to fear of patent trolls.

Please apply it for Debian redistribution, where we evidently do not 
have same concerns¹ (we distribute Opus encoders already).

Patch attached.  Patch also attached from same source (but can be 
applied independently) for read/write support for vp8 codec.

 - Jonas


¹ Please do *not* publicly discuss Debian position regarding patents - 
if needed then ask lea...@debian.org or bring it up somewhere else more 
private.

-- 
 * Jonas Smedegaard - idealist & Internet-arkitekt
 * Tlf.: +45 40843136  Website: http://dr.jones.dk/

 [x] quote me freely  [ ] ask before reusing  [ ] keep private
Description: Add Opus codec module supporting transcoding
Origin: https://github.com/seanbright/asterisk-opus
Author: Lorenzo Miniero <lore...@meetecho.com>
Forwarded: yes
Bug-Debian: http://bugs.debian.org/786972
Last-Update: 2015-10-12

--- 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)
 
 ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc kfreebsd-gnu),)
   ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
@@ -159,6 +160,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 = {
--- a/res/res_format_attr_opus.c
+++ b/res/res_format_attr_opus.c
@@ -51,6 +51,12 @@
 	unsigned int spropstereo;	        /* Default 0 */
 };
 
+static struct opus_attr default_opus_attr = {
+	.fec    = 0,
+	.dtx    = 0,
+	.stereo = 0,
+};
+
 static void opus_destroy(struct ast_format *format)
 {
 	struct opus_attr *attr = ast_format_get_attribute_data(format);
@@ -120,7 +126,7 @@
 		attr->dtx = val;
 	}
 
-	return 0;
+	return cloned;
 }
 
 static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
@@ -163,6 +169,14 @@
 	struct ast_format *jointformat;
 	struct opus_attr *attr_res;
 
+	if (!attr1) {
+		attr1 = &default_opus_attr;
+	}
+
+	if (!attr2) {
+		attr2 = &default_opus_attr;
+	}
+
 	jointformat = ast_format_clone(format1);
 	if (!jointformat) {
 		return NULL;
--- /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,587 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2014, Lorenzo Miniero
+ *
+ * Lorenzo Miniero <lore...@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 <lore...@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"
+
+#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;
+	int datalen = 0;	/* output bytes */
+	int samples = 0;	/* output samples */
+
+	/* We can't work on anything less than a frame in size */
+	if (pvt->samples < opvt->framesize) {
+		return NULL;
+	}
+
+	/* Encode 160 samples (or more if it's not narrowband) */
+	ast_debug(3, "[Encoder #%d (%d)] %d samples, %d bytes\n",
+		opvt->id,
+		opvt->sampling_rate,
+		opvt->framesize,
+		opvt->framesize * 2);
+
+	if ((datalen = opus_encode(opvt->opus, opvt->buf, opvt->framesize, pvt->outbuf.uc, BUFFER_SAMPLES)) < 0) {
+		ast_log(LOG_ERROR, "Error encoding the Opus frame: %s\n", opus_strerror(datalen));
+		return NULL;
+	}
+
+	samples += opvt->framesize;
+	pvt->samples -= opvt->framesize;
+
+	/* Move the data at the end of the buffer to the front */
+	if (pvt->samples) {
+		memmove(opvt->buf, opvt->buf + samples, pvt->samples * 2);
+	}
+
+	ast_debug(3, "[Encoder #%d (%d)]   >> Got %d samples, %d bytes\n",
+		opvt->id,
+		opvt->sampling_rate,
+		opvt->multiplier * samples,
+		datalen);
+
+	return ast_trans_frameout(pvt, datalen, opvt->multiplier * samples);
+}
+
+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,
+	);
Description: Add VP8 format module supporting read/write to file
Origin: https://github.com/seanbright/asterisk-opus
Author: Lorenzo Miniero <lore...@meetecho.com>
Forwarded: yes
Bug-Debian: http://bugs.debian.org/786972
Last-Update: 2015-10-12

--- /dev/null
+++ b/formats/format_vp8.c
@@ -0,0 +1,203 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2014, Lorenzo Miniero
+ *
+ * Lorenzo Miniero <lore...@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 <lore...@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
+	);

Attachment: signature.asc
Description: signature

Reply via email to