diff --git a/doc/example/example.js b/doc/example/example.js
index c9ca877e9..0681102ce 100644
--- a/doc/example/example.js
+++ b/doc/example/example.js
@@ -12,6 +12,9 @@ var confOptions = {
openSctp: true
}
+
+var isJoined = false;
+
/**
* Handles local tracks.
* @param tracks Array with JitsiTrack objects
@@ -23,15 +26,15 @@ function onLocalTracks(tracks)
{
localTracks[i].addEventListener(JitsiMeetJS.events.track.TRACK_AUDIO_LEVEL_CHANGED,
function (audioLevel) {
- console.debug("Audio Level local: " + audioLevel);
+ console.log("Audio Level local: " + audioLevel);
});
localTracks[i].addEventListener(JitsiMeetJS.events.track.TRACK_MUTE_CHANGED,
function () {
- console.debug("local track muted");
+ console.log("local track muted");
});
localTracks[i].addEventListener(JitsiMeetJS.events.track.TRACK_STOPPED,
function () {
- console.debug("local track stoped");
+ console.log("local track stoped");
});
if(localTracks[i].getType() == "video") {
$("body").append("");
@@ -40,6 +43,8 @@ function onLocalTracks(tracks)
$("body").append("");
localTracks[i].attach($("#localAudio" + i ));
}
+ if(isJoined)
+ room.addTrack(localTracks[i]);
}
}
@@ -56,21 +61,21 @@ function onRemoteTrack(track) {
var idx = remoteTracks[participant].push(track);
track.addEventListener(JitsiMeetJS.events.track.TRACK_AUDIO_LEVEL_CHANGED,
function (audioLevel) {
- console.debug("Audio Level remote: " + audioLevel);
+ console.log("Audio Level remote: " + audioLevel);
});
track.addEventListener(JitsiMeetJS.events.track.TRACK_MUTE_CHANGED,
function () {
- console.debug("remote track muted");
+ console.log("remote track muted");
});
track.addEventListener(JitsiMeetJS.events.track.TRACK_STOPPED,
function () {
- console.debug("remote track stoped");
+ console.log("remote track stoped");
});
var id = participant + track.getType() + idx;
if(track.getType() == "video") {
$("body").append("");
} else {
- $("body").append("");
+ $("body").append("");
}
track.attach($("#" + id));
}
@@ -80,6 +85,7 @@ function onRemoteTrack(track) {
*/
function onConferenceJoined () {
console.log("conference joined!");
+ isJoined = true;
for(var i = 0; i < localTracks.length; i++)
room.addTrack(localTracks[i]);
}
@@ -99,16 +105,16 @@ function onConnectionSuccess(){
room = connection.initJitsiConference("conference2", confOptions);
room.on(JitsiMeetJS.events.conference.TRACK_ADDED, onRemoteTrack);
room.on(JitsiMeetJS.events.conference.TRACK_REMOVED, function (track) {
- console.debug("track removed!!!" + track);
+ console.log("track removed!!!" + track);
});
room.on(JitsiMeetJS.events.conference.CONFERENCE_JOINED, onConferenceJoined);
room.on(JitsiMeetJS.events.conference.USER_JOINED, function(id){ remoteTracks[id] = [];});
room.on(JitsiMeetJS.events.conference.USER_LEFT, onUserLeft);
room.on(JitsiMeetJS.events.conference.TRACK_MUTE_CHANGED, function (track) {
- console.debug(track.getType() + " - " + track.isMuted());
+ console.log(track.getType() + " - " + track.isMuted());
});
room.on(JitsiMeetJS.events.conference.DISPLAY_NAME_CHANGED, function (userID, displayName) {
- console.debug(userID + " - " + displayName);
+ console.log(userID + " - " + displayName);
});
room.on(JitsiMeetJS.events.conference.TRACK_AUDIO_LEVEL_CHANGED,
function(userID, audioLevel){
@@ -181,9 +187,9 @@ JitsiMeetJS.init(initOptions).then(function(){
then(onLocalTracks).catch(function (error) {
console.log(error);
});
- }).catch(function (error) {
- console.log(error);
- });
+}).catch(function (error) {
+ console.log(error);
+});
var connection = null;
var room = null;
diff --git a/lib-jitsi-meet.js b/lib-jitsi-meet.js
index ccd575b05..f7cc9fe08 100644
--- a/lib-jitsi-meet.js
+++ b/lib-jitsi-meet.js
@@ -1346,7 +1346,6 @@ function JitsiLocalTrack(stream, videoType,
this.dontFireRemoveEvent = false;
this.resolution = resolution;
this.startMuted = false;
- this.isLocal = true;
var self = this;
JitsiTrack.call(this, null, stream,
function () {
@@ -1517,7 +1516,6 @@ function JitsiRemoteTrack(RTC, data, sid, ssrc) {
this.videoType = data.videoType;
this.ssrc = ssrc;
this.muted = false;
- this.isLocal = false;
if((this.type === JitsiTrack.AUDIO && data.audiomuted)
|| (this.type === JitsiTrack.VIDEO && data.videomuted)) {
this.muted = true;
@@ -3391,9 +3389,8 @@ module.exports = ScreenObtainer;
}).call(this,"/modules/RTC/ScreenObtainer.js")
},{"../../service/desktopsharing/DesktopSharingEventTypes":82,"./RTCBrowserType":17,"./adapter.screenshare":20,"jitsi-meet-logger":47}],20:[function(require,module,exports){
(function (__filename){
-/*! adapterjs - v0.12.0 - 2015-09-04 */
+/*! adapterjs - v0.12.3 - 2015-11-16 */
var console = require("jitsi-meet-logger").getLogger(__filename);
-
// Adapter's interface.
var AdapterJS = AdapterJS || {};
@@ -3411,7 +3408,7 @@ AdapterJS.options = AdapterJS.options || {};
// AdapterJS.options.hidePluginInstallPrompt = true;
// AdapterJS version
-AdapterJS.VERSION = '0.12.0';
+AdapterJS.VERSION = '0.12.3';
// This function will be called when the WebRTC API is ready to be used
// Whether it is the native implementation (Chrome, Firefox, Opera) or
@@ -4001,7 +3998,7 @@ if (navigator.mozGetUserMedia) {
createIceServers = function (urls, username, password) {
var iceServers = [];
- for (i = 0; i < urls.length; i++) {
+ for (var i = 0; i < urls.length; i++) {
var iceServer = createIceServer(urls[i], username, password);
if (iceServer !== null) {
iceServers.push(iceServer);
@@ -4091,7 +4088,7 @@ if (navigator.mozGetUserMedia) {
'username' : username
};
} else {
- for (i = 0; i < urls.length; i++) {
+ for (var i = 0; i < urls.length; i++) {
var iceServer = createIceServer(urls[i], username, password);
if (iceServer !== null) {
iceServers.push(iceServer);
@@ -4393,12 +4390,13 @@ if (navigator.mozGetUserMedia) {
return;
}
- var streamId
+ var streamId;
if (stream === null) {
streamId = '';
- }
- else {
- stream.enableSoundTracks(true); // TODO: remove on 0.12.0
+ } else {
+ if (typeof stream.enableSoundTracks !== 'undefined') {
+ stream.enableSoundTracks(true);
+ }
streamId = stream.id;
}
@@ -4440,16 +4438,13 @@ if (navigator.mozGetUserMedia) {
var height = '';
var width = '';
- if (element.getBoundingClientRect) {
- var rectObject = element.getBoundingClientRect();
- width = rectObject.width + 'px';
- height = rectObject.height + 'px';
+ if (element.clientWidth || element.clientHeight) {
+ width = element.clientWidth;
+ height = element.clientHeight;
}
- else if (element.width) {
+ else if (element.width || element.height) {
width = element.width;
height = element.height;
- } else {
- // TODO: What scenario could bring us here?
}
element.parentNode.insertBefore(frag, element);
@@ -4468,19 +4463,7 @@ if (navigator.mozGetUserMedia) {
element.setStreamId(streamId);
}
var newElement = document.getElementById(elementId);
- newElement.onplaying = (element.onplaying) ? element.onplaying : function (arg) {};
- newElement.onplay = (element.onplay) ? element.onplay : function (arg) {};
- newElement.onclick = (element.onclick) ? element.onclick : function (arg) {};
- if (isIE) { // on IE the event needs to be plugged manually
- newElement.attachEvent('onplaying', newElement.onplaying);
- newElement.attachEvent('onplay', newElement.onplay);
- newElement._TemOnClick = function (id) {
- var arg = {
- srcElement : document.getElementById(id)
- };
- newElement.onclick(arg);
- };
- }
+ AdapterJS.forwardEventHandlers(newElement, element, Object.getPrototypeOf(element));
return newElement;
};
@@ -4503,6 +4486,32 @@ if (navigator.mozGetUserMedia) {
}
};
+ AdapterJS.forwardEventHandlers = function (destElem, srcElem, prototype) {
+
+ properties = Object.getOwnPropertyNames( prototype );
+
+ for(prop in properties) {
+ propName = properties[prop];
+
+ if (typeof(propName.slice) === 'function') {
+ if (propName.slice(0,2) == 'on' && srcElem[propName] != null) {
+ if (isIE) {
+ destElem.attachEvent(propName,srcElem[propName]);
+ } else {
+ destElem.addEventListener(propName.slice(2), srcElem[propName], false)
+ }
+ } else {
+ //TODO (http://jira.temasys.com.sg/browse/TWP-328) Forward non-event properties ?
+ }
+ }
+ }
+
+ var subPrototype = Object.getPrototypeOf(prototype)
+ if(subPrototype != null) {
+ AdapterJS.forwardEventHandlers(destElem, srcElem, subPrototype);
+ }
+ }
+
RTCIceCandidate = function (candidate) {
if (!candidate.sdpMid) {
candidate.sdpMid = '';
@@ -9659,7 +9668,7 @@ function TraceablePeerConnection(ice_config, constraints, session) {
var Interop = require('sdp-interop').Interop;
this.interop = new Interop();
var Simulcast = require('sdp-simulcast');
- this.simulcast = new Simulcast({numOfLayers: 2, explodeRemoteSimulcast: false});
+ this.simulcast = new Simulcast({numOfLayers: 3, explodeRemoteSimulcast: false});
// override as desired
this.trace = function (what, info) {
@@ -10083,7 +10092,7 @@ TraceablePeerConnection.prototype.getStats = function(callback, errback) {
module.exports = TraceablePeerConnection;
}).call(this,"/modules/xmpp/TraceablePeerConnection.js")
-},{"../../service/xmpp/XMPPEvents":85,"../RTC/RTC":16,"../RTC/RTCBrowserType.js":17,"./LocalSSRCReplacement":29,"jitsi-meet-logger":47,"sdp-interop":65,"sdp-simulcast":68,"sdp-transform":75}],34:[function(require,module,exports){
+},{"../../service/xmpp/XMPPEvents":85,"../RTC/RTC":16,"../RTC/RTCBrowserType.js":17,"./LocalSSRCReplacement":29,"jitsi-meet-logger":47,"sdp-interop":65,"sdp-simulcast":72,"sdp-transform":75}],34:[function(require,module,exports){
(function (__filename){
/* global $, $iq, APP, config, messageHandler,
roomName, sessionTerminated, Strophe, Util */
@@ -21592,7 +21601,487 @@ exports.parse = function(sdp) {
};
-},{"sdp-transform":75}],68:[function(require,module,exports){
+},{"sdp-transform":69}],68:[function(require,module,exports){
+var grammar = module.exports = {
+ v: [{
+ name: 'version',
+ reg: /^(\d*)$/
+ }],
+ o: [{ //o=- 20518 0 IN IP4 203.0.113.1
+ // NB: sessionId will be a String in most cases because it is huge
+ name: 'origin',
+ reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
+ names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
+ format: "%s %s %d %s IP%d %s"
+ }],
+ // default parsing of these only (though some of these feel outdated)
+ s: [{ name: 'name' }],
+ i: [{ name: 'description' }],
+ u: [{ name: 'uri' }],
+ e: [{ name: 'email' }],
+ p: [{ name: 'phone' }],
+ z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly..
+ r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly
+ //k: [{}], // outdated thing ignored
+ t: [{ //t=0 0
+ name: 'timing',
+ reg: /^(\d*) (\d*)/,
+ names: ['start', 'stop'],
+ format: "%d %d"
+ }],
+ c: [{ //c=IN IP4 10.47.197.26
+ name: 'connection',
+ reg: /^IN IP(\d) (\S*)/,
+ names: ['version', 'ip'],
+ format: "IN IP%d %s"
+ }],
+ b: [{ //b=AS:4000
+ push: 'bandwidth',
+ reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
+ names: ['type', 'limit'],
+ format: "%s:%s"
+ }],
+ m: [{ //m=video 51744 RTP/AVP 126 97 98 34 31
+ // NB: special - pushes to session
+ // TODO: rtp/fmtp should be filtered by the payloads found here?
+ reg: /^(\w*) (\d*) ([\w\/]*)(?: (.*))?/,
+ names: ['type', 'port', 'protocol', 'payloads'],
+ format: "%s %d %s %s"
+ }],
+ a: [
+ { //a=rtpmap:110 opus/48000/2
+ push: 'rtp',
+ reg: /^rtpmap:(\d*) ([\w\-]*)(?:\s*\/(\d*)(?:\s*\/(\S*))?)?/,
+ names: ['payload', 'codec', 'rate', 'encoding'],
+ format: function (o) {
+ return (o.encoding) ?
+ "rtpmap:%d %s/%s/%s":
+ o.rate ?
+ "rtpmap:%d %s/%s":
+ "rtpmap:%d %s";
+ }
+ },
+ {
+ //a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
+ //a=fmtp:111 minptime=10; useinbandfec=1
+ push: 'fmtp',
+ reg: /^fmtp:(\d*) ([\S| ]*)/,
+ names: ['payload', 'config'],
+ format: "fmtp:%d %s"
+ },
+ { //a=control:streamid=0
+ name: 'control',
+ reg: /^control:(.*)/,
+ format: "control:%s"
+ },
+ { //a=rtcp:65179 IN IP4 193.84.77.194
+ name: 'rtcp',
+ reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
+ names: ['port', 'netType', 'ipVer', 'address'],
+ format: function (o) {
+ return (o.address != null) ?
+ "rtcp:%d %s IP%d %s":
+ "rtcp:%d";
+ }
+ },
+ { //a=rtcp-fb:98 trr-int 100
+ push: 'rtcpFbTrrInt',
+ reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
+ names: ['payload', 'value'],
+ format: "rtcp-fb:%d trr-int %d"
+ },
+ { //a=rtcp-fb:98 nack rpsi
+ push: 'rtcpFb',
+ reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
+ names: ['payload', 'type', 'subtype'],
+ format: function (o) {
+ return (o.subtype != null) ?
+ "rtcp-fb:%s %s %s":
+ "rtcp-fb:%s %s";
+ }
+ },
+ { //a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
+ //a=extmap:1/recvonly URI-gps-string
+ push: 'ext',
+ reg: /^extmap:([\w_\/]*) (\S*)(?: (\S*))?/,
+ names: ['value', 'uri', 'config'], // value may include "/direction" suffix
+ format: function (o) {
+ return (o.config != null) ?
+ "extmap:%s %s %s":
+ "extmap:%s %s";
+ }
+ },
+ {
+ //a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
+ push: 'crypto',
+ reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
+ names: ['id', 'suite', 'config', 'sessionConfig'],
+ format: function (o) {
+ return (o.sessionConfig != null) ?
+ "crypto:%d %s %s %s":
+ "crypto:%d %s %s";
+ }
+ },
+ { //a=setup:actpass
+ name: 'setup',
+ reg: /^setup:(\w*)/,
+ format: "setup:%s"
+ },
+ { //a=mid:1
+ name: 'mid',
+ reg: /^mid:([^\s]*)/,
+ format: "mid:%s"
+ },
+ { //a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
+ name: 'msid',
+ reg: /^msid:(.*)/,
+ format: "msid:%s"
+ },
+ { //a=ptime:20
+ name: 'ptime',
+ reg: /^ptime:(\d*)/,
+ format: "ptime:%d"
+ },
+ { //a=maxptime:60
+ name: 'maxptime',
+ reg: /^maxptime:(\d*)/,
+ format: "maxptime:%d"
+ },
+ { //a=sendrecv
+ name: 'direction',
+ reg: /^(sendrecv|recvonly|sendonly|inactive)/
+ },
+ { //a=ice-lite
+ name: 'icelite',
+ reg: /^(ice-lite)/
+ },
+ { //a=ice-ufrag:F7gI
+ name: 'iceUfrag',
+ reg: /^ice-ufrag:(\S*)/,
+ format: "ice-ufrag:%s"
+ },
+ { //a=ice-pwd:x9cml/YzichV2+XlhiMu8g
+ name: 'icePwd',
+ reg: /^ice-pwd:(\S*)/,
+ format: "ice-pwd:%s"
+ },
+ { //a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
+ name: 'fingerprint',
+ reg: /^fingerprint:(\S*) (\S*)/,
+ names: ['type', 'hash'],
+ format: "fingerprint:%s %s"
+ },
+ {
+ //a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
+ //a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0
+ //a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0
+ //a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0
+ //a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0
+ push:'candidates',
+ reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: tcptype (\S*))?(?: generation (\d*))?/,
+ names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation'],
+ format: function (o) {
+ var str = "candidate:%s %d %s %d %s %d typ %s";
+
+ str += (o.raddr != null) ? " raddr %s rport %d" : "%v%v";
+
+ // NB: candidate has three optional chunks, so %void middles one if it's missing
+ str += (o.tcptype != null) ? " tcptype %s" : "%v";
+
+ if (o.generation != null) {
+ str += " generation %d";
+ }
+ return str;
+ }
+ },
+ { //a=end-of-candidates (keep after the candidates line for readability)
+ name: 'endOfCandidates',
+ reg: /^(end-of-candidates)/
+ },
+ { //a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
+ name: 'remoteCandidates',
+ reg: /^remote-candidates:(.*)/,
+ format: "remote-candidates:%s"
+ },
+ { //a=ice-options:google-ice
+ name: 'iceOptions',
+ reg: /^ice-options:(\S*)/,
+ format: "ice-options:%s"
+ },
+ { //a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
+ push: "ssrcs",
+ reg: /^ssrc:(\d*) ([\w_]*):(.*)/,
+ names: ['id', 'attribute', 'value'],
+ format: "ssrc:%d %s:%s"
+ },
+ { //a=ssrc-group:FEC 1 2
+ push: "ssrcGroups",
+ reg: /^ssrc-group:(\w*) (.*)/,
+ names: ['semantics', 'ssrcs'],
+ format: "ssrc-group:%s %s"
+ },
+ { //a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
+ name: "msidSemantic",
+ reg: /^msid-semantic:\s?(\w*) (\S*)/,
+ names: ['semantic', 'token'],
+ format: "msid-semantic: %s %s" // space after ":" is not accidental
+ },
+ { //a=group:BUNDLE audio video
+ push: 'groups',
+ reg: /^group:(\w*) (.*)/,
+ names: ['type', 'mids'],
+ format: "group:%s %s"
+ },
+ { //a=rtcp-mux
+ name: 'rtcpMux',
+ reg: /^(rtcp-mux)/
+ },
+ { //a=rtcp-rsize
+ name: 'rtcpRsize',
+ reg: /^(rtcp-rsize)/
+ },
+ { // any a= that we don't understand is kepts verbatim on media.invalid
+ push: 'invalid',
+ names: ["value"]
+ }
+ ]
+};
+
+// set sensible defaults to avoid polluting the grammar with boring details
+Object.keys(grammar).forEach(function (key) {
+ var objs = grammar[key];
+ objs.forEach(function (obj) {
+ if (!obj.reg) {
+ obj.reg = /(.*)/;
+ }
+ if (!obj.format) {
+ obj.format = "%s";
+ }
+ });
+});
+
+},{}],69:[function(require,module,exports){
+var parser = require('./parser');
+var writer = require('./writer');
+
+exports.write = writer;
+exports.parse = parser.parse;
+exports.parseFmtpConfig = parser.parseFmtpConfig;
+exports.parsePayloads = parser.parsePayloads;
+exports.parseRemoteCandidates = parser.parseRemoteCandidates;
+
+},{"./parser":70,"./writer":71}],70:[function(require,module,exports){
+var toIntIfInt = function (v) {
+ return String(Number(v)) === v ? Number(v) : v;
+};
+
+var attachProperties = function (match, location, names, rawName) {
+ if (rawName && !names) {
+ location[rawName] = toIntIfInt(match[1]);
+ }
+ else {
+ for (var i = 0; i < names.length; i += 1) {
+ if (match[i+1] != null) {
+ location[names[i]] = toIntIfInt(match[i+1]);
+ }
+ }
+ }
+};
+
+var parseReg = function (obj, location, content) {
+ var needsBlank = obj.name && obj.names;
+ if (obj.push && !location[obj.push]) {
+ location[obj.push] = [];
+ }
+ else if (needsBlank && !location[obj.name]) {
+ location[obj.name] = {};
+ }
+ var keyLocation = obj.push ?
+ {} : // blank object that will be pushed
+ needsBlank ? location[obj.name] : location; // otherwise, named location or root
+
+ attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
+
+ if (obj.push) {
+ location[obj.push].push(keyLocation);
+ }
+};
+
+var grammar = require('./grammar');
+var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
+
+exports.parse = function (sdp) {
+ var session = {}
+ , media = []
+ , location = session; // points at where properties go under (one of the above)
+
+ // parse lines we understand
+ sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
+ var type = l[0];
+ var content = l.slice(2);
+ if (type === 'm') {
+ media.push({rtp: [], fmtp: []});
+ location = media[media.length-1]; // point at latest media line
+ }
+
+ for (var j = 0; j < (grammar[type] || []).length; j += 1) {
+ var obj = grammar[type][j];
+ if (obj.reg.test(content)) {
+ return parseReg(obj, location, content);
+ }
+ }
+ });
+
+ session.media = media; // link it up
+ return session;
+};
+
+var fmtpReducer = function (acc, expr) {
+ var s = expr.split('=');
+ if (s.length === 2) {
+ acc[s[0]] = toIntIfInt(s[1]);
+ }
+ return acc;
+};
+
+exports.parseFmtpConfig = function (str) {
+ return str.split(/\;\s?/).reduce(fmtpReducer, {});
+};
+
+exports.parsePayloads = function (str) {
+ return str.split(' ').map(Number);
+};
+
+exports.parseRemoteCandidates = function (str) {
+ var candidates = [];
+ var parts = str.split(' ').map(toIntIfInt);
+ for (var i = 0; i < parts.length; i += 3) {
+ candidates.push({
+ component: parts[i],
+ ip: parts[i + 1],
+ port: parts[i + 2]
+ });
+ }
+ return candidates;
+};
+
+},{"./grammar":68}],71:[function(require,module,exports){
+var grammar = require('./grammar');
+
+// customized util.format - discards excess arguments and can void middle ones
+var formatRegExp = /%[sdv%]/g;
+var format = function (formatStr) {
+ var i = 1;
+ var args = arguments;
+ var len = args.length;
+ return formatStr.replace(formatRegExp, function (x) {
+ if (i >= len) {
+ return x; // missing argument
+ }
+ var arg = args[i];
+ i += 1;
+ switch (x) {
+ case '%%':
+ return '%';
+ case '%s':
+ return String(arg);
+ case '%d':
+ return Number(arg);
+ case '%v':
+ return '';
+ }
+ });
+ // NB: we discard excess arguments - they are typically undefined from makeLine
+};
+
+var makeLine = function (type, obj, location) {
+ var str = obj.format instanceof Function ?
+ (obj.format(obj.push ? location : location[obj.name])) :
+ obj.format;
+
+ var args = [type + '=' + str];
+ if (obj.names) {
+ for (var i = 0; i < obj.names.length; i += 1) {
+ var n = obj.names[i];
+ if (obj.name) {
+ args.push(location[obj.name][n]);
+ }
+ else { // for mLine and push attributes
+ args.push(location[obj.names[i]]);
+ }
+ }
+ }
+ else {
+ args.push(location[obj.name]);
+ }
+ return format.apply(null, args);
+};
+
+// RFC specified order
+// TODO: extend this with all the rest
+var defaultOuterOrder = [
+ 'v', 'o', 's', 'i',
+ 'u', 'e', 'p', 'c',
+ 'b', 't', 'r', 'z', 'a'
+];
+var defaultInnerOrder = ['i', 'c', 'b', 'a'];
+
+
+module.exports = function (session, opts) {
+ opts = opts || {};
+ // ensure certain properties exist
+ if (session.version == null) {
+ session.version = 0; // "v=0" must be there (only defined version atm)
+ }
+ if (session.name == null) {
+ session.name = " "; // "s= " must be there if no meaningful name set
+ }
+ session.media.forEach(function (mLine) {
+ if (mLine.payloads == null) {
+ mLine.payloads = "";
+ }
+ });
+
+ var outerOrder = opts.outerOrder || defaultOuterOrder;
+ var innerOrder = opts.innerOrder || defaultInnerOrder;
+ var sdp = [];
+
+ // loop through outerOrder for matching properties on session
+ outerOrder.forEach(function (type) {
+ grammar[type].forEach(function (obj) {
+ if (obj.name in session && session[obj.name] != null) {
+ sdp.push(makeLine(type, obj, session));
+ }
+ else if (obj.push in session && session[obj.push] != null) {
+ session[obj.push].forEach(function (el) {
+ sdp.push(makeLine(type, obj, el));
+ });
+ }
+ });
+ });
+
+ // then for each media line, follow the innerOrder
+ session.media.forEach(function (mLine) {
+ sdp.push(makeLine('m', grammar.m[0], mLine));
+
+ innerOrder.forEach(function (type) {
+ grammar[type].forEach(function (obj) {
+ if (obj.name in mLine && mLine[obj.name] != null) {
+ sdp.push(makeLine(type, obj, mLine));
+ }
+ else if (obj.push in mLine && mLine[obj.push] != null) {
+ mLine[obj.push].forEach(function (el) {
+ sdp.push(makeLine(type, obj, el));
+ });
+ }
+ });
+ });
+ });
+
+ return sdp.join('\r\n') + '\r\n';
+};
+
+},{"./grammar":68}],72:[function(require,module,exports){
/* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21725,7 +22214,7 @@ function explodeRemoteSimulcast(mLine) {
function implodeRemoteSimulcast(mLine) {
if (!mLine || !Array.isArray(mLine.ssrcGroups)) {
- console.debug('Halt: There are no SSRC groups in the remote ' +
+ console.info('Halt: There are no SSRC groups in the remote ' +
'description.');
return;
}
@@ -21738,7 +22227,7 @@ function implodeRemoteSimulcast(mLine) {
return;
}
- console.debug("Imploding SIM group: " + simulcastGroup.ssrcs);
+ console.info("Imploding SIM group: " + simulcastGroup.ssrcs);
// Schedule the SIM group for nuking.
simulcastGroup.nuke = true;
@@ -22012,7 +22501,7 @@ Simulcast.prototype.mungeLocalDescription = function (desc) {
module.exports = Simulcast;
-},{"./transform-utils":69,"sdp-transform":71}],69:[function(require,module,exports){
+},{"./transform-utils":73,"sdp-transform":75}],73:[function(require,module,exports){
/* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22078,827 +22567,15 @@ exports.parseSsrcs = function (mLine) {
};
-},{}],70:[function(require,module,exports){
-var grammar = module.exports = {
- v: [{
- name: 'version',
- reg: /^(\d*)$/
- }],
- o: [{ //o=- 20518 0 IN IP4 203.0.113.1
- // NB: sessionId will be a String in most cases because it is huge
- name: 'origin',
- reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
- names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
- format: "%s %s %d %s IP%d %s"
- }],
- // default parsing of these only (though some of these feel outdated)
- s: [{ name: 'name' }],
- i: [{ name: 'description' }],
- u: [{ name: 'uri' }],
- e: [{ name: 'email' }],
- p: [{ name: 'phone' }],
- z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly..
- r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly
- //k: [{}], // outdated thing ignored
- t: [{ //t=0 0
- name: 'timing',
- reg: /^(\d*) (\d*)/,
- names: ['start', 'stop'],
- format: "%d %d"
- }],
- c: [{ //c=IN IP4 10.47.197.26
- name: 'connection',
- reg: /^IN IP(\d) (\S*)/,
- names: ['version', 'ip'],
- format: "IN IP%d %s"
- }],
- b: [{ //b=AS:4000
- push: 'bandwidth',
- reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
- names: ['type', 'limit'],
- format: "%s:%s"
- }],
- m: [{ //m=video 51744 RTP/AVP 126 97 98 34 31
- // NB: special - pushes to session
- // TODO: rtp/fmtp should be filtered by the payloads found here?
- reg: /^(\w*) (\d*) ([\w\/]*)(?: (.*))?/,
- names: ['type', 'port', 'protocol', 'payloads'],
- format: "%s %d %s %s"
- }],
- a: [
- { //a=rtpmap:110 opus/48000/2
- push: 'rtp',
- reg: /^rtpmap:(\d*) ([\w\-]*)\/(\d*)(?:\s*\/(\S*))?/,
- names: ['payload', 'codec', 'rate', 'encoding'],
- format: function (o) {
- return (o.encoding) ?
- "rtpmap:%d %s/%s/%s":
- "rtpmap:%d %s/%s";
- }
- },
- { //a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
- push: 'fmtp',
- reg: /^fmtp:(\d*) (\S*)/,
- names: ['payload', 'config'],
- format: "fmtp:%d %s"
- },
- { //a=control:streamid=0
- name: 'control',
- reg: /^control:(.*)/,
- format: "control:%s"
- },
- { //a=rtcp:65179 IN IP4 193.84.77.194
- name: 'rtcp',
- reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
- names: ['port', 'netType', 'ipVer', 'address'],
- format: function (o) {
- return (o.address != null) ?
- "rtcp:%d %s IP%d %s":
- "rtcp:%d";
- }
- },
- { //a=rtcp-fb:98 trr-int 100
- push: 'rtcpFbTrrInt',
- reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
- names: ['payload', 'value'],
- format: "rtcp-fb:%d trr-int %d"
- },
- { //a=rtcp-fb:98 nack rpsi
- push: 'rtcpFb',
- reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
- names: ['payload', 'type', 'subtype'],
- format: function (o) {
- return (o.subtype != null) ?
- "rtcp-fb:%s %s %s":
- "rtcp-fb:%s %s";
- }
- },
- { //a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
- //a=extmap:1/recvonly URI-gps-string
- push: 'ext',
- reg: /^extmap:([\w_\/]*) (\S*)(?: (\S*))?/,
- names: ['value', 'uri', 'config'], // value may include "/direction" suffix
- format: function (o) {
- return (o.config != null) ?
- "extmap:%s %s %s":
- "extmap:%s %s";
- }
- },
- {
- //a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
- push: 'crypto',
- reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
- names: ['id', 'suite', 'config', 'sessionConfig'],
- format: function (o) {
- return (o.sessionConfig != null) ?
- "crypto:%d %s %s %s":
- "crypto:%d %s %s";
- }
- },
- { //a=setup:actpass
- name: 'setup',
- reg: /^setup:(\w*)/,
- format: "setup:%s"
- },
- { //a=mid:1
- name: 'mid',
- reg: /^mid:([^\s]*)/,
- format: "mid:%s"
- },
- { //a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
- name: 'msid',
- reg: /^msid:(.*)/,
- format: "msid:%s"
- },
- { //a=ptime:20
- name: 'ptime',
- reg: /^ptime:(\d*)/,
- format: "ptime:%d"
- },
- { //a=maxptime:60
- name: 'maxptime',
- reg: /^maxptime:(\d*)/,
- format: "maxptime:%d"
- },
- { //a=sendrecv
- name: 'direction',
- reg: /^(sendrecv|recvonly|sendonly|inactive)/
- },
- { //a=ice-lite
- name: 'icelite',
- reg: /^(ice-lite)/
- },
- { //a=ice-ufrag:F7gI
- name: 'iceUfrag',
- reg: /^ice-ufrag:(\S*)/,
- format: "ice-ufrag:%s"
- },
- { //a=ice-pwd:x9cml/YzichV2+XlhiMu8g
- name: 'icePwd',
- reg: /^ice-pwd:(\S*)/,
- format: "ice-pwd:%s"
- },
- { //a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
- name: 'fingerprint',
- reg: /^fingerprint:(\S*) (\S*)/,
- names: ['type', 'hash'],
- format: "fingerprint:%s %s"
- },
- {
- //a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
- //a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0
- //a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0
- push:'candidates',
- reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: generation (\d*))?/,
- names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'generation'],
- format: function (o) {
- var str = "candidate:%s %d %s %d %s %d typ %s";
- // NB: candidate has two optional chunks, so %void middle one if it's missing
- str += (o.raddr != null) ? " raddr %s rport %d" : "%v%v";
- if (o.generation != null) {
- str += " generation %d";
- }
- return str;
- }
- },
- { //a=end-of-candidates (keep after the candidates line for readability)
- name: 'endOfCandidates',
- reg: /^(end-of-candidates)/
- },
- { //a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
- name: 'remoteCandidates',
- reg: /^remote-candidates:(.*)/,
- format: "remote-candidates:%s"
- },
- { //a=ice-options:google-ice
- name: 'iceOptions',
- reg: /^ice-options:(\S*)/,
- format: "ice-options:%s"
- },
- { //a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
- push: "ssrcs",
- reg: /^ssrc:(\d*) ([\w_]*):(.*)/,
- names: ['id', 'attribute', 'value'],
- format: "ssrc:%d %s:%s"
- },
- { //a=ssrc-group:FEC 1 2
- push: "ssrcGroups",
- reg: /^ssrc-group:(\w*) (.*)/,
- names: ['semantics', 'ssrcs'],
- format: "ssrc-group:%s %s"
- },
- { //a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
- name: "msidSemantic",
- reg: /^msid-semantic:\s?(\w*) (\S*)/,
- names: ['semantic', 'token'],
- format: "msid-semantic: %s %s" // space after ":" is not accidental
- },
- { //a=group:BUNDLE audio video
- push: 'groups',
- reg: /^group:(\w*) (.*)/,
- names: ['type', 'mids'],
- format: "group:%s %s"
- },
- { //a=rtcp-mux
- name: 'rtcpMux',
- reg: /^(rtcp-mux)/
- },
- { //a=rtcp-rsize
- name: 'rtcpRsize',
- reg: /^(rtcp-rsize)/
- },
- { // any a= that we don't understand is kepts verbatim on media.invalid
- push: 'invalid',
- names: ["value"]
- }
- ]
-};
-
-// set sensible defaults to avoid polluting the grammar with boring details
-Object.keys(grammar).forEach(function (key) {
- var objs = grammar[key];
- objs.forEach(function (obj) {
- if (!obj.reg) {
- obj.reg = /(.*)/;
- }
- if (!obj.format) {
- obj.format = "%s";
- }
- });
-});
-
-},{}],71:[function(require,module,exports){
-var parser = require('./parser');
-var writer = require('./writer');
-
-exports.write = writer;
-exports.parse = parser.parse;
-exports.parseFmtpConfig = parser.parseFmtpConfig;
-exports.parsePayloads = parser.parsePayloads;
-exports.parseRemoteCandidates = parser.parseRemoteCandidates;
-
-},{"./parser":72,"./writer":73}],72:[function(require,module,exports){
-var toIntIfInt = function (v) {
- return String(Number(v)) === v ? Number(v) : v;
-};
-
-var attachProperties = function (match, location, names, rawName) {
- if (rawName && !names) {
- location[rawName] = toIntIfInt(match[1]);
- }
- else {
- for (var i = 0; i < names.length; i += 1) {
- if (match[i+1] != null) {
- location[names[i]] = toIntIfInt(match[i+1]);
- }
- }
- }
-};
-
-var parseReg = function (obj, location, content) {
- var needsBlank = obj.name && obj.names;
- if (obj.push && !location[obj.push]) {
- location[obj.push] = [];
- }
- else if (needsBlank && !location[obj.name]) {
- location[obj.name] = {};
- }
- var keyLocation = obj.push ?
- {} : // blank object that will be pushed
- needsBlank ? location[obj.name] : location; // otherwise, named location or root
-
- attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
-
- if (obj.push) {
- location[obj.push].push(keyLocation);
- }
-};
-
-var grammar = require('./grammar');
-var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
-
-exports.parse = function (sdp) {
- var session = {}
- , media = []
- , location = session; // points at where properties go under (one of the above)
-
- // parse lines we understand
- sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
- var type = l[0];
- var content = l.slice(2);
- if (type === 'm') {
- media.push({rtp: [], fmtp: []});
- location = media[media.length-1]; // point at latest media line
- }
-
- for (var j = 0; j < (grammar[type] || []).length; j += 1) {
- var obj = grammar[type][j];
- if (obj.reg.test(content)) {
- return parseReg(obj, location, content);
- }
- }
- });
-
- session.media = media; // link it up
- return session;
-};
-
-var fmtpReducer = function (acc, expr) {
- var s = expr.split('=');
- if (s.length === 2) {
- acc[s[0]] = toIntIfInt(s[1]);
- }
- return acc;
-};
-
-exports.parseFmtpConfig = function (str) {
- return str.split(';').reduce(fmtpReducer, {});
-};
-
-exports.parsePayloads = function (str) {
- return str.split(' ').map(Number);
-};
-
-exports.parseRemoteCandidates = function (str) {
- var candidates = [];
- var parts = str.split(' ').map(toIntIfInt);
- for (var i = 0; i < parts.length; i += 3) {
- candidates.push({
- component: parts[i],
- ip: parts[i + 1],
- port: parts[i + 2]
- });
- }
- return candidates;
-};
-
-},{"./grammar":70}],73:[function(require,module,exports){
-var grammar = require('./grammar');
-
-// customized util.format - discards excess arguments and can void middle ones
-var formatRegExp = /%[sdv%]/g;
-var format = function (formatStr) {
- var i = 1;
- var args = arguments;
- var len = args.length;
- return formatStr.replace(formatRegExp, function (x) {
- if (i >= len) {
- return x; // missing argument
- }
- var arg = args[i];
- i += 1;
- switch (x) {
- case '%%':
- return '%';
- case '%s':
- return String(arg);
- case '%d':
- return Number(arg);
- case '%v':
- return '';
- }
- });
- // NB: we discard excess arguments - they are typically undefined from makeLine
-};
-
-var makeLine = function (type, obj, location) {
- var str = obj.format instanceof Function ?
- (obj.format(obj.push ? location : location[obj.name])) :
- obj.format;
-
- var args = [type + '=' + str];
- if (obj.names) {
- for (var i = 0; i < obj.names.length; i += 1) {
- var n = obj.names[i];
- if (obj.name) {
- args.push(location[obj.name][n]);
- }
- else { // for mLine and push attributes
- args.push(location[obj.names[i]]);
- }
- }
- }
- else {
- args.push(location[obj.name]);
- }
- return format.apply(null, args);
-};
-
-// RFC specified order
-// TODO: extend this with all the rest
-var defaultOuterOrder = [
- 'v', 'o', 's', 'i',
- 'u', 'e', 'p', 'c',
- 'b', 't', 'r', 'z', 'a'
-];
-var defaultInnerOrder = ['i', 'c', 'b', 'a'];
-
-
-module.exports = function (session, opts) {
- opts = opts || {};
- // ensure certain properties exist
- if (session.version == null) {
- session.version = 0; // "v=0" must be there (only defined version atm)
- }
- if (session.name == null) {
- session.name = " "; // "s= " must be there if no meaningful name set
- }
- session.media.forEach(function (mLine) {
- if (mLine.payloads == null) {
- mLine.payloads = "";
- }
- });
-
- var outerOrder = opts.outerOrder || defaultOuterOrder;
- var innerOrder = opts.innerOrder || defaultInnerOrder;
- var sdp = [];
-
- // loop through outerOrder for matching properties on session
- outerOrder.forEach(function (type) {
- grammar[type].forEach(function (obj) {
- if (obj.name in session && session[obj.name] != null) {
- sdp.push(makeLine(type, obj, session));
- }
- else if (obj.push in session && session[obj.push] != null) {
- session[obj.push].forEach(function (el) {
- sdp.push(makeLine(type, obj, el));
- });
- }
- });
- });
-
- // then for each media line, follow the innerOrder
- session.media.forEach(function (mLine) {
- sdp.push(makeLine('m', grammar.m[0], mLine));
-
- innerOrder.forEach(function (type) {
- grammar[type].forEach(function (obj) {
- if (obj.name in mLine && mLine[obj.name] != null) {
- sdp.push(makeLine(type, obj, mLine));
- }
- else if (obj.push in mLine && mLine[obj.push] != null) {
- mLine[obj.push].forEach(function (el) {
- sdp.push(makeLine(type, obj, el));
- });
- }
- });
- });
- });
-
- return sdp.join('\r\n') + '\r\n';
-};
-
-},{"./grammar":70}],74:[function(require,module,exports){
-var grammar = module.exports = {
- v: [{
- name: 'version',
- reg: /^(\d*)$/
- }],
- o: [{ //o=- 20518 0 IN IP4 203.0.113.1
- // NB: sessionId will be a String in most cases because it is huge
- name: 'origin',
- reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
- names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
- format: "%s %s %d %s IP%d %s"
- }],
- // default parsing of these only (though some of these feel outdated)
- s: [{ name: 'name' }],
- i: [{ name: 'description' }],
- u: [{ name: 'uri' }],
- e: [{ name: 'email' }],
- p: [{ name: 'phone' }],
- z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly..
- r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly
- //k: [{}], // outdated thing ignored
- t: [{ //t=0 0
- name: 'timing',
- reg: /^(\d*) (\d*)/,
- names: ['start', 'stop'],
- format: "%d %d"
- }],
- c: [{ //c=IN IP4 10.47.197.26
- name: 'connection',
- reg: /^IN IP(\d) (\S*)/,
- names: ['version', 'ip'],
- format: "IN IP%d %s"
- }],
- b: [{ //b=AS:4000
- push: 'bandwidth',
- reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
- names: ['type', 'limit'],
- format: "%s:%s"
- }],
- m: [{ //m=video 51744 RTP/AVP 126 97 98 34 31
- // NB: special - pushes to session
- // TODO: rtp/fmtp should be filtered by the payloads found here?
- reg: /^(\w*) (\d*) ([\w\/]*)(?: (.*))?/,
- names: ['type', 'port', 'protocol', 'payloads'],
- format: "%s %d %s %s"
- }],
- a: [
- { //a=rtpmap:110 opus/48000/2
- push: 'rtp',
- reg: /^rtpmap:(\d*) ([\w\-]*)\/(\d*)(?:\s*\/(\S*))?/,
- names: ['payload', 'codec', 'rate', 'encoding'],
- format: function (o) {
- return (o.encoding) ?
- "rtpmap:%d %s/%s/%s":
- "rtpmap:%d %s/%s";
- }
- },
- {
- //a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
- //a=fmtp:111 minptime=10; useinbandfec=1
- push: 'fmtp',
- reg: /^fmtp:(\d*) ([\S| ]*)/,
- names: ['payload', 'config'],
- format: "fmtp:%d %s"
- },
- { //a=control:streamid=0
- name: 'control',
- reg: /^control:(.*)/,
- format: "control:%s"
- },
- { //a=rtcp:65179 IN IP4 193.84.77.194
- name: 'rtcp',
- reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
- names: ['port', 'netType', 'ipVer', 'address'],
- format: function (o) {
- return (o.address != null) ?
- "rtcp:%d %s IP%d %s":
- "rtcp:%d";
- }
- },
- { //a=rtcp-fb:98 trr-int 100
- push: 'rtcpFbTrrInt',
- reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
- names: ['payload', 'value'],
- format: "rtcp-fb:%d trr-int %d"
- },
- { //a=rtcp-fb:98 nack rpsi
- push: 'rtcpFb',
- reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
- names: ['payload', 'type', 'subtype'],
- format: function (o) {
- return (o.subtype != null) ?
- "rtcp-fb:%s %s %s":
- "rtcp-fb:%s %s";
- }
- },
- { //a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
- //a=extmap:1/recvonly URI-gps-string
- push: 'ext',
- reg: /^extmap:([\w_\/]*) (\S*)(?: (\S*))?/,
- names: ['value', 'uri', 'config'], // value may include "/direction" suffix
- format: function (o) {
- return (o.config != null) ?
- "extmap:%s %s %s":
- "extmap:%s %s";
- }
- },
- {
- //a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
- push: 'crypto',
- reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
- names: ['id', 'suite', 'config', 'sessionConfig'],
- format: function (o) {
- return (o.sessionConfig != null) ?
- "crypto:%d %s %s %s":
- "crypto:%d %s %s";
- }
- },
- { //a=setup:actpass
- name: 'setup',
- reg: /^setup:(\w*)/,
- format: "setup:%s"
- },
- { //a=mid:1
- name: 'mid',
- reg: /^mid:([^\s]*)/,
- format: "mid:%s"
- },
- { //a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
- name: 'msid',
- reg: /^msid:(.*)/,
- format: "msid:%s"
- },
- { //a=ptime:20
- name: 'ptime',
- reg: /^ptime:(\d*)/,
- format: "ptime:%d"
- },
- { //a=maxptime:60
- name: 'maxptime',
- reg: /^maxptime:(\d*)/,
- format: "maxptime:%d"
- },
- { //a=sendrecv
- name: 'direction',
- reg: /^(sendrecv|recvonly|sendonly|inactive)/
- },
- { //a=ice-lite
- name: 'icelite',
- reg: /^(ice-lite)/
- },
- { //a=ice-ufrag:F7gI
- name: 'iceUfrag',
- reg: /^ice-ufrag:(\S*)/,
- format: "ice-ufrag:%s"
- },
- { //a=ice-pwd:x9cml/YzichV2+XlhiMu8g
- name: 'icePwd',
- reg: /^ice-pwd:(\S*)/,
- format: "ice-pwd:%s"
- },
- { //a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
- name: 'fingerprint',
- reg: /^fingerprint:(\S*) (\S*)/,
- names: ['type', 'hash'],
- format: "fingerprint:%s %s"
- },
- {
- //a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
- //a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0
- //a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0
- push:'candidates',
- reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: generation (\d*))?/,
- names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'generation'],
- format: function (o) {
- var str = "candidate:%s %d %s %d %s %d typ %s";
- // NB: candidate has two optional chunks, so %void middle one if it's missing
- str += (o.raddr != null) ? " raddr %s rport %d" : "%v%v";
- if (o.generation != null) {
- str += " generation %d";
- }
- return str;
- }
- },
- { //a=end-of-candidates (keep after the candidates line for readability)
- name: 'endOfCandidates',
- reg: /^(end-of-candidates)/
- },
- { //a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
- name: 'remoteCandidates',
- reg: /^remote-candidates:(.*)/,
- format: "remote-candidates:%s"
- },
- { //a=ice-options:google-ice
- name: 'iceOptions',
- reg: /^ice-options:(\S*)/,
- format: "ice-options:%s"
- },
- { //a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
- push: "ssrcs",
- reg: /^ssrc:(\d*) ([\w_]*):(.*)/,
- names: ['id', 'attribute', 'value'],
- format: "ssrc:%d %s:%s"
- },
- { //a=ssrc-group:FEC 1 2
- push: "ssrcGroups",
- reg: /^ssrc-group:(\w*) (.*)/,
- names: ['semantics', 'ssrcs'],
- format: "ssrc-group:%s %s"
- },
- { //a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
- name: "msidSemantic",
- reg: /^msid-semantic:\s?(\w*) (\S*)/,
- names: ['semantic', 'token'],
- format: "msid-semantic: %s %s" // space after ":" is not accidental
- },
- { //a=group:BUNDLE audio video
- push: 'groups',
- reg: /^group:(\w*) (.*)/,
- names: ['type', 'mids'],
- format: "group:%s %s"
- },
- { //a=rtcp-mux
- name: 'rtcpMux',
- reg: /^(rtcp-mux)/
- },
- { //a=rtcp-rsize
- name: 'rtcpRsize',
- reg: /^(rtcp-rsize)/
- },
- { // any a= that we don't understand is kepts verbatim on media.invalid
- push: 'invalid',
- names: ["value"]
- }
- ]
-};
-
-// set sensible defaults to avoid polluting the grammar with boring details
-Object.keys(grammar).forEach(function (key) {
- var objs = grammar[key];
- objs.forEach(function (obj) {
- if (!obj.reg) {
- obj.reg = /(.*)/;
- }
- if (!obj.format) {
- obj.format = "%s";
- }
- });
-});
-
-},{}],75:[function(require,module,exports){
+},{}],74:[function(require,module,exports){
+arguments[4][68][0].apply(exports,arguments)
+},{"dup":68}],75:[function(require,module,exports){
+arguments[4][69][0].apply(exports,arguments)
+},{"./parser":76,"./writer":77,"dup":69}],76:[function(require,module,exports){
+arguments[4][70][0].apply(exports,arguments)
+},{"./grammar":74,"dup":70}],77:[function(require,module,exports){
arguments[4][71][0].apply(exports,arguments)
-},{"./parser":76,"./writer":77,"dup":71}],76:[function(require,module,exports){
-var toIntIfInt = function (v) {
- return String(Number(v)) === v ? Number(v) : v;
-};
-
-var attachProperties = function (match, location, names, rawName) {
- if (rawName && !names) {
- location[rawName] = toIntIfInt(match[1]);
- }
- else {
- for (var i = 0; i < names.length; i += 1) {
- if (match[i+1] != null) {
- location[names[i]] = toIntIfInt(match[i+1]);
- }
- }
- }
-};
-
-var parseReg = function (obj, location, content) {
- var needsBlank = obj.name && obj.names;
- if (obj.push && !location[obj.push]) {
- location[obj.push] = [];
- }
- else if (needsBlank && !location[obj.name]) {
- location[obj.name] = {};
- }
- var keyLocation = obj.push ?
- {} : // blank object that will be pushed
- needsBlank ? location[obj.name] : location; // otherwise, named location or root
-
- attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
-
- if (obj.push) {
- location[obj.push].push(keyLocation);
- }
-};
-
-var grammar = require('./grammar');
-var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
-
-exports.parse = function (sdp) {
- var session = {}
- , media = []
- , location = session; // points at where properties go under (one of the above)
-
- // parse lines we understand
- sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
- var type = l[0];
- var content = l.slice(2);
- if (type === 'm') {
- media.push({rtp: [], fmtp: []});
- location = media[media.length-1]; // point at latest media line
- }
-
- for (var j = 0; j < (grammar[type] || []).length; j += 1) {
- var obj = grammar[type][j];
- if (obj.reg.test(content)) {
- return parseReg(obj, location, content);
- }
- }
- });
-
- session.media = media; // link it up
- return session;
-};
-
-var fmtpReducer = function (acc, expr) {
- var s = expr.split('=');
- if (s.length === 2) {
- acc[s[0]] = toIntIfInt(s[1]);
- }
- return acc;
-};
-
-exports.parseFmtpConfig = function (str) {
- return str.split(/\;\s?/).reduce(fmtpReducer, {});
-};
-
-exports.parsePayloads = function (str) {
- return str.split(' ').map(Number);
-};
-
-exports.parseRemoteCandidates = function (str) {
- var candidates = [];
- var parts = str.split(' ').map(toIntIfInt);
- for (var i = 0; i < parts.length; i += 3) {
- candidates.push({
- component: parts[i],
- ip: parts[i + 1],
- port: parts[i + 2]
- });
- }
- return candidates;
-};
-
-},{"./grammar":74}],77:[function(require,module,exports){
-arguments[4][73][0].apply(exports,arguments)
-},{"./grammar":74,"dup":73}],78:[function(require,module,exports){
+},{"./grammar":74,"dup":71}],78:[function(require,module,exports){
var MediaStreamType = {
VIDEO_TYPE: "Video",
diff --git a/modules/RTC/JitsiLocalTrack.js b/modules/RTC/JitsiLocalTrack.js
index bf6ae2305..32c6aa5a7 100644
--- a/modules/RTC/JitsiLocalTrack.js
+++ b/modules/RTC/JitsiLocalTrack.js
@@ -14,7 +14,6 @@ function JitsiLocalTrack(stream, videoType,
this.dontFireRemoveEvent = false;
this.resolution = resolution;
this.startMuted = false;
- this.isLocal = true;
var self = this;
JitsiTrack.call(this, null, stream,
function () {
diff --git a/modules/RTC/JitsiRemoteTrack.js b/modules/RTC/JitsiRemoteTrack.js
index a9d40ead1..3d69317c3 100644
--- a/modules/RTC/JitsiRemoteTrack.js
+++ b/modules/RTC/JitsiRemoteTrack.js
@@ -22,7 +22,6 @@ function JitsiRemoteTrack(RTC, data, sid, ssrc) {
this.videoType = data.videoType;
this.ssrc = ssrc;
this.muted = false;
- this.isLocal = false;
if((this.type === JitsiTrack.AUDIO && data.audiomuted)
|| (this.type === JitsiTrack.VIDEO && data.videomuted)) {
this.muted = true;
diff --git a/modules/RTC/adapter.screenshare.js b/modules/RTC/adapter.screenshare.js
index d38154033..e24382118 100644
--- a/modules/RTC/adapter.screenshare.js
+++ b/modules/RTC/adapter.screenshare.js
@@ -1,6 +1,5 @@
-/*! adapterjs - v0.12.0 - 2015-09-04 */
+/*! adapterjs - v0.12.3 - 2015-11-16 */
var console = require("jitsi-meet-logger").getLogger(__filename);
-
// Adapter's interface.
var AdapterJS = AdapterJS || {};
@@ -18,7 +17,7 @@ AdapterJS.options = AdapterJS.options || {};
// AdapterJS.options.hidePluginInstallPrompt = true;
// AdapterJS version
-AdapterJS.VERSION = '0.12.0';
+AdapterJS.VERSION = '0.12.3';
// This function will be called when the WebRTC API is ready to be used
// Whether it is the native implementation (Chrome, Firefox, Opera) or
@@ -608,7 +607,7 @@ if (navigator.mozGetUserMedia) {
createIceServers = function (urls, username, password) {
var iceServers = [];
- for (i = 0; i < urls.length; i++) {
+ for (var i = 0; i < urls.length; i++) {
var iceServer = createIceServer(urls[i], username, password);
if (iceServer !== null) {
iceServers.push(iceServer);
@@ -698,7 +697,7 @@ if (navigator.mozGetUserMedia) {
'username' : username
};
} else {
- for (i = 0; i < urls.length; i++) {
+ for (var i = 0; i < urls.length; i++) {
var iceServer = createIceServer(urls[i], username, password);
if (iceServer !== null) {
iceServers.push(iceServer);
@@ -1000,12 +999,13 @@ if (navigator.mozGetUserMedia) {
return;
}
- var streamId
+ var streamId;
if (stream === null) {
streamId = '';
- }
- else {
- stream.enableSoundTracks(true); // TODO: remove on 0.12.0
+ } else {
+ if (typeof stream.enableSoundTracks !== 'undefined') {
+ stream.enableSoundTracks(true);
+ }
streamId = stream.id;
}
@@ -1047,16 +1047,13 @@ if (navigator.mozGetUserMedia) {
var height = '';
var width = '';
- if (element.getBoundingClientRect) {
- var rectObject = element.getBoundingClientRect();
- width = rectObject.width + 'px';
- height = rectObject.height + 'px';
+ if (element.clientWidth || element.clientHeight) {
+ width = element.clientWidth;
+ height = element.clientHeight;
}
- else if (element.width) {
+ else if (element.width || element.height) {
width = element.width;
height = element.height;
- } else {
- // TODO: What scenario could bring us here?
}
element.parentNode.insertBefore(frag, element);
@@ -1075,19 +1072,7 @@ if (navigator.mozGetUserMedia) {
element.setStreamId(streamId);
}
var newElement = document.getElementById(elementId);
- newElement.onplaying = (element.onplaying) ? element.onplaying : function (arg) {};
- newElement.onplay = (element.onplay) ? element.onplay : function (arg) {};
- newElement.onclick = (element.onclick) ? element.onclick : function (arg) {};
- if (isIE) { // on IE the event needs to be plugged manually
- newElement.attachEvent('onplaying', newElement.onplaying);
- newElement.attachEvent('onplay', newElement.onplay);
- newElement._TemOnClick = function (id) {
- var arg = {
- srcElement : document.getElementById(id)
- };
- newElement.onclick(arg);
- };
- }
+ AdapterJS.forwardEventHandlers(newElement, element, Object.getPrototypeOf(element));
return newElement;
};
@@ -1110,6 +1095,32 @@ if (navigator.mozGetUserMedia) {
}
};
+ AdapterJS.forwardEventHandlers = function (destElem, srcElem, prototype) {
+
+ properties = Object.getOwnPropertyNames( prototype );
+
+ for(prop in properties) {
+ propName = properties[prop];
+
+ if (typeof(propName.slice) === 'function') {
+ if (propName.slice(0,2) == 'on' && srcElem[propName] != null) {
+ if (isIE) {
+ destElem.attachEvent(propName,srcElem[propName]);
+ } else {
+ destElem.addEventListener(propName.slice(2), srcElem[propName], false)
+ }
+ } else {
+ //TODO (http://jira.temasys.com.sg/browse/TWP-328) Forward non-event properties ?
+ }
+ }
+ }
+
+ var subPrototype = Object.getPrototypeOf(prototype)
+ if(subPrototype != null) {
+ AdapterJS.forwardEventHandlers(destElem, srcElem, subPrototype);
+ }
+ }
+
RTCIceCandidate = function (candidate) {
if (!candidate.sdpMid) {
candidate.sdpMid = '';
diff --git a/modules/xmpp/TraceablePeerConnection.js b/modules/xmpp/TraceablePeerConnection.js
index cc85736b7..76db8b412 100644
--- a/modules/xmpp/TraceablePeerConnection.js
+++ b/modules/xmpp/TraceablePeerConnection.js
@@ -25,7 +25,7 @@ function TraceablePeerConnection(ice_config, constraints, session) {
var Interop = require('sdp-interop').Interop;
this.interop = new Interop();
var Simulcast = require('sdp-simulcast');
- this.simulcast = new Simulcast({numOfLayers: 2, explodeRemoteSimulcast: false});
+ this.simulcast = new Simulcast({numOfLayers: 3, explodeRemoteSimulcast: false});
// override as desired
this.trace = function (what, info) {
diff --git a/package.json b/package.json
index 90b306181..fd0b7ebde 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,7 @@
"pako": "*",
"sdp-interop": "0.1.11",
"sdp-transform": "1.5.*",
- "sdp-simulcast": "0.1.3",
+ "sdp-simulcast": "jitsi/sdp-simulcast",
"async": "0.9.0",
"retry": "0.6.1",
"jssha": "1.5.0",
@@ -39,4 +39,4 @@
"lint"
],
"license": "Apache-2.0"
-}
\ No newline at end of file
+}