asterisk/asterisk-11.5.0_opus+vp8.diff

1186 lines
37 KiB
Diff

--- 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;