Sophie

Sophie

distrib > Mageia > 5 > x86_64 > by-pkgid > 2dfe1f3fe4a67400c5a3ade197d836a8 > files > 8

asterisk-11.17.1-1.mga5.src.rpm

--- a/build_tools/menuselect-deps.in	2012-07-25 16:21:54.000000000 +0400
+++ b/build_tools/menuselect-deps.in	2013-06-10 18:25:18.439426627 +0400
@@ -40,6 +40,7 @@
 NEON29=@PBX_NEON29@
 OGG=@PBX_OGG@
 OPENH323=@PBX_OPENH323@
+OPUS=@PBX_OPUS@
 OSPTK=@PBX_OSPTK@
 OSS=@PBX_OSS@
 PGSQL=@PBX_PGSQL@
--- a/channels/chan_sip.c	2013-03-27 23:51:29.000000000 +0400
+++ b/channels/chan_sip.c	2013-06-10 18:25:18.470430575 +0400
@@ -7757,8 +7757,25 @@
 		break;
 	case AST_CONTROL_VIDUPDATE:	/* Request a video frame update */
 		if (p->vrtp && !p->novideo) {
-			transmit_info_with_vidupdate(p);
-			/* ast_rtcp_send_h261fur(p->vrtp); */
+			/* Only use this for WebRTC users */
+			struct ast_format_cap *fcap = ast_channel_nativeformats(ast);
+			struct ast_format vp8;
+			ast_format_set(&vp8, AST_FORMAT_VP8, 0);
+			if(ast_format_cap_iscompatible(fcap, &vp8)) {
+				sip_pvt_lock(p);
+				if (p->vrtp) {
+					ast_log(LOG_WARNING, "chan_sip, sending RTCP FIR to WebRTC user\n");
+					/* FIXME Fake RTP write, this will be sent as an RTCP packet */
+					struct ast_frame fr;
+					fr.frametype = AST_FRAME_CONTROL;
+					fr.subclass.integer = AST_CONTROL_VIDUPDATE;
+					res = ast_rtp_instance_write(p->vrtp, &fr);
+				}
+				sip_pvt_unlock(p);
+			} else {
+				transmit_info_with_vidupdate(p);
+				/* ast_rtcp_send_h261fur(p->vrtp); */
+			}
 		} else
 			res = -1;
 		break;
@@ -11028,7 +11045,7 @@
 		struct ast_format *format;
 
 		if ((format = ast_rtp_codecs_get_payload_format(newaudiortp, codec))) {
-			unsigned int bit_rate;
+			unsigned int bit_rate, value;
 
 			if (!ast_format_sdp_parse(format, fmtp_string)) {
 				found = TRUE;
@@ -11067,6 +11084,53 @@
 					}
 				}
 				break;
+			/* Opus SDP fmtp parameters (draft-ietf-payload-rtp-opus-00) */
+			case AST_FORMAT_OPUS:
+				if (sscanf(fmtp_string, "maxplaybackrate=%30u", &value) == 1) {
+					ast_log(LOG_DEBUG, "Got Opus maxplaybackrate=%d\n", value);
+					/* TODO: actually handle this */
+					found = TRUE;
+				}
+				if (sscanf(fmtp_string, "sprop-maxcapturerate=%30u", &value) == 1) {
+					ast_log(LOG_DEBUG, "Got Opus sprop-maxcapturerate=%d\n", value);
+					/* TODO: actually handle this */
+					found = TRUE;
+				}
+				if (sscanf(fmtp_string, "minptime=%30u", &value) == 1) {
+					ast_log(LOG_DEBUG, "Got Opus minptime=%d\n", value);
+					/* TODO: actually handle this */
+					found = TRUE;
+				}
+				if (sscanf(fmtp_string, "maxaveragebitrate=%30u", &value) == 1) {
+					ast_log(LOG_DEBUG, "Got Opus maxaveragebitrate=%d\n", value);
+					/* TODO: actually handle this */
+					found = TRUE;
+				}
+				if (sscanf(fmtp_string, "stereo=%30u", &value) == 1) {
+					ast_log(LOG_DEBUG, "Got Opus stereo=%d\n", value);
+					/* TODO: actually handle this */
+					found = TRUE;
+				}
+				if (sscanf(fmtp_string, "sprop-stereo=%30u", &value) == 1) {
+					ast_log(LOG_DEBUG, "Got Opus sprop-stereo=%d\n", value);
+					/* TODO: actually handle this */
+					found = TRUE;
+				}
+				if (sscanf(fmtp_string, "cbr=%30u", &value) == 1) {
+					ast_log(LOG_DEBUG, "Got Opus cbr=%d\n", value);
+					/* TODO: actually handle this */
+					found = TRUE;
+				}
+				if (sscanf(fmtp_string, "useinbandfec=%30u", &value) == 1) {
+					ast_log(LOG_DEBUG, "Got Opus useinbandfec=%d\n", value);
+					/* TODO: actually handle this */
+					found = TRUE;
+				}
+				if (sscanf(fmtp_string, "usedtx=%30u", &value) == 1) {
+					ast_log(LOG_DEBUG, "Got Opus usedtx=%d\n", value);
+					/* TODO: actually handle this */
+					found = TRUE;
+				}
 			}
 		}
 	}
@@ -11087,7 +11151,9 @@
 		/* We have a rtpmap to handle */
 		if (*last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
 			/* Note: should really look at the '#chans' params too */
-			if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3)) {
+			if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3)
+					/* VP8 */
+					|| !strncasecmp(mimeSubtype, "VP8", 3)) {
 				if (!(ast_rtp_codecs_payloads_set_rtpmap_type_rate(newvideortp, NULL, codec, "video", mimeSubtype, 0, sample_rate))) {
 					if (debug)
 						ast_verbose("Found video description format %s for ID %u\n", mimeSubtype, codec);
@@ -12656,7 +12722,11 @@
 	} else /* I don't see how you couldn't have p->rtp, but good to check for and error out if not there like earlier code */
 		return;
 	ast_str_append(m_buf, 0, " %d", rtp_code);
-	ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u\r\n", rtp_code, mime, rate);
+	/* Opus mandates 2 channels in rtpmap */
+	if((int) format->id == AST_FORMAT_OPUS)
+		ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u/2\r\n", rtp_code, mime, rate);
+	else
+		ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u\r\n", rtp_code, mime, rate);
 
 	ast_format_sdp_generate(format, rtp_code, a_buf);
 
@@ -12685,6 +12755,17 @@
 		/* Indicate that we only expect 64Kbps */
 		ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=64000\r\n", rtp_code);
 		break;
+	/* Opus, pass parameters we care about (FIXME could this be 'fb' and not 'wb'?) */
+	case AST_FORMAT_OPUS:
+		ast_str_append(a_buf, 0, "a=maxptime:%d\r\n", 60);	/* FIXME */
+		ast_str_append(a_buf, 0, "a=fmtp:%d maxplaybackrate=%d; stereo=%d; sprop-stereo=%d; useinbandfec=%d\r\n",
+				rtp_code,
+				16000,	/* maxplaybackrate */
+				0,		/* stereo */
+				0,		/* sprop-stereo */
+				0		/* useinbandfec FIXME */
+		);
+		break;
 	}
 
 	if (fmt.cur_ms && (fmt.cur_ms < *min_packet_size))
--- a/codecs/codec_opus.c	1970-01-01 03:00:00.000000000 +0300
+++ b/codecs/codec_opus.c	2013-06-10 18:25:18.477411840 +0400
@@ -0,0 +1,529 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@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)
+ *
+ * \author Lorenzo Miniero <lorenzo@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: 328209 $")
+
+#include <opus/opus.h>
+
+#include "asterisk/translate.h"
+#include "asterisk/module.h"
+#include "asterisk/config.h"
+#include "asterisk/utils.h"
+#include "asterisk/cli.h"
+
+
+#define	BUFFER_SAMPLES	8000
+#define	OPUS_SAMPLES	160
+
+#define USE_FEC			0
+
+
+/* Sample frame data */
+#include "asterisk/slin.h"
+#include "ex_opus.h"
+
+/* FIXME: Test */
+#include "asterisk/file.h"
+
+
+static int encid = 0;
+static int decid = 0;
+
+static int opusdebug = 0;
+
+
+/* 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;
+	
+	FILE *file;
+};
+
+
+/* Helper methods */
+static int opus_encoder_construct(struct ast_trans_pvt *pvt, int sampling_rate) {
+	if(sampling_rate != 8000 && sampling_rate != 12000 && sampling_rate != 16000 && sampling_rate != 24000 && sampling_rate != 48000)
+		return -1;
+	struct opus_coder_pvt *opvt = pvt->pvt;
+	opvt->sampling_rate = sampling_rate;
+	opvt->multiplier = 48000/sampling_rate;
+	opvt->fec = USE_FEC;
+	int error = 0;
+	opvt->opus = opus_encoder_create(sampling_rate, 1, OPUS_APPLICATION_VOIP, &error);
+	if(error != OPUS_OK) {
+		if(opusdebug)
+			ast_verbose("[Opus] Ops! got an error creating the Opus encoder: %d (%s)\n", error, 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 = ++encid;
+	if(opusdebug)
+		ast_verbose("[Opus] 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) {
+	if(sampling_rate != 8000 && sampling_rate != 12000 && sampling_rate != 16000 && sampling_rate != 24000 && sampling_rate != 48000)
+		return -1;
+	struct opus_coder_pvt *opvt = pvt->pvt;
+	opvt->sampling_rate = sampling_rate;
+	opvt->multiplier = 48000/sampling_rate;
+	opvt->fec = USE_FEC;	/* FIXME: should be triggered by chan_sip */
+	int error = 0;
+	opvt->opus = opus_decoder_create(sampling_rate, 1, &error);
+	if(error != OPUS_OK) {
+		if(opusdebug)
+			ast_verbose("[Opus] Ops! got an error creating the Opus decoder: %d (%s)\n", error, opus_strerror(error));
+		return -1;
+	}
+	opvt->id = ++decid;
+	if(opusdebug)
+		ast_verbose("[Opus] Created decoder #%d (opus->%d)\n", opvt->id, sampling_rate);
+
+	if(opusdebug > 1) {
+		char filename[50];
+		sprintf(filename, "/home/lminiero/opusdec-%04d-%d.raw", opvt->id, opvt->sampling_rate);
+		opvt->file = fopen(filename, "wb");
+	}
+	
+	return 0;
+}
+
+/* Translator callbacks */
+static int lintoopus_new(struct ast_trans_pvt *pvt) {
+	return opus_encoder_construct(pvt, 8000);
+}
+
+static int lin12toopus_new(struct ast_trans_pvt *pvt) {
+	return opus_encoder_construct(pvt, 12000);
+}
+
+static int lin16toopus_new(struct ast_trans_pvt *pvt) {
+	return opus_encoder_construct(pvt, 16000);
+}
+
+static int lin24toopus_new(struct ast_trans_pvt *pvt) {
+	return opus_encoder_construct(pvt, 24000);
+}
+
+static int lin48toopus_new(struct ast_trans_pvt *pvt) {
+	return opus_encoder_construct(pvt, 48000);
+}
+
+static int opustolin_new(struct ast_trans_pvt *pvt) {
+	return opus_decoder_construct(pvt, 8000);
+}
+
+static int opustolin12_new(struct ast_trans_pvt *pvt) {
+	return opus_decoder_construct(pvt, 12000);
+}
+
+static int opustolin16_new(struct ast_trans_pvt *pvt) {
+	return opus_decoder_construct(pvt, 16000);
+}
+
+static int opustolin24_new(struct ast_trans_pvt *pvt) {
+	return opus_decoder_construct(pvt, 24000);
+}
+
+static int opustolin48_new(struct ast_trans_pvt *pvt) {
+	return opus_decoder_construct(pvt, 48000);
+}
+
+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;
+
+	/* We can't work on anything less than a frame in size */
+	if (pvt->samples < opvt->framesize)
+		return NULL;
+		
+	int datalen = 0;	/* output bytes */
+	int samples = 0;	/* output samples */
+
+	/* Encode 160 samples (or more if it's not narrowband) */
+	if(opusdebug > 1)
+		ast_verbose("[Opus] [Encoder #%d (%d)] %d samples, %d bytes\n", opvt->id, opvt->sampling_rate, opvt->framesize, opvt->framesize*2);
+	datalen = opus_encode(opvt->opus, opvt->buf, opvt->framesize, pvt->outbuf.uc, BUFFER_SAMPLES);
+	if(datalen < 0) {
+		if(opusdebug)
+			ast_verbose("[Opus] Ops! got an error encoding the Opus frame: %d (%s)\n", datalen, 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);
+
+	if(opusdebug > 1)
+		ast_verbose("[Opus] [Encoder #%d (%d)]   >> Got %d samples, %d bytes\n", opvt->id, opvt->sampling_rate, opvt->multiplier*samples, datalen);
+
+	if(opvt->file)
+		fwrite(opvt->buf, sizeof(int16_t), opvt->multiplier*samples, opvt->file);
+	
+	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;
+	/* Decode */
+	if(opusdebug > 1)
+		ast_verbose("[Opus] [Decoder #%d (%d)] %d samples, %d bytes\n", opvt->id, opvt->sampling_rate, f->samples, f->datalen);
+	int error = opus_decode(opvt->opus, f->data.ptr, f->datalen, pvt->outbuf.i16, BUFFER_SAMPLES, opvt->fec);
+	if(error < 0) {
+		if(opusdebug)
+			ast_verbose("[Opus] Ops! got an error decoding the Opus frame: %d (%s)\n", error, opus_strerror(error));
+		return -1;
+	}
+	pvt->samples += error;
+	pvt->datalen += error*2;
+
+	if(opusdebug > 1)
+		ast_verbose("[Opus] [Decoder #%d (%d)]   >> Got %d samples, %d bytes\n", opvt->id, opvt->sampling_rate, pvt->samples, pvt->datalen);
+
+	if(opvt->file)
+		fwrite(pvt->outbuf.i16, sizeof(int16_t), pvt->samples, opvt->file);
+
+	return 0;
+}
+
+static void lintoopus_destroy(struct ast_trans_pvt *arg) {
+	struct opus_coder_pvt *opvt = arg->pvt;
+	if(opvt == NULL || opvt->opus == NULL)
+		return;
+	opus_encoder_destroy(opvt->opus);
+	if(opusdebug)
+		ast_verbose("[Opus] Destroyed encoder #%d (%d->opus)\n", opvt->id, opvt->sampling_rate);
+	opvt->opus = NULL;
+
+	if(opvt->file)
+		fclose(opvt->file);
+	opvt->file = NULL;
+}
+
+static void opustolin_destroy(struct ast_trans_pvt *arg) {
+	struct opus_coder_pvt *opvt = arg->pvt;
+	if(opvt == NULL || opvt->opus == NULL)
+		return;
+	opus_decoder_destroy(opvt->opus);
+	if(opusdebug)
+		ast_verbose("[Opus] Destroyed decoder #%d (opus->%d)\n", opvt->id, opvt->sampling_rate);
+	opvt->opus = NULL;
+
+	if(opvt->file)
+		fclose(opvt->file);
+	opvt->file = NULL;
+}
+
+	
+/* Translators */
+static struct ast_translator lintoopus = {
+	.name = "lintoopus", 
+	.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 lin12toopus = {
+	.name = "lin12toopus", 
+	.newpvt = lin12toopus_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 lin16toopus = {
+	.name = "lin16toopus", 
+	.newpvt = lin16toopus_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 lin24toopus = {
+	.name = "lin24toopus", 
+	.newpvt = lin24toopus_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 lin48toopus = {
+	.name = "lin48toopus", 
+	.newpvt = lin48toopus_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 opustolin = {
+	.name = "opustolin", 
+	.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,
+	.native_plc = 1,	/* FIXME: needed? */
+};
+
+static struct ast_translator opustolin12 = {
+	.name = "opustolin12", 
+	.newpvt = opustolin12_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,
+	.native_plc = 1,	/* FIXME: needed? */
+};
+
+static struct ast_translator opustolin16 = {
+	.name = "opustolin16", 
+	.newpvt = opustolin16_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,
+	.native_plc = 1,	/* FIXME: needed? */
+};
+
+static struct ast_translator opustolin24 = {
+	.name = "opustolin24", 
+	.newpvt = opustolin24_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,
+	.native_plc = 1,	/* FIXME: needed? */
+};
+
+static struct ast_translator opustolin48 = {
+	.name = "opustolin48", 
+	.newpvt = opustolin48_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,
+	.native_plc = 1,	/* FIXME: needed? */
+};
+
+
+/* Simple CLI interface to enable/disable debugging */
+static char *handle_cli_opus_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "opus set debug";
+		e->usage =
+			"Usage: opus set debug {status|none|normal|huge}\n"
+			"       Enable/Disable Opus debugging: normal only debugs setup and errors, huge debugs every single packet\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 4)
+		return CLI_SHOWUSAGE;
+
+	if (!strncasecmp(a->argv[a->argc-1], "status", 6)) {
+		ast_cli(a->fd, "Opus debugging %s\n", opusdebug > 1 ? "huge" : opusdebug > 0 ? "normal" : "none");
+		return CLI_SUCCESS;
+	}
+	if (!strncasecmp(a->argv[a->argc-1], "huge", 4))
+		opusdebug = 2;
+	else if (!strncasecmp(a->argv[a->argc-1], "normal", 6))
+		opusdebug = 1;
+	else if (!strncasecmp(a->argv[a->argc-1], "none", 4))
+		opusdebug = 0;
+	else
+		return CLI_SHOWUSAGE;
+
+	ast_cli(a->fd, "Opus debugging %s\n", opusdebug > 1 ? "huge" : opusdebug > 0 ? "normal" : "none");
+	return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_opus[] = {
+	AST_CLI_DEFINE(handle_cli_opus_set_debug, "Enable/Disable Opus debugging"),
+};
+
+
+/* Configuration and module setup */
+static int parse_config(int reload) {
+	/* TODO: place stuff to negotiate/enforce here */
+	return 0;
+}
+
+static int reload(void) {
+	if(parse_config(1))
+		return AST_MODULE_LOAD_DECLINE;
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void) {
+	int res = 0;
+
+	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_opus, ARRAY_LEN(cli_opus));
+
+	return res;
+}
+
+static int load_module(void) {
+	int res = 0;
+
+	if(parse_config(0))
+		return AST_MODULE_LOAD_DECLINE;
+
+	/* 8khz (nb) */
+	ast_format_set(&opustolin.src_format, AST_FORMAT_OPUS, 0);
+	ast_format_set(&opustolin.dst_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintoopus.src_format, AST_FORMAT_SLINEAR, 0);
+	ast_format_set(&lintoopus.dst_format, AST_FORMAT_OPUS, 0);
+	/* 12khz (mb) */
+	ast_format_set(&opustolin12.src_format, AST_FORMAT_OPUS, 0);
+	ast_format_set(&opustolin12.dst_format, AST_FORMAT_SLINEAR12, 0);
+	ast_format_set(&lin12toopus.src_format, AST_FORMAT_SLINEAR12, 0);
+	ast_format_set(&lin12toopus.dst_format, AST_FORMAT_OPUS, 0);
+	/* 16khz (wb) */
+	ast_format_set(&opustolin16.src_format, AST_FORMAT_OPUS, 0);
+	ast_format_set(&opustolin16.dst_format, AST_FORMAT_SLINEAR16, 0);
+	ast_format_set(&lin16toopus.src_format, AST_FORMAT_SLINEAR16, 0);
+	ast_format_set(&lin16toopus.dst_format, AST_FORMAT_OPUS, 0);
+	/* 24khz (swb) */
+	ast_format_set(&opustolin24.src_format, AST_FORMAT_OPUS, 0);
+	ast_format_set(&opustolin24.dst_format, AST_FORMAT_SLINEAR24, 0);
+	ast_format_set(&lin24toopus.src_format, AST_FORMAT_SLINEAR24, 0);
+	ast_format_set(&lin24toopus.dst_format, AST_FORMAT_OPUS, 0);
+	/* 48khz (fb) */
+	ast_format_set(&opustolin48.src_format, AST_FORMAT_OPUS, 0);
+	ast_format_set(&opustolin48.dst_format, AST_FORMAT_SLINEAR48, 0);
+	ast_format_set(&lin48toopus.src_format, AST_FORMAT_SLINEAR48, 0);
+	ast_format_set(&lin48toopus.dst_format, AST_FORMAT_OPUS, 0);
+
+	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_opus, sizeof(cli_opus) / sizeof(struct ast_cli_entry));
+
+	return res;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Opus Coder/Decoder",
+		.load = load_module,
+		.unload = unload_module,
+		.reload = reload,
+	       );
--- a/codecs/ex_opus.h	1970-01-01 03:00:00.000000000 +0300
+++ b/codecs/ex_opus.h	2013-06-10 18:25:18.477411840 +0400
@@ -0,0 +1,35 @@
+/*! \file
+ * \brief 8-bit data
+ *
+ * Copyright (C) 2008, Digium, Inc.
+ *
+ * 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,
+	};
+
+	ast_format_set(&f.subclass.format, AST_FORMAT_OPUS, 0);
+
+	return &f;
+}
--- a/configure.ac	2013-02-26 23:45:09.000000000 +0400
+++ b/configure.ac	2013-06-10 18:25:18.479439154 +0400
@@ -422,6 +422,7 @@
 AST_EXT_LIB_SETUP([NEWT], [newt], [newt])
 AST_EXT_LIB_SETUP([OGG], [OGG], [ogg])
 AST_EXT_LIB_SETUP([OPENR2], [MFR2], [openr2])
+AST_EXT_LIB_SETUP([OPUS], [Opus], [opus])
 AST_EXT_LIB_SETUP([OSPTK], [OSP Toolkit], [osptk])
 AST_EXT_LIB_SETUP([OSS], [Open Sound System], [oss])
 AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres])
@@ -2118,6 +2119,8 @@
 
 AC_SUBST(PBX_SPEEX_PREPROCESS)
 
+AST_EXT_LIB_CHECK([OPUS], [opus], [opus_encoder_create], [opus/opus.h])
+
 AST_EXT_LIB_CHECK([SQLITE], [sqlite], [sqlite_exec], [sqlite.h])
 
 AST_EXT_LIB_CHECK([SQLITE3], [sqlite3], [sqlite3_open], [sqlite3.h], [${PTHREAD_LIBS}], [${PTHREAD_CFLAGS}])
--- a/formats/format_vp8.c	1970-01-01 03:00:00.000000000 +0300
+++ b/formats/format_vp8.c	2013-06-10 18:25:18.480457409 +0400
@@ -0,0 +1,195 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@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 Save to raw, headerless VP8 data.
+ *
+ * \author Lorenzo Miniero <lorenzo@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: 328209 $")
+
+#include "asterisk/mod_format.h"
+#include "asterisk/module.h"
+#include "asterisk/endian.h"
+
+/* VP8 passthrough */
+
+#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 & 0x8000) ? 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.frametype = AST_FRAME_VIDEO;
+	ast_format_set(&s->fr.subclass.format, AST_FORMAT_VP8, 0);
+	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;
+    if (mark) {
+		ast_format_set_video_mark(&s->fr.subclass.format);
+	}
+	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 = ast_format_get_video_mark(&f->subclass.format) ? 0x8000 : 0;
+	if (f->subclass.format.id != AST_FORMAT_VP8) {
+		ast_log(LOG_WARNING, "Asked to write non-VP8 frame (%s)!\n", ast_getformatname(&f->subclass.format));
+		return -1;
+	}
+	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(AST_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(AST_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)
+{
+	ast_format_set(&vp8_f.format, AST_FORMAT_VP8, 0);
+	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
+);
--- a/include/asterisk/format.h	2012-07-13 22:41:07.000000000 +0400
+++ b/include/asterisk/format.h	2013-06-10 18:25:18.480457409 +0400
@@ -101,6 +101,8 @@
 	AST_FORMAT_SLINEAR192       = 27 + AST_FORMAT_TYPE_AUDIO,
 	AST_FORMAT_SPEEX32          = 28 + AST_FORMAT_TYPE_AUDIO,
 	AST_FORMAT_CELT             = 29 + AST_FORMAT_TYPE_AUDIO,
+	/*! Opus */
+	AST_FORMAT_OPUS             = 30 + AST_FORMAT_TYPE_AUDIO,
 
 	/*! H.261 Video */
 	AST_FORMAT_H261             = 1 + AST_FORMAT_TYPE_VIDEO,
@@ -112,6 +114,8 @@
 	AST_FORMAT_H264             = 4 + AST_FORMAT_TYPE_VIDEO,
 	/*! MPEG4 Video */
 	AST_FORMAT_MP4_VIDEO        = 5 + AST_FORMAT_TYPE_VIDEO,
+	/*! VP8 */
+	AST_FORMAT_VP8              = 6 + AST_FORMAT_TYPE_VIDEO,
 
 	/*! JPEG Images */
 	AST_FORMAT_JPEG             = 1 + AST_FORMAT_TYPE_IMAGE,
--- a/main/channel.c	2013-05-09 18:21:31.000000000 +0400
+++ b/main/channel.c	2013-06-10 18:25:18.489517352 +0400
@@ -914,6 +914,8 @@
 		AST_FORMAT_SPEEX32,
 		AST_FORMAT_SPEEX16,
 		AST_FORMAT_SPEEX,
+		/*! Opus */
+		AST_FORMAT_OPUS,
 		/*! SILK is pretty awesome. */
 		AST_FORMAT_SILK,
 		/*! CELT supports crazy high sample rates */
--- a/main/format.c	2012-12-05 06:19:43.000000000 +0400
+++ b/main/format.c	2013-06-10 18:25:18.490487801 +0400
@@ -430,6 +430,9 @@
 	/*! SpeeX Wideband (16kHz) Free Compression */
 	case AST_FORMAT_SPEEX16:
 		return (1ULL << 33);
+	/*! Opus audio (8kHz, 16kHz, 24kHz, 48Khz) */
+	case AST_FORMAT_OPUS:
+		return (1ULL << 34);
 	/*! Raw mu-law data (G.711) */
 	case AST_FORMAT_TESTLAW:
 		return (1ULL << 47);
@@ -449,6 +452,9 @@
 	/*! MPEG4 Video */
 	case AST_FORMAT_MP4_VIDEO:
 		return (1ULL << 22);
+	/*! VP8 Video */
+	case AST_FORMAT_VP8:
+		return (1ULL << 23);
 
 	/*! JPEG Images */
 	case AST_FORMAT_JPEG:
@@ -532,6 +538,9 @@
 	/*! SpeeX Wideband (16kHz) Free Compression */
 	case (1ULL << 33):
 		return ast_format_set(dst, AST_FORMAT_SPEEX16, 0);
+	/*! Opus audio (8kHz, 16kHz, 24kHz, 48Khz) */
+	case (1ULL << 34):
+		return ast_format_set(dst, AST_FORMAT_OPUS, 0);
 	/*! Raw mu-law data (G.711) */
 	case (1ULL << 47):
 		return ast_format_set(dst, AST_FORMAT_TESTLAW, 0);
@@ -551,6 +560,9 @@
 	/*! MPEG4 Video */
 	case (1ULL << 22):
 		return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0);
+	/*! VP8 Video */
+	case (1ULL << 23):
+		return ast_format_set(dst, AST_FORMAT_VP8, 0);
 
 	/*! JPEG Images */
 	case (1ULL << 16):
@@ -782,6 +794,9 @@
 			return samplerate;
 		}
 	}
+	/* Opus */
+	case AST_FORMAT_OPUS:
+		return 48000;
 	default:
 		return 8000;
 	}
@@ -1071,6 +1086,10 @@
 	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR48, 0), "slin48", 48000, "16 bit Signed Linear PCM (48kHz)", 960, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (48kHz) */
 	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR96, 0), "slin96", 96000, "16 bit Signed Linear PCM (96kHz)", 1920, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (96kHz) */
 	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR192, 0), "slin192", 192000, "16 bit Signed Linear PCM (192kHz)", 3840, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (192kHz) */
+	/* Opus (FIXME: real min is 3/5/10, real max is 120...) */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_OPUS, 0), "opus", 48000, "Opus Codec", 10, 20, 60, 20, 20, 0, 0);   /*!< codec_opus.c */
+	/* VP8 (passthrough) */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0), "vp8", 0, "VP8 Video", 0, 0, 0, 0 ,0 ,0, 0);         /*!< Passthrough support, see format_h263.c */
 
 	return 0;
 }
--- a/main/frame.c	2012-07-24 20:54:26.000000000 +0400
+++ b/main/frame.c	2013-06-10 18:25:18.490487801 +0400
@@ -1002,6 +1002,40 @@
 	return cnt;
 }
 
+/* Opus: copied from opus_decoder.c */
+static int opus_samples(unsigned char *data, int len) {
+	/* Do opus_packet_get_nb_frames first */
+	int count, frames;
+	if (len<1) {
+		return 0;	/* FIXME OPUS_BAD_ARG */
+	} else {
+		count = data[0]&0x3;
+		if (count==0)
+			frames = 1;
+		else if (count!=3)
+			frames = 2;
+		else if (len<2)
+			return 0;	/* FIXME OPUS_INVALID_PACKET */
+		else
+			frames = data[1]&0x3F;
+	}
+	/* The, do a opus_packet_get_samples_per_frame */
+   int audiosize, Fs = 48000;
+   if (data[0]&0x80) {
+      audiosize = ((data[0]>>3)&0x3);
+      audiosize = (Fs<<audiosize)/400;
+   } else if ((data[0]&0x60) == 0x60) {
+      audiosize = (data[0]&0x08) ? Fs/50 : Fs/100;
+   } else {
+      audiosize = ((data[0]>>3)&0x3);
+      if (audiosize == 3)
+         audiosize = Fs*60/1000;
+      else
+         audiosize = (Fs<<audiosize)/100;
+   }
+   return frames*audiosize;
+}
+
 int ast_codec_get_samples(struct ast_frame *f)
 {
 	int samples = 0;
@@ -1083,6 +1117,10 @@
 		/* TODO The assumes 20ms delivery right now, which is incorrect */
 		samples = ast_format_rate(&f->subclass.format) / 50;
 		break;
+	/* Opus */
+	case AST_FORMAT_OPUS:
+		samples = opus_samples(f->data.ptr, f->datalen);
+		break;
 	default:
 		ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(&f->subclass.format));
 	}
--- a/main/rtp_engine.c	2013-02-13 00:31:52.000000000 +0400
+++ b/main/rtp_engine.c	2013-06-10 18:25:18.494532446 +0400
@@ -2289,6 +2289,9 @@
 	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SIREN7, 0), 0, "audio", "G7221", 16000);
 	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SIREN14, 0), 0, "audio", "G7221", 32000);
 	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), 0, "audio", "G719", 48000);
+	/* Opus and VP8 */
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_OPUS, 0), 0,  "audio", "opus", 48000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0), 0,  "video", "VP8", 90000);
 
 	/* Define the static rtp payload mappings */
 	add_static_payload(0, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), 0);
@@ -2330,6 +2333,9 @@
 	add_static_payload(118, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0), 0); /* 16 Khz signed linear */
 	add_static_payload(119, ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), 0);
 	add_static_payload(121, NULL, AST_RTP_CISCO_DTMF);   /* Must be type 121 */
+	/* Opus and VP8 */
+	add_static_payload(100, ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0), 0);
+	add_static_payload(107, ast_format_set(&tmpfmt, AST_FORMAT_OPUS, 0), 0);
 
 	return 0;
 }
--- a/makeopts.in	2013-01-19 01:10:23.000000000 +0400
+++ b/makeopts.in	2013-06-10 18:25:18.495508515 +0400
@@ -262,6 +262,9 @@
 SPEEXDSP_INCLUDE=@SPEEXDSP_INCLUDE@
 SPEEXDSP_LIB=@SPEEXDSP_LIB@
 
+OPUS_INCLUDE=@OPUS_INCLUDE@
+OPUS_LIB=@OPUS_LIB@
+
 SQLITE_INCLUDE=@SQLITE_INCLUDE@
 SQLITE_LIB=@SQLITE_LIB@
 
--- a/res/res_rtp_asterisk.c	2013-03-27 21:06:07.000000000 +0400
+++ b/res/res_rtp_asterisk.c	2013-06-10 18:25:18.497487325 +0400
@@ -91,6 +91,8 @@
 #define RTCP_PT_SDES    202
 #define RTCP_PT_BYE     203
 #define RTCP_PT_APP     204
+/* VP8: RTCP Feedback */
+#define RTCP_PT_PSFB    206
 
 #define RTP_MTU		1200
 #define DTMF_SAMPLE_RATE_MS    8 /*!< DTMF samples per millisecond */
@@ -347,6 +349,9 @@
 	double normdevrtt;
 	double stdevrtt;
 	unsigned int rtt_count;
+
+	/* VP8: sequence number for the RTCP FIR FCI */
+	int firseq;
 
 #ifdef HAVE_OPENSSL_SRTP
 	struct dtls_details dtls; /*!< DTLS state information */
@@ -2615,6 +2620,41 @@
 		return 0;
 	}
 
+	/* VP8: is this a request to send a RTCP FIR? */
+	if(frame->frametype == AST_FRAME_CONTROL && frame->subclass.integer == AST_CONTROL_VIDUPDATE) {
+		ast_log(LOG_WARNING, "res_rtp_asterisk, requested to send a RTCP FIR packet to the peer\n");
+		struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+		if (!rtp || !rtp->rtcp)
+			return 0;
+		unsigned int *rtcpheader;
+		char bdata[1024];
+		if (ast_sockaddr_isnull(&rtp->rtcp->them)) {
+			/*
+			 * RTCP was stopped.
+			 */
+			return 0;
+		}
+		/* Prepare RTCP FIR (PT=206, FMT=4) */
+		rtp->rtcp->firseq++;
+		if(rtp->rtcp->firseq == 256)
+			rtp->rtcp->firseq = 0;
+		int len = 20;
+		int ice;
+		rtcpheader = (unsigned int *)bdata;
+		rtcpheader[0] = htonl((2 << 30) | (4 << 24) | (RTCP_PT_PSFB << 16) | ((len/4)-1));
+		rtcpheader[1] = htonl(rtp->ssrc);
+		rtcpheader[2] = htonl(rtp->themssrc);
+		rtcpheader[3] = htonl(rtp->themssrc);	/* FCI: SSRC */
+		rtcpheader[4] = htonl(rtp->rtcp->firseq << 24);			/* FCI: Sequence number */
+		int res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &rtp->rtcp->them, &ice);
+		if (res < 0) {
+			ast_log(LOG_ERROR, "RTCP FIR transmission error: %s\n",strerror(errno));
+			return 0;
+		}
+		ast_log(LOG_WARNING, " >> RTCP FIR packet sent to the peer!\n");
+		return 0;
+	}
+
 	/* If there is no data length we can't very well send the packet */
 	if (!frame->datalen) {
 		ast_debug(1, "Received frame with no data for RTP instance '%p' so dropping frame\n", instance);
@@ -2666,6 +2706,8 @@
 		case AST_FORMAT_SIREN7:
 		case AST_FORMAT_SIREN14:
 		case AST_FORMAT_G719:
+		/* Opus */
+		case AST_FORMAT_OPUS:
 			/* these are all frame-based codecs and cannot be safely run through
 			   a smoother */
 			break;