diff -urN asterisk-11.1.2/channels/chan_sip.c asterisk-11.1.2-opus-passthrough/channels/chan_sip.c --- asterisk-11.1.2/channels/chan_sip.c 2013-01-02 20:23:44.000000000 +0100 +++ asterisk-11.1.2-opus-passthrough/channels/chan_sip.c 2013-07-18 11:20:46.519468160 +0200 @@ -7724,8 +7724,24 @@ 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) { + /* 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; @@ -11041,7 +11057,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 %d\n", mimeSubtype, codec); @@ -12583,7 +12601,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/%d\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/%d/2\r\n", rtp_code, mime, rate); + else + ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code, mime, rate); ast_format_sdp_generate(format, rtp_code, a_buf); @@ -12646,6 +12668,10 @@ ast_str_append(m_buf, 0, " %d", rtp_code); ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code, subtype, rate); + /* VP8: add RTCP FIR support */ + if((int) format->id == AST_FORMAT_VP8) { + ast_str_append(a_buf, 0, "a=rtcp-fb:* ccm fir\r\n"); + } ast_format_sdp_generate(format, rtp_code, a_buf); } diff -urN asterisk-11.1.2/include/asterisk/format.h asterisk-11.1.2-opus-passthrough/include/asterisk/format.h --- asterisk-11.1.2/include/asterisk/format.h 2012-07-13 20:41:07.000000000 +0200 +++ asterisk-11.1.2-opus-passthrough/include/asterisk/format.h 2013-07-18 10:35:48.309453118 +0200 @@ -29,6 +29,7 @@ #include "asterisk/astobj2.h" #include "asterisk/silk.h" #include "asterisk/celt.h" +#include "asterisk/opus.h" #define AST_FORMAT_ATTR_SIZE 64 #define AST_FORMAT_INC 100000 @@ -101,6 +102,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 +115,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, diff -urN asterisk-11.1.2/include/asterisk/opus.h asterisk-11.1.2-opus-passthrough/include/asterisk/opus.h --- asterisk-11.1.2/include/asterisk/opus.h 1970-01-01 01:00:00.000000000 +0100 +++ asterisk-11.1.2-opus-passthrough/include/asterisk/opus.h 2013-07-18 11:22:48.810809294 +0200 @@ -0,0 +1,41 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2011, Digium, Inc. + * + * David Vossel + * + * 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 Opus Format Attributes (http://tools.ietf.org/html/draft-ietf-payload-rtp-opus) + * + * \author Lorenzo Miniero + */ +#ifndef _AST_FORMAT_OPUS_H_ +#define _AST_FORMAT_OPUS_H_ + +/*! Opus format attribute key value pairs, all are accessible through ast_format_get_value()*/ +enum opus_attr_keys { + OPUS_ATTR_KEY_MAX_BITRATE, /*! value is an int (6000-510000 in spec). */ + OPUS_ATTR_KEY_MAX_PLAYRATE, /*! value is an int (8000-48000), maximum output rate the receiver can render. */ + OPUS_ATTR_KEY_MINPTIME, /*! value is an int (3-120 in spec, 10-60 in format.c), decoder's minimum length of time in milliseconds. */ + OPUS_ATTR_KEY_STEREO, /*! value is an int, 1 prefer receiving stereo, 0 prefer mono. */ + OPUS_ATTR_KEY_CBR, /*! value is an int, 1 use constant bitrate, 0 use variable bitrate. */ + OPUS_ATTR_KEY_FEC, /*! value is an int, 1 encode with FEC, 0 do not use FEC. */ + OPUS_ATTR_KEY_DTX, /*! value is an int, 1 dtx is enabled, 0 dtx not enabled. */ + OPUS_ATTR_KEY_SPROP_CAPTURE_RATE, /*! value is an int (8000-48000), likely input rate we're going to produce. */ + OPUS_ATTR_KEY_SPROP_STEREO, /*! value is an int, 1 likely to send stereo, 0 likely to send mono. */ +}; + +#endif /* _AST_FORMAT_OPUS_H */ diff -urN asterisk-11.1.2/main/channel.c asterisk-11.1.2-opus-passthrough/main/channel.c --- asterisk-11.1.2/main/channel.c 2013-01-02 20:23:44.000000000 +0100 +++ asterisk-11.1.2-opus-passthrough/main/channel.c 2013-07-03 11:04:06.515699866 +0200 @@ -909,6 +909,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 */ diff -urN asterisk-11.1.2/main/format.c asterisk-11.1.2-opus-passthrough/main/format.c --- asterisk-11.1.2/main/format.c 2012-10-02 03:27:19.000000000 +0200 +++ asterisk-11.1.2-opus-passthrough/main/format.c 2013-07-03 11:04:12.262613954 +0200 @@ -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; } @@ -1072,6 +1087,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; } diff -urN asterisk-11.1.2/main/frame.c asterisk-11.1.2-opus-passthrough/main/frame.c --- asterisk-11.1.2/main/frame.c 2012-07-24 18:54:26.000000000 +0200 +++ asterisk-11.1.2-opus-passthrough/main/frame.c 2013-07-18 11:56:16.675089967 +0200 @@ -1083,6 +1083,10 @@ /* TODO The assumes 20ms delivery right now, which is incorrect */ samples = ast_format_rate(&f->subclass.format) / 50; break; + case AST_FORMAT_OPUS: + /* TODO The assumes 20ms delivery right now, which is incorrect */ + samples = 960; + break; default: ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(&f->subclass.format)); } diff -urN asterisk-11.1.2/main/rtp_engine.c asterisk-11.1.2-opus-passthrough/main/rtp_engine.c --- asterisk-11.1.2/main/rtp_engine.c 2012-09-20 20:18:47.000000000 +0200 +++ asterisk-11.1.2-opus-passthrough/main/rtp_engine.c 2013-07-03 11:04:21.529480072 +0200 @@ -2268,6 +2268,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); @@ -2309,6 +2312,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; } diff -urN asterisk-11.1.2/res/res_format_attr_opus.c asterisk-11.1.2-opus-passthrough/res/res_format_attr_opus.c --- asterisk-11.1.2/res/res_format_attr_opus.c 1970-01-01 01:00:00.000000000 +0100 +++ asterisk-11.1.2-opus-passthrough/res/res_format_attr_opus.c 2013-07-18 15:14:41.701160708 +0200 @@ -0,0 +1,322 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2011, Digium, Inc. + * + * David Vossel + * + * 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 Opus format attribute interface + * + * \author Lorenzo Miniero + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370055 $") + +#include "asterisk/module.h" +#include "asterisk/format.h" + +/*! + * \brief Opus attribute structure. + * + * \note http://tools.ietf.org/html/draft-ietf-payload-rtp-opus-00. + */ +struct opus_attr { + unsigned int maxbitrate; /* Default 64-128 kb/s for FB stereo music */ + unsigned int maxplayrate /* Default 48000 */; + unsigned int minptime; /* Default 3, but it's 10 in format.c */ + unsigned int stereo; /* Default 0 */ + unsigned int cbr; /* Default 0 */ + unsigned int fec; /* Default 0 */ + unsigned int dtx; /* Default 0 */ + unsigned int spropmaxcapturerate; /* Default 48000 */ + unsigned int spropstereo; /* Default 0 */ +}; + +static int opus_sdp_parse(struct ast_format_attr *format_attr, const char *attributes) +{ + struct opus_attr *attr = (struct opus_attr *) format_attr; + unsigned int val; + + if (strstr(attributes, "maxplaybackrate") && sscanf(strstr(attributes, "maxplaybackrate"), "maxplaybackrate=%30u", &val) == 1) { + attr->maxplayrate = val; + } + if (strstr(attributes, "sprop-maxcapturerate") && sscanf(strstr(attributes, "sprop-maxcapturerate"), "sprop-maxcapturerate=%30u", &val) == 1) { + attr->spropmaxcapturerate = val; + } + if (strstr(attributes, "minptime") && sscanf(strstr(attributes, "minptime"), "minptime=%30u", &val) == 1) { + attr->minptime = val; + } + if (strstr(attributes, "maxaveragebitrate") && sscanf(strstr(attributes, "maxaveragebitrate"), "maxaveragebitrate=%30u", &val) == 1) { + attr->maxbitrate = val; + } + if (strstr(attributes, " stereo") && sscanf(strstr(attributes, " stereo"), " stereo=%30u", &val) == 1) { + attr->stereo = val; + } + if (strstr(attributes, ";stereo") && sscanf(strstr(attributes, ";stereo"), ";stereo=%30u", &val) == 1) { + attr->stereo = val; + } + if (strstr(attributes, "sprop-stereo") && sscanf(strstr(attributes, "sprop-stereo"), "sprop-stereo=%30u", &val) == 1) { + attr->spropstereo = val; + } + if (strstr(attributes, "cbr") && sscanf(strstr(attributes, "cbr"), "cbr=%30u", &val) == 1) { + attr->cbr = val; + } + if (strstr(attributes, "useinbandfec") && sscanf(strstr(attributes, "useinbandfec"), "useinbandfec=%30u", &val) == 1) { + attr->fec = val; + } + if (strstr(attributes, "usedtx") && sscanf(strstr(attributes, "usedtx"), "usedtx=%30u", &val) == 1) { + attr->dtx = val; + } + + return 0; +} + +static void opus_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str) +{ + struct opus_attr *attr = (struct opus_attr *) format_attr; + + /* FIXME should we only generate attributes that were explicitly set? */ + ast_str_append(str, 0, + "a=fmtp:%d " + "maxplaybackrate=%d;" + "sprop-maxcapturerate=%d;" + "minptime=%d;" + "maxaveragebitrate=%d;" + "stereo=%d;" + "sprop-stereo=%d;" + "cbr=%d;" + "useinbandfec=%d;" + "usedtx=%d\r\n", + payload, + attr->maxplayrate ? attr->maxplayrate : 48000, /* maxplaybackrate */ + attr->spropmaxcapturerate ? attr->spropmaxcapturerate : 48000, /* sprop-maxcapturerate */ + attr->minptime > 10 ? attr->minptime : 10, /* minptime */ + attr->maxbitrate ? attr->maxbitrate : 20000, /* maxaveragebitrate */ + attr->stereo ? 1 : 0, /* stereo */ + attr->spropstereo ? 1 : 0, /* sprop-stereo */ + attr->cbr ? 1 : 0, /* cbr */ + attr->fec ? 1 : 0, /* useinbandfec */ + attr->dtx ? 1 : 0 /* usedtx */ + ); + /* FIXME what about maxptime? that's not an Opus specific attribute */ + ast_str_append(str, 0, "a=maxptime:%d\r\n", 60); /* As defined in format.c */ +} + +static int opus_get_val(const struct ast_format_attr *fattr, int key, void *result) +{ + const struct opus_attr *attr = (struct opus_attr *) fattr; + int *val = result; + + switch (key) { + case OPUS_ATTR_KEY_MAX_BITRATE: + *val = attr->maxbitrate; + break; + case OPUS_ATTR_KEY_MAX_PLAYRATE: + *val = attr->maxplayrate; + break; + case OPUS_ATTR_KEY_MINPTIME: + *val = attr->minptime; + break; + case OPUS_ATTR_KEY_STEREO: + *val = attr->stereo; + break; + case OPUS_ATTR_KEY_CBR: + *val = attr->cbr; + break; + case OPUS_ATTR_KEY_FEC: + *val = attr->fec; + break; + case OPUS_ATTR_KEY_DTX: + *val = attr->dtx; + break; + case OPUS_ATTR_KEY_SPROP_CAPTURE_RATE: + *val = attr->spropmaxcapturerate; + break; + case OPUS_ATTR_KEY_SPROP_STEREO: + *val = attr->spropstereo; + break; + default: + ast_log(LOG_WARNING, "unknown attribute type %d\n", key); + return -1; + } + return 0; +} + +static int opus_isset(const struct ast_format_attr *fattr, va_list ap) +{ + enum opus_attr_keys key; + const struct opus_attr *attr = (struct opus_attr *) fattr; + + for (key = va_arg(ap, int); + key != AST_FORMAT_ATTR_END; + key = va_arg(ap, int)) + { + switch (key) { + case OPUS_ATTR_KEY_MAX_BITRATE: + if (attr->maxbitrate != (va_arg(ap, int))) { + return -1; + } + break; + case OPUS_ATTR_KEY_MAX_PLAYRATE: + if (attr->maxplayrate != (va_arg(ap, int))) { + return -1; + } + break; + case OPUS_ATTR_KEY_MINPTIME: + if (attr->minptime != (va_arg(ap, int))) { + return -1; + } + break; + case OPUS_ATTR_KEY_STEREO: + if (attr->stereo != (va_arg(ap, int))) { + return -1; + } + break; + case OPUS_ATTR_KEY_CBR: + if (attr->cbr != (va_arg(ap, int))) { + return -1; + } + break; + case OPUS_ATTR_KEY_FEC: + if (attr->fec != (va_arg(ap, int))) { + return -1; + } + break; + case OPUS_ATTR_KEY_DTX: + if (attr->dtx != (va_arg(ap, int))) { + return -1; + } + break; + case OPUS_ATTR_KEY_SPROP_CAPTURE_RATE: + if (attr->spropmaxcapturerate != (va_arg(ap, int))) { + return -1; + } + break; + case OPUS_ATTR_KEY_SPROP_STEREO: + if (attr->spropstereo != (va_arg(ap, int))) { + return -1; + } + break; + default: + ast_log(LOG_WARNING, "unknown attribute type %d\n", key); + return -1; + } + } + return 0; +} +static int opus_getjoint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result) +{ + struct opus_attr *attr1 = (struct opus_attr *) fattr1; + struct opus_attr *attr2 = (struct opus_attr *) fattr2; + struct opus_attr *attr_res = (struct opus_attr *) result; + int joint = 0; + + /* Only do dtx if both sides want it. DTX is a trade off between + * computational complexity and bandwidth. */ + attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0; + + /* Only do FEC if both sides want it. If a peer specifically requests not + * to receive with FEC, it may be a waste of bandwidth. */ + attr_res->fec = attr1->fec && attr2->fec ? 1 : 0; + + /* Only do stereo if both sides want it. If a peer specifically requests not + * to receive stereo signals, it may be a waste of bandwidth. */ + attr_res->stereo = attr1->stereo && attr2->stereo ? 1 : 0; + + /* FIXME: do we need to join other attributes as well, e.g., minptime, cbr, etc.? */ + + return joint; +} + +static void opus_set(struct ast_format_attr *fattr, va_list ap) +{ + enum opus_attr_keys key; + struct opus_attr *attr = (struct opus_attr *) fattr; + + for (key = va_arg(ap, int); + key != AST_FORMAT_ATTR_END; + key = va_arg(ap, int)) + { + switch (key) { + case OPUS_ATTR_KEY_MAX_BITRATE: + attr->maxbitrate = (va_arg(ap, int)); + break; + case OPUS_ATTR_KEY_MAX_PLAYRATE: + attr->maxplayrate = (va_arg(ap, int)); + break; + case OPUS_ATTR_KEY_MINPTIME: + attr->minptime = (va_arg(ap, int)); + break; + case OPUS_ATTR_KEY_STEREO: + attr->stereo = (va_arg(ap, int)); + break; + case OPUS_ATTR_KEY_CBR: + attr->cbr = (va_arg(ap, int)); + break; + case OPUS_ATTR_KEY_FEC: + attr->fec = (va_arg(ap, int)); + break; + case OPUS_ATTR_KEY_DTX: + attr->dtx = (va_arg(ap, int)); + break; + case OPUS_ATTR_KEY_SPROP_CAPTURE_RATE: + attr->spropmaxcapturerate = (va_arg(ap, int)); + break; + case OPUS_ATTR_KEY_SPROP_STEREO: + attr->spropstereo = (va_arg(ap, int)); + break; + default: + ast_log(LOG_WARNING, "unknown attribute type %d\n", key); + } + } +} + +static struct ast_format_attr_interface opus_interface = { + .id = AST_FORMAT_OPUS, + .format_attr_get_joint = opus_getjoint, + .format_attr_set = opus_set, + .format_attr_isset = opus_isset, + .format_attr_get_val = opus_get_val, + .format_attr_sdp_parse = opus_sdp_parse, + .format_attr_sdp_generate = opus_sdp_generate, +}; + +static int load_module(void) +{ + if (ast_format_attr_reg_interface(&opus_interface)) { + return AST_MODULE_LOAD_DECLINE; + } + + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + ast_format_attr_unreg_interface(&opus_interface); + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Opus Format Attribute Module", + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_CHANNEL_DEPEND, +); diff -urN asterisk-11.1.2/res/res_rtp_asterisk.c asterisk-11.1.2-opus-passthrough/res/res_rtp_asterisk.c --- asterisk-11.1.2/res/res_rtp_asterisk.c 2012-10-11 18:04:19.000000000 +0200 +++ asterisk-11.1.2-opus-passthrough/res/res_rtp_asterisk.c 2013-07-18 12:06:29.406813101 +0200 @@ -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 @@ -341,6 +343,9 @@ double normdevrtt; double stdevrtt; unsigned int rtt_count; + + /* VP8: sequence number for the RTCP FIR FCI */ + int firseq; }; struct rtp_red { @@ -2599,6 +2604,39 @@ return 0; } + /* VP8: is this a request to send a RTCP FIR? */ + if(frame->frametype == AST_FRAME_CONTROL && frame->subclass.integer == AST_CONTROL_VIDUPDATE) { + 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; + } + 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); @@ -2650,6 +2688,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; @@ -3308,6 +3348,8 @@ } break; case RTCP_PT_FUR: + /* Handle RTCP FIR as FUR */ + case RTCP_PT_PSFB: if (rtcp_debug_test_addr(&addr)) ast_verbose("Received an RTCP Fast Update Request\n"); rtp->f.frametype = AST_FRAME_CONTROL;