+ DEFAULT: false
+ The flag if for each Peer connection instead of bundling all
+ media connections into 1 connection, should have all of them negotiated as different separate media connections.
+
- Defined in: source/room-connection.js:616
+ Defined in: source/room-connection.js:618
diff --git a/doc/data.json b/doc/data.json
index 089721aa8..a8050f8db 100644
--- a/doc/data.json
+++ b/doc/data.json
@@ -2,7 +2,7 @@
"project": {
"name": "skylinkjs",
"description": "Temasys Web SDK is an open-source client-side library for your web-browser that enables any website to easily leverage the capabilities of WebRTC and its direct data streaming powers between peers for audio/video conferencing or file transfer.",
- "version": "0.6.29",
+ "version": "0.6.30",
"url": "https://temasys.io/"
},
"files": {
@@ -2763,7 +2763,7 @@
},
{
"file": "source/data-channel.js",
- "line": 230,
+ "line": 231,
"description": "Function that returns the Datachannel buffer threshold and amount.",
"itemtype": "method",
"name": "_getDataChannelBuffer",
@@ -2778,7 +2778,7 @@
},
{
"file": "source/data-channel.js",
- "line": 264,
+ "line": 265,
"description": "Function that sends data over the Datachannel connection.",
"itemtype": "method",
"name": "_sendMessageToDataChannel",
@@ -2789,7 +2789,7 @@
},
{
"file": "source/data-channel.js",
- "line": 339,
+ "line": 340,
"description": "Function that stops the Datachannel connection and removes object references.",
"itemtype": "method",
"name": "_closeDataChannel",
@@ -4283,6 +4283,13 @@
"description": "The type of certificate that Peer connection should\n generate and use when available.\n- When not provided, its value is AUTO.\n [Rel: Skylink.PEER_CERTIFICATE]",
"type": "String",
"optional": true
+ },
+ {
+ "name": "disableBundle",
+ "description": "The flag if for each Peer connection instead of bundling all\n media connections into 1 connection, should have all of them negotiated as different separate media connections.",
+ "type": "String",
+ "optional": true,
+ "optdefault": "false"
}
]
},
@@ -4381,7 +4388,7 @@
},
{
"file": "source/room-connection.js",
- "line": 466,
+ "line": 468,
"description": "
\n Note that this method will close any existing socket channel connection despite not being in the Room.\n
\nFunction that locks the current Room when in session to prevent other Peers from joining the Room.",
"itemtype": "method",
"name": "lockRoom",
@@ -4456,7 +4463,7 @@
},
{
"file": "source/room-connection.js",
- "line": 616,
+ "line": 618,
"description": "
return;
}
+ if (
+ // If peer connection exists first and state is not closed.
+ self._peerConnections[targetMid] && self._peerConnections[targetMid].signalingState !== self.PEER_CONNECTION_STATE.CLOSED &&
// If remote description is set
- if (self._peerConnections[targetMid].remoteDescription && self._peerConnections[targetMid].remoteDescription.sdp &&
+ self._peerConnections[targetMid].remoteDescription && self._peerConnections[targetMid].remoteDescription.sdp &&
// If end-of-candidates signal is received
typeof self._peerEndOfCandidatesCounter[targetMid].expectedLen === 'number' &&
// If all ICE candidates are received
diff --git a/doc/files/source_peer-data.js.html b/doc/files/source_peer-data.js.html
index a2eaa5691..8a35eb4d1 100644
--- a/doc/files/source_peer-data.js.html
+++ b/doc/files/source_peer-data.js.html
@@ -2,7 +2,7 @@
- SkylinkJS 0.6.29
+ SkylinkJS 0.6.30
@@ -33,7 +33,7 @@
- Version: 0.6.29
+ Version: 0.6.30
* generate and use when available.
* - When not provided, its value is <code>AUTO</code>.
* [Rel: Skylink.PEER_CERTIFICATE]
+ * @param {String} [options.peerConnection.disableBundle=false] The flag if for each Peer connection instead of bundling all
+ * media connections into 1 connection, should have all of them negotiated as different separate media connections.
* @param {Boolean|JSON} [options.autoBandwidthAdjustment=false] <blockquote class="info">
* Note that this is an experimental feature which may be removed or changed in the future releases.
* This feature is also only available for non-MCU enabled Peer connections and Edge Peer connections.
@@ -782,7 +784,8 @@
SkylinkJS API Documentation
- Version: 0.6.29
+ Version: 0.6.30
diff --git a/package.json b/package.json
index e4548eb6c..4c287ce2a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "skylinkjs",
"description": "Temasys Web SDK is an open-source client-side library for your web-browser that enables any website to easily leverage the capabilities of WebRTC and its direct data streaming powers between peers for audio/video conferencing or file transfer.",
- "version": "0.6.29",
+ "version": "0.6.30",
"homepage": "https://temasys.io/",
"author": {
"name": "Temasys Communications Pte. Ltd.",
diff --git a/publish/skylink.complete.js b/publish/skylink.complete.js
index 23a97cc64..320c68c15 100644
--- a/publish/skylink.complete.js
+++ b/publish/skylink.complete.js
@@ -1,4 +1,4 @@
-/*! skylinkjs - v0.6.29 - Tue Feb 06 2018 18:44:39 GMT+0800 (+08) */
+/*! skylinkjs - v0.6.30 - Wed Feb 21 2018 17:48:18 GMT+0800 (+08) */
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.io = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;oinit() method ready states.
@@ -16161,6 +16161,54 @@ Skylink.prototype._createDataChannel = function(peerId, dataChannel, bufferThres
}
};
+/**
+ * Function that refreshes the main messaging Datachannel.
+ * @method refreshDatachannel
+ * @param {String} [peerId] The target Peer ID to retrieve connection stats from.
+ * @example
+ * // Example 1: Retrieve offerer and refresh datachannel:
+ * skylink.on("dataChannelState", function (state, peerId, error, channelName, channelType) {
+ * if (channelType === skylink.DATA_CHANNEL_TYPE.MESSAGING &&
+ * state === skylink.DATA_CHANNEL_STATE.CLOSED) {
+ * var userWeight = skylink.getPeerInfo().config.priorityWeight;
+ * var peerWeight = skylink.getPeerInfo(peerId).config.priorityWeight;
+ * // Determine who is offerer because as per SM protocol, higher weight is offerer
+ * if (userWeight > peerWeight) {
+ * skylink.refreshDatachannel(peerId);
+ * }
+ * }
+ * });
+ * @for Skylink
+ * @since 0.6.30
+ */
+
+Skylink.prototype.refreshDatachannel = function (peerId) {
+
+ var self = this;
+ if(self._dataChannels[peerId] && self._dataChannels[peerId]["main"] && self._dataChannels[peerId].main.channel) {
+ var channelName = self._dataChannels[peerId].main.channelName;
+ var channelType = self._dataChannels[peerId].main.channelType;
+ var channelProp = 'main';
+ var bufferThreshold= self._dataChannels[peerId].main.channel.bufferedAmountLowThreshold || 0;
+
+ if (channelType === self.DATA_CHANNEL_TYPE.MESSAGING) {
+ setTimeout(function () {
+ if (self._peerConnections[peerId] &&
+ self._peerConnections[peerId].signalingState !== self.PEER_CONNECTION_STATE.CLOSED &&
+ (self._peerConnections[peerId].localDescription &&
+ self._peerConnections[peerId].localDescription.type === self.HANDSHAKE_PROGRESS.OFFER)) {
+ self._closeDataChannel(peerId, 'main', true);
+ log.debug([peerId, 'RTCDataChannel', channelProp, 'Reviving Datachannel connection']);
+ self._createDataChannel(peerId, channelName, bufferThreshold, true);
+ }
+ }, 100);
+ }
+ }
+ else {
+ log.debug([peerId, 'RTCDataChannel', 'Not a valid Datachannel connection']);
+ }
+};
+
/**
* Function that returns the Datachannel buffer threshold and amount.
* @method _getDataChannelBuffer
@@ -16277,7 +16325,7 @@ Skylink.prototype._sendMessageToDataChannel = function(peerId, data, channelProp
* @for Skylink
* @since 0.1.0
*/
-Skylink.prototype._closeDataChannel = function(peerId, channelProp) {
+Skylink.prototype._closeDataChannel = function(peerId, channelProp, isCloseMainChannel) {
var self = this;
if (!self._dataChannels[peerId]) {
@@ -16302,7 +16350,11 @@ Skylink.prototype._closeDataChannel = function(peerId, channelProp) {
}
};
- if (!channelProp || channelProp === 'main') {
+ if(isCloseMainChannel)
+ {
+ closeFn(channelProp);
+ }
+ else if (!channelProp || channelProp === 'main') {
for (var channelNameProp in self._dataChannels) {
if (self._dataChannels[peerId].hasOwnProperty(channelNameProp)) {
if (self._dataChannels[peerId][channelNameProp]) {
@@ -16310,6 +16362,9 @@ Skylink.prototype._closeDataChannel = function(peerId, channelProp) {
}
}
}
+
+ delete self._dataChannels[peerId];
+
} else {
if (!self._dataChannels[peerId][channelProp]) {
log.warn([peerId, 'RTCDataChannel', channelProp, 'Aborting closing Datachannel as it does not exists']);
@@ -21516,8 +21571,11 @@ Skylink.prototype._signalingEndOfCandidates = function(targetMid) {
return;
}
+ if (
+ // If peer connection exists first and state is not closed.
+ self._peerConnections[targetMid] && self._peerConnections[targetMid].signalingState !== self.PEER_CONNECTION_STATE.CLOSED &&
// If remote description is set
- if (self._peerConnections[targetMid].remoteDescription && self._peerConnections[targetMid].remoteDescription.sdp &&
+ self._peerConnections[targetMid].remoteDescription && self._peerConnections[targetMid].remoteDescription.sdp &&
// If end-of-candidates signal is received
typeof self._peerEndOfCandidatesCounter[targetMid].expectedLen === 'number' &&
// If all ICE candidates are received
@@ -22486,6 +22544,10 @@ Skylink.prototype._setLocalAndSendMessage = function(targetMid, _sessionDescript
sessionDescription.sdp = self._handleSDPConnectionSettings(targetMid, sessionDescription, 'local');
sessionDescription.sdp = self._removeSDPREMBPackets(targetMid, sessionDescription);
+ if (self._peerConnectionConfig.disableBundle) {
+ sessionDescription.sdp = sessionDescription.sdp.replace(/a=group:BUNDLE.*\r\n/gi, '');
+ }
+
log.log([targetMid, 'RTCSessionDescription', sessionDescription.type,
'Local session description updated ->'], sessionDescription.sdp);
@@ -23019,7 +23081,8 @@ Skylink.prototype._waitForOpenChannel = function(mediaOptions, joinRoomTimestamp
bundlePolicy: self.BUNDLE_POLICY.BALANCED,
rtcpMuxPolicy: self.RTCP_MUX_POLICY.REQUIRE,
iceCandidatePoolSize: 0,
- certificate: self.PEER_CERTIFICATE.AUTO
+ certificate: self.PEER_CERTIFICATE.AUTO,
+ disableBundle: false
};
self._bandwidthAdjuster = null;
@@ -23119,6 +23182,7 @@ Skylink.prototype._waitForOpenChannel = function(mediaOptions, joinRoomTimestamp
}
}
}
+ self._peerConnectionConfig.disableBundle = mediaOptions.peerConnection.disableBundle === true;
}
if (mediaOptions.autoBandwidthAdjustment) {
diff --git a/publish/skylink.complete.min.js b/publish/skylink.complete.min.js
index 3586d61c0..974c19fe2 100644
--- a/publish/skylink.complete.min.js
+++ b/publish/skylink.complete.min.js
@@ -1,4 +1,4 @@
-/*! skylinkjs - v0.6.29 - 2018-02-06 */
+/*! skylinkjs - v0.6.30 - 2018-02-21 */
!function(f){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=f();else if("function"==typeof define&&define.amd)define([],f);else{var g;g="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,g.io=f()}}(function(){var define;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n||e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o0&&!this.encoding){var pack=this.packetBuffer.shift();this.packet(pack)}},Manager.prototype.cleanup=function(){debug("cleanup");for(var sub;sub=this.subs.shift();)sub.destroy();this.packetBuffer=[],this.encoding=!1,this.lastPing=null,this.decoder.destroy()},Manager.prototype.close=Manager.prototype.disconnect=function(){debug("disconnect"),this.skipReconnect=!0,this.reconnecting=!1,"opening"==this.readyState&&this.cleanup(),this.backoff.reset(),this.readyState="closed",this.engine&&this.engine.close()},Manager.prototype.onclose=function(reason){debug("onclose"),this.cleanup(),this.backoff.reset(),this.readyState="closed",this.emit("close",reason),this._reconnection&&!this.skipReconnect&&this.reconnect()},Manager.prototype.reconnect=function(){if(this.reconnecting||this.skipReconnect)return this;var self=this;if(this.backoff.attempts>=this._reconnectionAttempts)debug("reconnect failed"),this.backoff.reset(),this.emitAll("reconnect_failed"),this.reconnecting=!1;else{var delay=this.backoff.duration();debug("will wait %dms before reconnect attempt",delay),this.reconnecting=!0;var timer=setTimeout(function(){self.skipReconnect||(debug("attempting reconnect"),self.emitAll("reconnect_attempt",self.backoff.attempts),self.emitAll("reconnecting",self.backoff.attempts),self.skipReconnect||self.open(function(err){err?(debug("reconnect attempt error"),self.reconnecting=!1,self.reconnect(),self.emitAll("reconnect_error",err.data)):(debug("reconnect success"),self.onreconnect())}))},delay);this.subs.push({destroy:function(){clearTimeout(timer)}})}},Manager.prototype.onreconnect=function(){var attempt=this.backoff.attempts;this.reconnecting=!1,this.backoff.reset(),this.updateSocketIds(),this.emitAll("reconnect",attempt)}},{"./on":3,"./socket":4,backo2:8,"component-bind":11,"component-emitter":12,debug:14,"engine.io-client":16,indexof:32,"socket.io-parser":40}],3:[function(_dereq_,module,exports){function on(obj,ev,fn){return obj.on(ev,fn),{destroy:function(){obj.removeListener(ev,fn)}}}module.exports=on},{}],4:[function(_dereq_,module,exports){function Socket(io,nsp){this.io=io,this.nsp=nsp,this.json=this,this.ids=0,this.acks={},this.receiveBuffer=[],this.sendBuffer=[],this.connected=!1,this.disconnected=!0,this.io.autoConnect&&this.open()}var parser=_dereq_("socket.io-parser"),Emitter=_dereq_("component-emitter"),toArray=_dereq_("to-array"),on=_dereq_("./on"),bind=_dereq_("component-bind"),debug=_dereq_("debug")("socket.io-client:socket"),hasBin=_dereq_("has-binary");module.exports=Socket;var events={connect:1,connect_error:1,connect_timeout:1,connecting:1,disconnect:1,error:1,reconnect:1,reconnect_attempt:1,reconnect_failed:1,reconnect_error:1,reconnecting:1,ping:1,pong:1},emit=Emitter.prototype.emit;Emitter(Socket.prototype),Socket.prototype.subEvents=function(){if(!this.subs){var io=this.io;this.subs=[on(io,"open",bind(this,"onopen")),on(io,"packet",bind(this,"onpacket")),on(io,"close",bind(this,"onclose"))]}},Socket.prototype.open=Socket.prototype.connect=function(){return this.connected?this:(this.subEvents(),this.io.open(),"open"==this.io.readyState&&this.onopen(),this.emit("connecting"),this)},Socket.prototype.send=function(){var args=toArray(arguments);return args.unshift("message"),this.emit.apply(this,args),this},Socket.prototype.emit=function(ev){if(events.hasOwnProperty(ev))return emit.apply(this,arguments),this;var args=toArray(arguments),parserType=parser.EVENT;hasBin(args)&&(parserType=parser.BINARY_EVENT);var packet={type:parserType,data:args};return packet.options={},packet.options.compress=!this.flags||!1!==this.flags.compress,"function"==typeof args[args.length-1]&&(debug("emitting packet with ack id %d",this.ids),this.acks[this.ids]=args.pop(),packet.id=this.ids++),this.connected?this.packet(packet):this.sendBuffer.push(packet),delete this.flags,this},Socket.prototype.packet=function(packet){packet.nsp=this.nsp,this.io.packet(packet)},Socket.prototype.onopen=function(){debug("transport is open - connecting"),"/"!=this.nsp&&this.packet({type:parser.CONNECT})},Socket.prototype.onclose=function(reason){debug("close (%s)",reason),this.connected=!1,this.disconnected=!0,delete this.id,this.emit("disconnect",reason)},Socket.prototype.onpacket=function(packet){if(packet.nsp==this.nsp)switch(packet.type){case parser.CONNECT:this.onconnect();break;case parser.EVENT:case parser.BINARY_EVENT:this.onevent(packet);break;case parser.ACK:case parser.BINARY_ACK:this.onack(packet);break;case parser.DISCONNECT:this.ondisconnect();break;case parser.ERROR:this.emit("error",packet.data)}},Socket.prototype.onevent=function(packet){var args=packet.data||[];debug("emitting event %j",args),null!=packet.id&&(debug("attaching ack callback to event"),args.push(this.ack(packet.id))),this.connected?emit.apply(this,args):this.receiveBuffer.push(args)},Socket.prototype.ack=function(id){var self=this,sent=!1;return function(){if(!sent){sent=!0;var args=toArray(arguments);debug("sending ack %j",args);var type=hasBin(args)?parser.BINARY_ACK:parser.ACK;self.packet({type:type,id:id,data:args})}}},Socket.prototype.onack=function(packet){var ack=this.acks[packet.id];"function"==typeof ack?(debug("calling ack %s with %j",packet.id,packet.data),ack.apply(this,packet.data),delete this.acks[packet.id]):debug("bad ack %s",packet.id)},Socket.prototype.onconnect=function(){this.connected=!0,this.disconnected=!1,this.emit("connect"),this.emitBuffered()},Socket.prototype.emitBuffered=function(){var i;for(i=0;ibytes&&(end=bytes),start>=bytes||start>=end||0===bytes)return new ArrayBuffer(0);for(var abv=new Uint8Array(arraybuffer),result=new Uint8Array(end-start),i=start,ii=0;i0&&opts.jitter<=1?opts.jitter:0,this.attempts=0}module.exports=Backoff,Backoff.prototype.duration=function(){var ms=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var rand=Math.random(),deviation=Math.floor(rand*this.jitter*ms);ms=0==(1&Math.floor(10*rand))?ms-deviation:ms+deviation}return 0|Math.min(ms,this.max)},Backoff.prototype.reset=function(){this.attempts=0},Backoff.prototype.setMin=function(min){this.ms=min},Backoff.prototype.setMax=function(max){this.max=max},Backoff.prototype.setJitter=function(jitter){this.jitter=jitter}},{}],9:[function(_dereq_,module,exports){!function(){"use strict";for(var chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",lookup=new Uint8Array(256),i=0;i>2],base64+=chars[(3&bytes[i])<<4|bytes[i+1]>>4],base64+=chars[(15&bytes[i+1])<<2|bytes[i+2]>>6],base64+=chars[63&bytes[i+2]];return len%3==2?base64=base64.substring(0,base64.length-1)+"=":len%3==1&&(base64=base64.substring(0,base64.length-2)+"=="),base64},exports.decode=function(base64){var i,encoded1,encoded2,encoded3,encoded4,bufferLength=.75*base64.length,len=base64.length,p=0;"="===base64[base64.length-1]&&(bufferLength--,"="===base64[base64.length-2]&&bufferLength--);var arraybuffer=new ArrayBuffer(bufferLength),bytes=new Uint8Array(arraybuffer);for(i=0;i>4,bytes[p++]=(15&encoded2)<<4|encoded3>>2,bytes[p++]=(3&encoded3)<<6|63&encoded4;return arraybuffer}}()},{}],10:[function(_dereq_,module,exports){(function(global){function mapArrayBufferViews(ary){for(var i=0;i=31}function formatArgs(){var args=arguments,useColors=this.useColors;if(args[0]=(useColors?"%c":"")+this.namespace+(useColors?" %c":" ")+args[0]+(useColors?"%c ":" ")+"+"+exports.humanize(this.diff),!useColors)return args;var c="color: "+this.color;args=[args[0],c,"color: inherit"].concat(Array.prototype.slice.call(args,1));var index=0,lastC=0;return args[0].replace(/%[a-z%]/g,function(match){"%%"!==match&&(index++,"%c"===match&&(lastC=index))}),args.splice(lastC,0,c),args}function log(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function save(namespaces){try{null==namespaces?exports.storage.removeItem("debug"):exports.storage.debug=namespaces}catch(e){}}function load(){var r;try{r=exports.storage.debug}catch(e){}return r}function localstorage(){try{return window.localStorage}catch(e){}}exports=module.exports=_dereq_("./debug"),exports.log=log,exports.formatArgs=formatArgs,exports.save=save,exports.load=load,exports.useColors=useColors,exports.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:localstorage(),exports.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],exports.formatters.j=function(v){return JSON.stringify(v)},exports.enable(load())},{"./debug":15}],15:[function(_dereq_,module,exports){function selectColor(){return exports.colors[prevColor++%exports.colors.length]}function debug(namespace){function disabled(){}function enabled(){var self=enabled,curr=+new Date,ms=curr-(prevTime||curr);self.diff=ms,self.prev=prevTime,self.curr=curr,prevTime=curr,null==self.useColors&&(self.useColors=exports.useColors()),null==self.color&&self.useColors&&(self.color=selectColor());var args=Array.prototype.slice.call(arguments);args[0]=exports.coerce(args[0]),"string"!=typeof args[0]&&(args=["%o"].concat(args));var index=0;args[0]=args[0].replace(/%([a-z%])/g,function(match,format){if("%%"===match)return match;index++;var formatter=exports.formatters[format];if("function"==typeof formatter){var val=args[index];match=formatter.call(self,val),args.splice(index,1),index--}return match}),"function"==typeof exports.formatArgs&&(args=exports.formatArgs.apply(self,args)),(enabled.log||exports.log||console.log.bind(console)).apply(self,args)}disabled.enabled=!1,enabled.enabled=!0;var fn=exports.enabled(namespace)?enabled:disabled;return fn.namespace=namespace,fn}function enable(namespaces){exports.save(namespaces);for(var split=(namespaces||"").split(/[\s,]+/),len=split.length,i=0;i0&&(this.extraHeaders=opts.extraHeaders),this.open()}function clone(obj){var o={};for(var i in obj)obj.hasOwnProperty(i)&&(o[i]=obj[i]);return o}var transports=_dereq_("./transports"),Emitter=_dereq_("component-emitter"),debug=_dereq_("debug")("engine.io-client:socket"),index=_dereq_("indexof"),parser=_dereq_("engine.io-parser"),parseuri=_dereq_("parseuri"),parsejson=_dereq_("parsejson"),parseqs=_dereq_("parseqs");module.exports=Socket,Socket.priorWebsocketSuccess=!1,Emitter(Socket.prototype),Socket.protocol=parser.protocol,Socket.Socket=Socket,Socket.Transport=_dereq_("./transport"),Socket.transports=_dereq_("./transports"),Socket.parser=_dereq_("engine.io-parser"),Socket.prototype.createTransport=function(name){debug('creating transport "%s"',name);var query=clone(this.query);return query.EIO=parser.protocol,query.transport=name,this.id&&(query.sid=this.id),new transports[name]({agent:this.agent,hostname:this.hostname,port:this.port,secure:this.secure,path:this.path,query:query,forceJSONP:this.forceJSONP,jsonp:this.jsonp,forceBase64:this.forceBase64,enablesXDR:this.enablesXDR,timestampRequests:this.timestampRequests,timestampParam:this.timestampParam,policyPort:this.policyPort,socket:this,pfx:this.pfx,key:this.key,passphrase:this.passphrase,cert:this.cert,ca:this.ca,ciphers:this.ciphers,rejectUnauthorized:this.rejectUnauthorized,perMessageDeflate:this.perMessageDeflate,extraHeaders:this.extraHeaders})},Socket.prototype.open=function(){var transport;if(this.rememberUpgrade&&Socket.priorWebsocketSuccess&&-1!=this.transports.indexOf("websocket"))transport="websocket";else{if(0===this.transports.length){var self=this;return void setTimeout(function(){self.emit("error","No transports available")},0)}transport=this.transports[0]}this.readyState="opening";try{transport=this.createTransport(transport)}catch(e){return this.transports.shift(),void this.open()}transport.open(),this.setTransport(transport)},Socket.prototype.setTransport=function(transport){debug("setting transport %s",transport.name);var self=this;this.transport&&(debug("clearing existing transport %s",this.transport.name),this.transport.removeAllListeners()),this.transport=transport,transport.on("drain",function(){self.onDrain()}).on("packet",function(packet){self.onPacket(packet)}).on("error",function(e){self.onError(e)}).on("close",function(){self.onClose("transport close")})},Socket.prototype.probe=function(name){function onTransportOpen(){if(self.onlyBinaryUpgrades){var upgradeLosesBinary=!this.supportsBinary&&self.transport.supportsBinary;failed=failed||upgradeLosesBinary}failed||(debug('probe transport "%s" opened',name),transport.send([{type:"ping",data:"probe"}]),transport.once("packet",function(msg){if(!failed)if("pong"==msg.type&&"probe"==msg.data){if(debug('probe transport "%s" pong',name),self.upgrading=!0,self.emit("upgrading",transport),!transport)return;Socket.priorWebsocketSuccess="websocket"==transport.name,debug('pausing current transport "%s"',self.transport.name),self.transport.pause(function(){failed||"closed"!=self.readyState&&(debug("changing transport and sending upgrade packet"),cleanup(),self.setTransport(transport),transport.send([{type:"upgrade"}]),self.emit("upgrade",transport),transport=null,self.upgrading=!1,self.flush())})}else{debug('probe transport "%s" failed',name);var err=new Error("probe error");err.transport=transport.name,self.emit("upgradeError",err)}}))}function freezeTransport(){failed||(failed=!0,cleanup(),transport.close(),transport=null)}function onerror(err){var error=new Error("probe error: "+err);error.transport=transport.name,freezeTransport(),debug('probe transport "%s" failed because of error: %s',name,err),self.emit("upgradeError",error)}function onTransportClose(){onerror("transport closed")}function onclose(){onerror("socket closed")}function onupgrade(to){transport&&to.name!=transport.name&&(debug('"%s" works - aborting "%s"',to.name,transport.name),freezeTransport())}function cleanup(){transport.removeListener("open",onTransportOpen),transport.removeListener("error",onerror),transport.removeListener("close",onTransportClose),self.removeListener("close",onclose),self.removeListener("upgrading",onupgrade)}debug('probing transport "%s"',name);var transport=this.createTransport(name,{probe:1}),failed=!1,self=this;Socket.priorWebsocketSuccess=!1,transport.once("open",onTransportOpen),transport.once("error",onerror),transport.once("close",onTransportClose),this.once("close",onclose),this.once("upgrading",onupgrade),transport.open()},Socket.prototype.onOpen=function(){if(debug("socket open"),this.readyState="open",Socket.priorWebsocketSuccess="websocket"==this.transport.name,this.emit("open"),this.flush(),"open"==this.readyState&&this.upgrade&&this.transport.pause){debug("starting upgrade probes");for(var i=0,l=this.upgrades.length;i';iframe=document.createElement(html)}catch(e){iframe=document.createElement("iframe"),iframe.name=self.iframeId,iframe.src="javascript:0"}iframe.id=self.iframeId,self.form.appendChild(iframe),self.iframe=iframe}var self=this;if(!this.form){var iframe,form=document.createElement("form"),area=document.createElement("textarea"),id=this.iframeId="eio_iframe_"+this.index;form.className="socketio",form.style.position="absolute",form.style.top="-1000px",form.style.left="-1000px",form.target=id,form.method="POST",form.setAttribute("accept-charset","utf-8"),area.name="d",form.appendChild(area),document.body.appendChild(form),this.form=form,this.area=area}this.form.action=this.uri(),initIframe(),data=data.replace(rEscapedNewline,"\\\n"),this.area.value=data.replace(rNewline,"\\n");try{this.form.submit()}catch(e){}this.iframe.attachEvent?this.iframe.onreadystatechange=function(){"complete"==self.iframe.readyState&&complete()}:this.iframe.onload=complete}}).call(this,"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{})},{"./polling":23,"component-inherit":13}],22:[function(_dereq_,module,exports){(function(global){function empty(){}function XHR(opts){if(Polling.call(this,opts),global.location){var isSSL="https:"==location.protocol,port=location.port;port||(port=isSSL?443:80),this.xd=opts.hostname!=global.location.hostname||port!=opts.port,this.xs=opts.secure!=isSSL}else this.extraHeaders=opts.extraHeaders}function Request(opts){this.method=opts.method||"GET",this.uri=opts.uri,this.xd=!!opts.xd,this.xs=!!opts.xs,this.async=!1!==opts.async,this.data=void 0!=opts.data?opts.data:null,this.agent=opts.agent,this.isBinary=opts.isBinary,this.supportsBinary=opts.supportsBinary,this.enablesXDR=opts.enablesXDR,this.pfx=opts.pfx,this.key=opts.key,this.passphrase=opts.passphrase,this.cert=opts.cert,this.ca=opts.ca,this.ciphers=opts.ciphers,this.rejectUnauthorized=opts.rejectUnauthorized,this.extraHeaders=opts.extraHeaders,this.create()}function unloadHandler(){for(var i in Request.requests)Request.requests.hasOwnProperty(i)&&Request.requests[i].abort()}var XMLHttpRequest=_dereq_("xmlhttprequest-ssl"),Polling=_dereq_("./polling"),Emitter=_dereq_("component-emitter"),inherit=_dereq_("component-inherit"),debug=_dereq_("debug")("engine.io-client:polling-xhr");module.exports=XHR,module.exports.Request=Request,inherit(XHR,Polling),XHR.prototype.supportsBinary=!0,XHR.prototype.request=function(opts){return opts=opts||{},opts.uri=this.uri(),opts.xd=this.xd,opts.xs=this.xs,opts.agent=this.agent||!1,opts.supportsBinary=this.supportsBinary,opts.enablesXDR=this.enablesXDR,opts.pfx=this.pfx,opts.key=this.key,opts.passphrase=this.passphrase,opts.cert=this.cert,opts.ca=this.ca,opts.ciphers=this.ciphers,opts.rejectUnauthorized=this.rejectUnauthorized,opts.extraHeaders=this.extraHeaders,new Request(opts)},XHR.prototype.doWrite=function(data,fn){var isBinary="string"!=typeof data&&void 0!==data,req=this.request({method:"POST",data:data,isBinary:isBinary}),self=this;req.on("success",fn),req.on("error",function(err){self.onError("xhr post error",err)}),this.sendXhr=req},XHR.prototype.doPoll=function(){debug("xhr poll");var req=this.request(),self=this;req.on("data",function(data){self.onData(data)}),req.on("error",function(err){self.onError("xhr poll error",err)}),this.pollXhr=req},Emitter(Request.prototype),Request.prototype.create=function(){var opts={agent:this.agent,xdomain:this.xd,xscheme:this.xs,enablesXDR:this.enablesXDR};opts.pfx=this.pfx,opts.key=this.key,opts.passphrase=this.passphrase,opts.cert=this.cert,opts.ca=this.ca,opts.ciphers=this.ciphers,opts.rejectUnauthorized=this.rejectUnauthorized;var xhr=this.xhr=new XMLHttpRequest(opts),self=this;try{debug("xhr open %s: %s",this.method,this.uri),xhr.open(this.method,this.uri,this.async);try{if(this.extraHeaders){xhr.setDisableHeaderCheck(!0);for(var i in this.extraHeaders)this.extraHeaders.hasOwnProperty(i)&&xhr.setRequestHeader(i,this.extraHeaders[i])}}catch(e){}if(this.supportsBinary&&(xhr.responseType="arraybuffer"),"POST"==this.method)try{this.isBinary?xhr.setRequestHeader("Content-type","application/octet-stream"):xhr.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(e){}"withCredentials"in xhr&&(xhr.withCredentials=!0),this.hasXDR()?(xhr.onload=function(){self.onLoad()},xhr.onerror=function(){self.onError(xhr.responseText)}):xhr.onreadystatechange=function(){4==xhr.readyState&&(200==xhr.status||1223==xhr.status?self.onLoad():setTimeout(function(){self.onError(xhr.status)},0))},debug("xhr data %s",this.data),xhr.send(this.data)}catch(e){return void setTimeout(function(){self.onError(e)},0)}global.document&&(this.index=Request.requestsCount++,Request.requests[this.index]=this)},Request.prototype.onSuccess=function(){this.emit("success"),this.cleanup()},Request.prototype.onData=function(data){this.emit("data",data),this.onSuccess()},Request.prototype.onError=function(err){this.emit("error",err),this.cleanup(!0)},Request.prototype.cleanup=function(fromError){if(void 0!==this.xhr&&null!==this.xhr){if(this.hasXDR()?this.xhr.onload=this.xhr.onerror=empty:this.xhr.onreadystatechange=empty,fromError)try{this.xhr.abort()}catch(e){}global.document&&delete Request.requests[this.index],this.xhr=null}},Request.prototype.onLoad=function(){var data;try{var contentType;try{contentType=this.xhr.getResponseHeader("Content-Type").split(";")[0]}catch(e){}if("application/octet-stream"===contentType)data=this.xhr.response;else if(this.supportsBinary)try{data=String.fromCharCode.apply(null,new Uint8Array(this.xhr.response))}catch(e){for(var ui8Arr=new Uint8Array(this.xhr.response),dataArray=[],idx=0,length=ui8Arr.length;idx1?{type:packetslist[type],data:data.substring(1)}:{type:packetslist[type]}:err}var asArray=new Uint8Array(data),type=asArray[0],rest=sliceBuffer(data,1);return Blob&&"blob"===binaryType&&(rest=new Blob([rest])),{type:packetslist[type],data:rest}},exports.decodeBase64Packet=function(msg,binaryType){var type=packetslist[msg.charAt(0)];if(!global.ArrayBuffer)return{type:type,data:{base64:!0,data:msg.substr(1)}};var data=base64encoder.decode(msg.substr(1));return"blob"===binaryType&&Blob&&(data=new Blob([data])),{type:type,data:data}},exports.encodePayload=function(packets,supportsBinary,callback){function setLengthHeader(message){return message.length+":"+message}function encodeOne(packet,doneCallback){exports.encodePacket(packet,!!isBinary&&supportsBinary,!0,function(message){doneCallback(null,setLengthHeader(message))})}"function"==typeof supportsBinary&&(callback=supportsBinary,supportsBinary=null);var isBinary=hasBinary(packets);return supportsBinary&&isBinary?Blob&&!dontSendBlobs?exports.encodePayloadAsBlob(packets,callback):exports.encodePayloadAsArrayBuffer(packets,callback):packets.length?void map(packets,encodeOne,function(err,results){return callback(results.join(""))}):callback("0:")},exports.decodePayload=function(data,binaryType,callback){if("string"!=typeof data)return exports.decodePayloadAsBinary(data,binaryType,callback);"function"==typeof binaryType&&(callback=binaryType,binaryType=null);var packet;if(""==data)return callback(err,0,1);for(var n,msg,length="",i=0,l=data.length;i0;){for(var tailArray=new Uint8Array(bufferTail),isString=0===tailArray[0],msgLength="",i=1;255!=tailArray[i];i++){if(msgLength.length>310){numberTooLong=!0;break}msgLength+=tailArray[i]}if(numberTooLong)return callback(err,0,1);bufferTail=sliceBuffer(bufferTail,2+msgLength.length),msgLength=parseInt(msgLength);var msg=sliceBuffer(bufferTail,0,msgLength);if(isString)try{msg=String.fromCharCode.apply(null,new Uint8Array(msg))}catch(e){var typed=new Uint8Array(msg);msg="";for(var i=0;i1)))/4)-floor((year-1901+month)/100)+floor((year-1601+month)/400)};if((isProperty=objectProto.hasOwnProperty)||(isProperty=function(property){var constructor,members={};return(members.__proto__=null,members.__proto__={toString:1},members).toString!=getClass?isProperty=function(property){var original=this.__proto__,result=property in(this.__proto__=null,this);return this.__proto__=original,result}:(constructor=members.constructor,isProperty=function(property){var parent=(this.constructor||constructor).prototype;return property in this&&!(property in parent&&this[property]===parent[property])}),members=null,isProperty.call(this,property)}),forEach=function(object,callback){var Properties,members,property,size=0;(Properties=function(){this.valueOf=0}).prototype.valueOf=0,members=new Properties;for(property in members)isProperty.call(members,property)&&size++;return Properties=members=null,size?forEach=2==size?function(object,callback){var property,members={},isFunction=getClass.call(object)==functionClass;for(property in object)isFunction&&"prototype"==property||isProperty.call(members,property)||!(members[property]=1)||!isProperty.call(object,property)||callback(property)}:function(object,callback){var property,isConstructor,isFunction=getClass.call(object)==functionClass;for(property in object)isFunction&&"prototype"==property||!isProperty.call(object,property)||(isConstructor="constructor"===property)||callback(property);(isConstructor||isProperty.call(object,property="constructor"))&&callback(property)}:(members=["valueOf","toString","toLocaleString","propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"],forEach=function(object,callback){var property,length,isFunction=getClass.call(object)==functionClass,hasProperty=!isFunction&&"function"!=typeof object.constructor&&objectTypes[typeof object.hasOwnProperty]&&object.hasOwnProperty||isProperty;for(property in object)isFunction&&"prototype"==property||!hasProperty.call(object,property)||callback(property);for(length=members.length;property=members[--length];hasProperty.call(object,property)&&callback(property));}),forEach(object,callback)},!has("json-stringify")){var Escapes={92:"\\\\",34:'\\"',8:"\\b",12:"\\f",10:"\\n",13:"\\r",9:"\\t"},leadingZeroes="000000",toPaddedString=function(width,value){return(leadingZeroes+(value||0)).slice(-width)},unicodePrefix="\\u00",quote=function(value){for(var result='"',index=0,length=value.length,useCharIndex=!charIndexBuggy||length>10,symbols=useCharIndex&&(charIndexBuggy?value.split(""):value);index-1/0&&value<1/0){if(getDay){for(date=floor(value/864e5),year=floor(date/365.2425)+1970-1;getDay(year+1,0)<=date;year++);for(month=floor((date-getDay(year,0))/30.42);getDay(year,month+1)<=date;month++);date=1+date-getDay(year,month),time=(value%864e5+864e5)%864e5,hours=floor(time/36e5)%24,minutes=floor(time/6e4)%60,seconds=floor(time/1e3)%60,milliseconds=time%1e3}else year=value.getUTCFullYear(),month=value.getUTCMonth(),date=value.getUTCDate(),hours=value.getUTCHours(),minutes=value.getUTCMinutes(),seconds=value.getUTCSeconds(),milliseconds=value.getUTCMilliseconds();value=(year<=0||year>=1e4?(year<0?"-":"+")+toPaddedString(6,year<0?-year:year):toPaddedString(4,year))+"-"+toPaddedString(2,month+1)+"-"+toPaddedString(2,date)+"T"+toPaddedString(2,hours)+":"+toPaddedString(2,minutes)+":"+toPaddedString(2,seconds)+"."+toPaddedString(3,milliseconds)+"Z"}else value=null;if(callback&&(value=callback.call(object,property,value)),null===value)return"null";if((className=getClass.call(value))==booleanClass)return""+value;if(className==numberClass)return value>-1/0&&value<1/0?""+value:"null";if(className==stringClass)return quote(""+value);if("object"==typeof value){for(length=stack.length;length--;)if(stack[length]===value)throw TypeError();if(stack.push(value),results=[],prefix=indentation,indentation+=whitespace,className==arrayClass){for(index=0,length=value.length;index0)for(whitespace="",width>10&&(width=10);whitespace.length=48&&charCode<=57||charCode>=97&&charCode<=102||charCode>=65&&charCode<=70||abort();value+=fromCharCode("0x"+source.slice(begin,Index));break;default:abort()}else{if(34==charCode)break;for(charCode=source.charCodeAt(Index),begin=Index;charCode>=32&&92!=charCode&&34!=charCode;)charCode=source.charCodeAt(++Index);value+=source.slice(begin,Index)}if(34==source.charCodeAt(Index))return Index++,value;abort();default:if(begin=Index,45==charCode&&(isSigned=!0,charCode=source.charCodeAt(++Index)),charCode>=48&&charCode<=57){for(48==charCode&&(charCode=source.charCodeAt(Index+1))>=48&&charCode<=57&&abort(),isSigned=!1;Index=48&&charCode<=57;Index++);if(46==source.charCodeAt(Index)){for(position=++Index;position=48&&charCode<=57;position++);position==Index&&abort(),Index=position}if(101==(charCode=source.charCodeAt(Index))||69==charCode){for(charCode=source.charCodeAt(++Index),43!=charCode&&45!=charCode||Index++,position=Index;position=48&&charCode<=57;position++);position==Index&&abort(),Index=position}return+source.slice(begin,Index)}if(isSigned&&abort(),"true"==source.slice(Index,Index+4))return Index+=4,!0;if("false"==source.slice(Index,Index+5))return Index+=5,!1;if("null"==source.slice(Index,Index+4))return Index+=4,null;abort()}return"$"},get=function(value){var results,hasMembers;if("$"==value&&abort(),"string"==typeof value){if("@"==(charIndexBuggy?value.charAt(0):value[0]))return value.slice(1);if("["==value){for(results=[];"]"!=(value=lex());hasMembers||(hasMembers=!0))hasMembers&&(","==value?"]"==(value=lex())&&abort():abort()),","==value&&abort(),results.push(get(value));return results}if("{"==value){for(results={};"}"!=(value=lex());hasMembers||(hasMembers=!0))hasMembers&&(","==value?"}"==(value=lex())&&abort():abort()),","!=value&&"string"==typeof value&&"@"==(charIndexBuggy?value.charAt(0):value[0])&&":"==lex()||abort(),results[value.slice(1)]=get(lex());return results}abort()}return value},update=function(source,property,callback){var element=walk(source,property,callback);element===undef?delete source[property]:source[property]=element},walk=function(source,property,callback){var length,value=source[property];if("object"==typeof value&&value)if(getClass.call(value)==arrayClass)for(length=value.length;length--;)update(value,length,callback);else forEach(value,function(property){update(value,property,callback)});return callback.call(source,property,value)};exports.parse=function(source,callback){var result,value;return Index=0,Source=""+source,result=get(lex()),"$"!=lex()&&abort(),Index=Source=null,callback&&getClass.call(callback)==functionClass?walk((value={},value[""]=result,value),"",callback):result}}}return exports.runInContext=runInContext,exports}var isLoader="function"==typeof define&&define.amd,objectTypes={function:!0,object:!0},freeExports=objectTypes[typeof exports]&&exports&&!exports.nodeType&&exports,root=objectTypes[typeof window]&&window||this,freeGlobal=freeExports&&objectTypes[typeof module]&&module&&!module.nodeType&&"object"==typeof global&&global;if(!freeGlobal||freeGlobal.global!==freeGlobal&&freeGlobal.window!==freeGlobal&&freeGlobal.self!==freeGlobal||(root=freeGlobal),freeExports&&!isLoader)runInContext(root,freeExports);else{var nativeJSON=root.JSON,previousJSON=root.JSON3,isRestored=!1,JSON3=runInContext(root,root.JSON3={noConflict:function(){return isRestored||(isRestored=!0,root.JSON=nativeJSON,root.JSON3=previousJSON,nativeJSON=previousJSON=null),JSON3}});root.JSON={parse:JSON3.parse,stringify:JSON3.stringify}}isLoader&&define(function(){return JSON3})}).call(this)}).call(this,"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{})},{}],35:[function(_dereq_,module,exports){function parse(str){if(str=""+str,!(str.length>1e4)){var match=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str);if(match){var n=parseFloat(match[1]);switch((match[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return n*y;case"days":case"day":case"d":return n*d;case"hours":case"hour":case"hrs":case"hr":case"h":return n*h;case"minutes":case"minute":case"mins":case"min":case"m":return n*m;case"seconds":case"second":case"secs":case"sec":case"s":return n*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n}}}}function short(ms){return ms>=d?Math.round(ms/d)+"d":ms>=h?Math.round(ms/h)+"h":ms>=m?Math.round(ms/m)+"m":ms>=s?Math.round(ms/s)+"s":ms+"ms"}function long(ms){return plural(ms,d,"day")||plural(ms,h,"hour")||plural(ms,m,"minute")||plural(ms,s,"second")||ms+" ms"}function plural(ms,n,name){if(!(ms=55296&&value<=56319&&counter65535&&(value-=65536,output+=stringFromCharCode(value>>>10&1023|55296),value=56320|1023&value),output+=stringFromCharCode(value);return output}function checkScalarValue(codePoint){if(codePoint>=55296&&codePoint<=57343)throw Error("Lone surrogate U+"+codePoint.toString(16).toUpperCase()+" is not a scalar value")}function createByte(codePoint,shift){return stringFromCharCode(codePoint>>shift&63|128)}function encodeCodePoint(codePoint){if(0==(4294967168&codePoint))return stringFromCharCode(codePoint);var symbol="";return 0==(4294965248&codePoint)?symbol=stringFromCharCode(codePoint>>6&31|192):0==(4294901760&codePoint)?(checkScalarValue(codePoint),symbol=stringFromCharCode(codePoint>>12&15|224),symbol+=createByte(codePoint,6)):0==(4292870144&codePoint)&&(symbol=stringFromCharCode(codePoint>>18&7|240),symbol+=createByte(codePoint,12),symbol+=createByte(codePoint,6)),symbol+=stringFromCharCode(63&codePoint|128)}function utf8encode(string){for(var codePoint,codePoints=ucs2decode(string),length=codePoints.length,index=-1,byteString="";++index=byteCount)throw Error("Invalid byte index");var continuationByte=255&byteArray[byteIndex];if(byteIndex++,128==(192&continuationByte))return 63&continuationByte;throw Error("Invalid continuation byte")}function decodeSymbol(){var byte1,byte2,byte3,byte4,codePoint;if(byteIndex>byteCount)throw Error("Invalid byte index");if(byteIndex==byteCount)return!1;if(byte1=255&byteArray[byteIndex],byteIndex++,0==(128&byte1))return byte1;if(192==(224&byte1)){var byte2=readContinuationByte();if((codePoint=(31&byte1)<<6|byte2)>=128)return codePoint;throw Error("Invalid continuation byte")}if(224==(240&byte1)){if(byte2=readContinuationByte(),byte3=readContinuationByte(),(codePoint=(15&byte1)<<12|byte2<<6|byte3)>=2048)return checkScalarValue(codePoint),codePoint;throw Error("Invalid continuation byte")}if(240==(248&byte1)&&(byte2=readContinuationByte(),byte3=readContinuationByte(),byte4=readContinuationByte(),(codePoint=(15&byte1)<<18|byte2<<12|byte3<<6|byte4)>=65536&&codePoint<=1114111))return codePoint;throw Error("Invalid UTF-8 detected")}function utf8decode(byteString){byteArray=ucs2decode(byteString),byteCount=byteArray.length,byteIndex=0;for(var tmp,codePoints=[];!1!==(tmp=decodeSymbol());)codePoints.push(tmp);return ucs2encode(codePoints)}var freeExports="object"==typeof exports&&exports,freeModule="object"==typeof module&&module&&module.exports==freeExports&&module,freeGlobal="object"==typeof global&&global;freeGlobal.global!==freeGlobal&&freeGlobal.window!==freeGlobal||(root=freeGlobal);var byteArray,byteCount,byteIndex,stringFromCharCode=String.fromCharCode,utf8={version:"2.0.0",encode:utf8encode,decode:utf8decode};if("function"==typeof define&&"object"==typeof define.amd&&define.amd)define(function(){return utf8});else if(freeExports&&!freeExports.nodeType)if(freeModule)freeModule.exports=utf8;else{var object={},hasOwnProperty=object.hasOwnProperty;for(var key in utf8)hasOwnProperty.call(utf8,key)&&(freeExports[key]=utf8[key])}else root.utf8=utf8}(this)}).call(this,"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{})},{}],45:[function(_dereq_,module,exports){"use strict";function encode(num){var encoded="";do{encoded=alphabet[num%length]+encoded,num=Math.floor(num/length)}while(num>0);return encoded}function decode(str){var decoded=0;for(i=0;i0&&(console.warn("Timeout for addRemoteCandidate. Consider sending an end-of-candidates notification"),transceiver.iceTransport.addRemoteCandidate({}))})},4e3),new Promise(function(resolve){args.length>1&&"function"==typeof args[1]&&args[1].apply(null),resolve()})},RTCPeerConnection.prototype.close=function(){this.transceivers.forEach(function(transceiver){transceiver.iceTransport&&transceiver.iceTransport.stop(),transceiver.dtlsTransport&&transceiver.dtlsTransport.stop(),transceiver.rtpSender&&transceiver.rtpSender.stop(),transceiver.rtpReceiver&&transceiver.rtpReceiver.stop()}),this._updateSignalingState("closed")},RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event("signalingstatechange");this.dispatchEvent(event),null!==this.onsignalingstatechange&&this.onsignalingstatechange(event)},RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var self=this;"stable"===this.signalingState&&!0!==this.needNegotiation&&(this.needNegotiation=!0,window.setTimeout(function(){if(!1!==self.needNegotiation){self.needNegotiation=!1;var event=new Event("negotiationneeded");self.dispatchEvent(event),null!==self.onnegotiationneeded&&self.onnegotiationneeded(event)}},0))},RTCPeerConnection.prototype._updateConnectionState=function(){var newState,self=this,states={new:0,closed:0,connecting:0,checking:0,connected:0,completed:0,disconnected:0,failed:0};if(this.transceivers.forEach(function(transceiver){states[transceiver.iceTransport.state]++,states[transceiver.dtlsTransport.state]++}),states.connected+=states.completed,newState="new",states.failed>0?newState="failed":states.connecting>0||states.checking>0?newState="connecting":states.disconnected>0?newState="disconnected":states.new>0?newState="new":(states.connected>0||states.completed>0)&&(newState="connected"),newState!==self.iceConnectionState){self.iceConnectionState=newState;var event=new Event("iceconnectionstatechange");this.dispatchEvent(event),null!==this.oniceconnectionstatechange&&this.oniceconnectionstatechange(event)}},RTCPeerConnection.prototype.createOffer=function(){var offerOptions,self=this,args=arguments;1===arguments.length&&"function"!=typeof arguments[0]?offerOptions=arguments[0]:3===arguments.length&&(offerOptions=arguments[2]);var numAudioTracks=this.transceivers.filter(function(t){return"audio"===t.kind}).length,numVideoTracks=this.transceivers.filter(function(t){return"video"===t.kind}).length;if(offerOptions){if(offerOptions.mandatory||offerOptions.optional)throw new TypeError("Legacy mandatory/optional constraints not supported.");void 0!==offerOptions.offerToReceiveAudio&&(numAudioTracks=!0===offerOptions.offerToReceiveAudio?1:!1===offerOptions.offerToReceiveAudio?0:offerOptions.offerToReceiveAudio),void 0!==offerOptions.offerToReceiveVideo&&(numVideoTracks=!0===offerOptions.offerToReceiveVideo?1:!1===offerOptions.offerToReceiveVideo?0:offerOptions.offerToReceiveVideo)}for(this.transceivers.forEach(function(transceiver){"audio"===transceiver.kind?--numAudioTracks<0&&(transceiver.wantReceive=!1):"video"===transceiver.kind&&--numVideoTracks<0&&(transceiver.wantReceive=!1)});numAudioTracks>0||numVideoTracks>0;)numAudioTracks>0&&(this._createTransceiver("audio"),numAudioTracks--),numVideoTracks>0&&(this._createTransceiver("video"),numVideoTracks--);var sdp=SDPUtils.writeSessionBoilerplate(this._sdpSessionId,this._sdpSessionVersion++);this.transceivers.forEach(function(transceiver,sdpMLineIndex){var track=transceiver.track,kind=transceiver.kind,mid=SDPUtils.generateIdentifier();transceiver.mid=mid,transceiver.iceGatherer||(transceiver.iceGatherer=self._createIceGatherer(sdpMLineIndex,self.usingBundle));var localCapabilities=window.RTCRtpSender.getCapabilities(kind);edgeVersion<15019&&(localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return"rtx"!==codec.name})),localCapabilities.codecs.forEach(function(codec){"H264"===codec.name&&void 0===codec.parameters["level-asymmetry-allowed"]&&(codec.parameters["level-asymmetry-allowed"]="1")});var sendEncodingParameters=[{ssrc:1001*(2*sdpMLineIndex+1)}];track&&edgeVersion>=15019&&"video"===kind&&(sendEncodingParameters[0].rtx={ssrc:1001*(2*sdpMLineIndex+1)+1}),transceiver.wantReceive&&(transceiver.rtpReceiver=new window.RTCRtpReceiver(transceiver.dtlsTransport,kind)),transceiver.localCapabilities=localCapabilities,transceiver.sendEncodingParameters=sendEncodingParameters}),"max-compat"!==this._config.bundlePolicy&&(sdp+="a=group:BUNDLE "+this.transceivers.map(function(t){return t.mid}).join(" ")+"\r\n"),sdp+="a=ice-options:trickle\r\n",this.transceivers.forEach(function(transceiver,sdpMLineIndex){sdp+=writeMediaSection(transceiver,transceiver.localCapabilities,"offer",transceiver.stream),sdp+="a=rtcp-rsize\r\n",!transceiver.iceGatherer||"new"===self.iceGatheringState||0!==sdpMLineIndex&&self.usingBundle||(transceiver.iceGatherer.getLocalCandidates().forEach(function(cand){cand.component=1,sdp+="a="+SDPUtils.writeCandidate(cand)+"\r\n"}),"completed"===transceiver.iceGatherer.state&&(sdp+="a=end-of-candidates\r\n"))});var desc=new window.RTCSessionDescription({type:"offer",sdp:sdp});return new Promise(function(resolve){if(args.length>0&&"function"==typeof args[0])return args[0].apply(null,[desc]),void resolve();resolve(desc)})},RTCPeerConnection.prototype.createAnswer=function(){var args=arguments,sdp=SDPUtils.writeSessionBoilerplate(this._sdpSessionId,this._sdpSessionVersion++);this.usingBundle&&(sdp+="a=group:BUNDLE "+this.transceivers.map(function(t){return t.mid}).join(" ")+"\r\n");var mediaSectionsInOffer=SDPUtils.splitSections(this.remoteDescription.sdp).length-1;this.transceivers.forEach(function(transceiver,sdpMLineIndex){if(!(sdpMLineIndex+1>mediaSectionsInOffer)){if(transceiver.isDatachannel)return void(sdp+="m=application 0 DTLS/SCTP 5000\r\nc=IN IP4 0.0.0.0\r\na=mid:"+transceiver.mid+"\r\n");if(transceiver.stream){var localTrack;"audio"===transceiver.kind?localTrack=transceiver.stream.getAudioTracks()[0]:"video"===transceiver.kind&&(localTrack=transceiver.stream.getVideoTracks()[0]),localTrack&&edgeVersion>=15019&&"video"===transceiver.kind&&(transceiver.sendEncodingParameters[0].rtx={ssrc:1001*(2*sdpMLineIndex+2)+1})}var commonCapabilities=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);!commonCapabilities.codecs.filter(function(c){return"rtx"===c.name.toLowerCase()}).length&&transceiver.sendEncodingParameters[0].rtx&&delete transceiver.sendEncodingParameters[0].rtx,sdp+=writeMediaSection(transceiver,commonCapabilities,"answer",transceiver.stream),transceiver.rtcpParameters&&transceiver.rtcpParameters.reducedSize&&(sdp+="a=rtcp-rsize\r\n")}});var desc=new window.RTCSessionDescription({type:"answer",sdp:sdp});return new Promise(function(resolve){if(args.length>0&&"function"==typeof args[0])return args[0].apply(null,[desc]),void resolve();resolve(desc)})},RTCPeerConnection.prototype.addIceCandidate=function(candidate){var err,sections;if(candidate&&""!==candidate.candidate){if(!candidate.sdpMLineIndex&&!candidate.sdpMid)throw new TypeError("sdpMLineIndex or sdpMid required");if(this.remoteDescription){var sdpMLineIndex=candidate.sdpMLineIndex;if(candidate.sdpMid)for(var i=0;i0?SDPUtils.parseCandidate(candidate.candidate):{};if("tcp"===cand.protocol&&(0===cand.port||9===cand.port))return Promise.resolve();if(cand.component&&1!==cand.component)return Promise.resolve();(0===sdpMLineIndex||sdpMLineIndex>0&&transceiver.iceTransport!==this.transceivers[0].iceTransport)&&transceiver.iceTransport.addRemoteCandidate(cand);var candidateString=candidate.candidate.trim();0===candidateString.indexOf("a=")&&(candidateString=candidateString.substr(2)),sections=SDPUtils.splitSections(this.remoteDescription.sdp),sections[sdpMLineIndex+1]+="a="+(cand.type?candidateString:"end-of-candidates")+"\r\n",this.remoteDescription.sdp=sections.join("")}else err=new Error("Can not add ICE candidate"),err.name="OperationError"}else err=new Error("Can not add ICE candidate without a remote description"),err.name="InvalidStateError"}else for(var j=0;j2&&"function"==typeof args[2]&&args[2].apply(null,[err]),reject(err)):(args.length>1&&"function"==typeof args[1]&&args[1].apply(null),resolve())})},RTCPeerConnection.prototype.getStats=function(){var promises=[];this.transceivers.forEach(function(transceiver){["rtpSender","rtpReceiver","iceGatherer","iceTransport","dtlsTransport"].forEach(function(method){transceiver[method]&&promises.push(transceiver[method].getStats())})});var cb=arguments.length>1&&"function"==typeof arguments[1]&&arguments[1],fixStatsType=function(stat){return{inboundrtp:"inbound-rtp",outboundrtp:"outbound-rtp",candidatepair:"candidate-pair",localcandidate:"local-candidate",remotecandidate:"remote-candidate"}[stat.type]||stat.type};return new Promise(function(resolve){var results=new Map;Promise.all(promises).then(function(res){res.forEach(function(result){Object.keys(result).forEach(function(id){result[id].type=fixStatsType(result[id]),results.set(id,result[id])})}),cb&&cb.apply(null,results),resolve(results)})})},RTCPeerConnection}},{sdp:2}],2:[function(requirecopy,module,exports){"use strict";var SDPUtils={};SDPUtils.generateIdentifier=function(){return Math.random().toString(36).substr(2,10)},SDPUtils.localCName=SDPUtils.generateIdentifier(),SDPUtils.splitLines=function(blob){return blob.trim().split("\n").map(function(line){return line.trim()})},SDPUtils.splitSections=function(blob){return blob.split("\nm=").map(function(part,index){return(index>0?"m="+part:part).trim()+"\r\n"})},SDPUtils.matchPrefix=function(blob,prefix){return SDPUtils.splitLines(blob).filter(function(line){return 0===line.indexOf(prefix)})},SDPUtils.parseCandidate=function(line){var parts;parts=0===line.indexOf("a=candidate:")?line.substring(12).split(" "):line.substring(10).split(" ");for(var candidate={foundation:parts[0],component:parseInt(parts[1],10),protocol:parts[2].toLowerCase(),priority:parseInt(parts[3],10),ip:parts[4],port:parseInt(parts[5],10),type:parts[7]},i=8;i0?parts[0].split("/")[1]:"sendrecv",uri:parts[1]}},SDPUtils.writeExtmap=function(headerExtension){return"a=extmap:"+(headerExtension.id||headerExtension.preferredId)+(headerExtension.direction&&"sendrecv"!==headerExtension.direction?"/"+headerExtension.direction:"")+" "+headerExtension.uri+"\r\n"},SDPUtils.parseFmtp=function(line){for(var kv,parsed={},parts=line.substr(line.indexOf(" ")+1).split(";"),j=0;j-1?(parts.attribute=line.substr(sp+1,colon-sp-1),parts.value=line.substr(colon+1)):parts.attribute=line.substr(sp+1),parts},SDPUtils.getMid=function(mediaSection){var mid=SDPUtils.matchPrefix(mediaSection,"a=mid:")[0];if(mid)return mid.substr(6)},SDPUtils.parseFingerprint=function(line){var parts=line.substr(14).split(" ");return{algorithm:parts[0].toLowerCase(),value:parts[1]}},SDPUtils.getDtlsParameters=function(mediaSection,sessionpart){return{role:"auto",fingerprints:SDPUtils.matchPrefix(mediaSection+sessionpart,"a=fingerprint:").map(SDPUtils.parseFingerprint)}},SDPUtils.writeDtlsParameters=function(params,setupType){var sdp="a=setup:"+setupType+"\r\n";return params.fingerprints.forEach(function(fp){sdp+="a=fingerprint:"+fp.algorithm+" "+fp.value+"\r\n"}),sdp},SDPUtils.getIceParameters=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);return lines=lines.concat(SDPUtils.splitLines(sessionpart)),{usernameFragment:lines.filter(function(line){return 0===line.indexOf("a=ice-ufrag:")})[0].substr(12),password:lines.filter(function(line){return 0===line.indexOf("a=ice-pwd:")})[0].substr(10)}},SDPUtils.writeIceParameters=function(params){return"a=ice-ufrag:"+params.usernameFragment+"\r\na=ice-pwd:"+params.password+"\r\n"},SDPUtils.parseRtpParameters=function(mediaSection){for(var description={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]},lines=SDPUtils.splitLines(mediaSection),mline=lines[0].split(" "),i=3;i0?"9":"0",sdp+=" UDP/TLS/RTP/SAVPF ",sdp+=caps.codecs.map(function(codec){return void 0!==codec.preferredPayloadType?codec.preferredPayloadType:codec.payloadType}).join(" ")+"\r\n",sdp+="c=IN IP4 0.0.0.0\r\n",sdp+="a=rtcp:9 IN IP4 0.0.0.0\r\n",caps.codecs.forEach(function(codec){sdp+=SDPUtils.writeRtpMap(codec),sdp+=SDPUtils.writeFmtp(codec),sdp+=SDPUtils.writeRtcpFb(codec)});var maxptime=0;return caps.codecs.forEach(function(codec){codec.maxptime>maxptime&&(maxptime=codec.maxptime)}),maxptime>0&&(sdp+="a=maxptime:"+maxptime+"\r\n"),sdp+="a=rtcp-mux\r\n",caps.headerExtensions.forEach(function(extension){sdp+=SDPUtils.writeExtmap(extension)}),sdp},SDPUtils.parseRtpEncodingParameters=function(mediaSection){var secondarySsrc,encodingParameters=[],description=SDPUtils.parseRtpParameters(mediaSection),hasRed=-1!==description.fecMechanisms.indexOf("RED"),hasUlpfec=-1!==description.fecMechanisms.indexOf("ULPFEC"),ssrcs=SDPUtils.matchPrefix(mediaSection,"a=ssrc:").map(function(line){return SDPUtils.parseSsrcMedia(line)}).filter(function(parts){return"cname"===parts.attribute}),primarySsrc=ssrcs.length>0&&ssrcs[0].ssrc,flows=SDPUtils.matchPrefix(mediaSection,"a=ssrc-group:FID").map(function(line){var parts=line.split(" ");return parts.shift(),parts.map(function(part){return parseInt(part,10)})});flows.length>0&&flows[0].length>1&&flows[0][0]===primarySsrc&&(secondarySsrc=flows[0][1]),description.codecs.forEach(function(codec){if("RTX"===codec.name.toUpperCase()&&codec.parameters.apt){var encParam={ssrc:primarySsrc,codecPayloadType:parseInt(codec.parameters.apt,10),rtx:{ssrc:secondarySsrc}};encodingParameters.push(encParam),hasRed&&(encParam=JSON.parse(JSON.stringify(encParam)),encParam.fec={ssrc:secondarySsrc,mechanism:hasUlpfec?"red+ulpfec":"red"},encodingParameters.push(encParam))}}),0===encodingParameters.length&&primarySsrc&&encodingParameters.push({ssrc:primarySsrc});var bandwidth=SDPUtils.matchPrefix(mediaSection,"b=");return bandwidth.length&&(bandwidth=0===bandwidth[0].indexOf("b=TIAS:")?parseInt(bandwidth[0].substr(7),10):0===bandwidth[0].indexOf("b=AS:")?1e3*parseInt(bandwidth[0].substr(5),10)*.95-16e3:void 0,encodingParameters.forEach(function(params){params.maxBitrate=bandwidth})),encodingParameters},SDPUtils.parseRtcpParameters=function(mediaSection){var rtcpParameters={},remoteSsrc=SDPUtils.matchPrefix(mediaSection,"a=ssrc:").map(function(line){return SDPUtils.parseSsrcMedia(line)}).filter(function(obj){return"cname"===obj.attribute})[0];remoteSsrc&&(rtcpParameters.cname=remoteSsrc.value,rtcpParameters.ssrc=remoteSsrc.ssrc);var rsize=SDPUtils.matchPrefix(mediaSection,"a=rtcp-rsize");rtcpParameters.reducedSize=rsize.length>0,rtcpParameters.compound=0===rsize.length;var mux=SDPUtils.matchPrefix(mediaSection,"a=rtcp-mux");return rtcpParameters.mux=mux.length>0,rtcpParameters},SDPUtils.parseMsid=function(mediaSection){var parts,spec=SDPUtils.matchPrefix(mediaSection,"a=msid:");if(1===spec.length)return parts=spec[0].substr(7).split(" "),{stream:parts[0],track:parts[1]};var planB=SDPUtils.matchPrefix(mediaSection,"a=ssrc:").map(function(line){return SDPUtils.parseSsrcMedia(line)}).filter(function(parts){return"msid"===parts.attribute});return planB.length>0?(parts=planB[0].value.split(" "),{stream:parts[0],track:parts[1]}):void 0},SDPUtils.generateSessionId=function(){return Math.random().toString().substr(2,21)},SDPUtils.writeSessionBoilerplate=function(sessId,sessVer){var version=void 0!==sessVer?sessVer:2;return"v=0\r\no=thisisadapterortc "+(sessId||SDPUtils.generateSessionId())+" "+version+" IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},SDPUtils.writeMediaSection=function(transceiver,caps,type,stream){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);if(sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters()),sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),"offer"===type?"actpass":"active"),sdp+="a=mid:"+transceiver.mid+"\r\n",transceiver.direction?sdp+="a="+transceiver.direction+"\r\n":transceiver.rtpSender&&transceiver.rtpReceiver?sdp+="a=sendrecv\r\n":transceiver.rtpSender?sdp+="a=sendonly\r\n":transceiver.rtpReceiver?sdp+="a=recvonly\r\n":sdp+="a=inactive\r\n",transceiver.rtpSender){var msid="msid:"+stream.id+" "+transceiver.rtpSender.track.id+"\r\n";sdp+="a="+msid,sdp+="a=ssrc:"+transceiver.sendEncodingParameters[0].ssrc+" "+msid,transceiver.sendEncodingParameters[0].rtx&&(sdp+="a=ssrc:"+transceiver.sendEncodingParameters[0].rtx.ssrc+" "+msid,sdp+="a=ssrc-group:FID "+transceiver.sendEncodingParameters[0].ssrc+" "+transceiver.sendEncodingParameters[0].rtx.ssrc+"\r\n")}return sdp+="a=ssrc:"+transceiver.sendEncodingParameters[0].ssrc+" cname:"+SDPUtils.localCName+"\r\n",transceiver.rtpSender&&transceiver.sendEncodingParameters[0].rtx&&(sdp+="a=ssrc:"+transceiver.sendEncodingParameters[0].rtx.ssrc+" cname:"+SDPUtils.localCName+"\r\n"),sdp},SDPUtils.getDirection=function(mediaSection,sessionpart){for(var lines=SDPUtils.splitLines(mediaSection),i=0;i0&&"function"==typeof selector)return origGetStats.apply(this,arguments);if(0===origGetStats.length&&(0===arguments.length||"function"!=typeof arguments[0]))return origGetStats.apply(this,[]);var fixChromeStats_=function(response){var standardReport={};return response.result().forEach(function(report){var standardStats={id:report.id,timestamp:report.timestamp,type:{localcandidate:"local-candidate",remotecandidate:"remote-candidate"}[report.type]||report.type};report.names().forEach(function(name){standardStats[name]=report.stat(name)}),standardReport[standardStats.id]=standardStats}),standardReport},makeMapStats=function(stats){return new Map(Object.keys(stats).map(function(key){return[key,stats[key]]}))};if(arguments.length>=2){var successCallbackWrapper_=function(response){args[1](makeMapStats(fixChromeStats_(response)))};return origGetStats.apply(this,[successCallbackWrapper_,arguments[0]])}return new Promise(function(resolve,reject){origGetStats.apply(self,[function(response){resolve(makeMapStats(fixChromeStats_(response)))},reject])}).then(successCallback,errorCallback)},browserDetails.version<51&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){var args=arguments,self=this,promise=new Promise(function(resolve,reject){nativeMethod.apply(self,[args[0],resolve,reject])});return args.length<2?promise:promise.then(function(){args[1].apply(null,[])},function(err){args.length>=3&&args[2].apply(null,[err])})}}),browserDetails.version<52&&["createOffer","createAnswer"].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){var self=this;if(arguments.length<1||1===arguments.length&&"object"==typeof arguments[0]){var opts=1===arguments.length?arguments[0]:void 0;return new Promise(function(resolve,reject){nativeMethod.apply(self,[resolve,reject,opts])})}return nativeMethod.apply(this,arguments)}}),["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){return arguments[0]=new("addIceCandidate"===method?window.RTCIceCandidate:window.RTCSessionDescription)(arguments[0]),nativeMethod.apply(this,arguments)}});var nativeAddIceCandidate=window.RTCPeerConnection.prototype.addIceCandidate;window.RTCPeerConnection.prototype.addIceCandidate=function(){return arguments[0]?nativeAddIceCandidate.apply(this,arguments):(arguments[1]&&arguments[1].apply(null),Promise.resolve())}}};module.exports={shimMediaStream:chromeShim.shimMediaStream,shimOnTrack:chromeShim.shimOnTrack,shimAddTrackRemoveTrack:chromeShim.shimAddTrackRemoveTrack,shimGetSendersWithDtmf:chromeShim.shimGetSendersWithDtmf,shimSourceObject:chromeShim.shimSourceObject,shimPeerConnection:chromeShim.shimPeerConnection,shimGetUserMedia:requirecopy("./getusermedia")}},{"../utils.js":13,"./getusermedia":6}],6:[function(requirecopy,module,exports){"use strict";var utils=requirecopy("../utils.js"),logging=utils.log;module.exports=function(window){var browserDetails=utils.detectBrowser(window),navigator=window&&window.navigator,constraintsToChrome_=function(c){if("object"!=typeof c||c.mandatory||c.optional)return c;var cc={};return Object.keys(c).forEach(function(key){if("require"!==key&&"advanced"!==key&&"mediaSource"!==key){var r="object"==typeof c[key]?c[key]:{ideal:c[key]};void 0!==r.exact&&"number"==typeof r.exact&&(r.min=r.max=r.exact);var oldname_=function(prefix,name){return prefix?prefix+name.charAt(0).toUpperCase()+name.slice(1):"deviceId"===name?"sourceId":name};if(void 0!==r.ideal){cc.optional=cc.optional||[];var oc={};"number"==typeof r.ideal?(oc[oldname_("min",key)]=r.ideal,cc.optional.push(oc),oc={},oc[oldname_("max",key)]=r.ideal,cc.optional.push(oc)):(oc[oldname_("",key)]=r.ideal,cc.optional.push(oc))}void 0!==r.exact&&"number"!=typeof r.exact?(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname_("",key)]=r.exact):["min","max"].forEach(function(mix){void 0!==r[mix]&&(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname_(mix,key)]=r[mix])})}}),c.advanced&&(cc.optional=(cc.optional||[]).concat(c.advanced)),cc},shimConstraints_=function(constraints,func){if((constraints=JSON.parse(JSON.stringify(constraints)))&&"object"==typeof constraints.audio){var remap=function(obj,a,b){a in obj&&!(b in obj)&&(obj[b]=obj[a],delete obj[a])};constraints=JSON.parse(JSON.stringify(constraints)),remap(constraints.audio,"autoGainControl","googAutoGainControl"),remap(constraints.audio,"noiseSuppression","googNoiseSuppression"),constraints.audio=constraintsToChrome_(constraints.audio)}if(constraints&&"object"==typeof constraints.video){var face=constraints.video.facingMode;face=face&&("object"==typeof face?face:{ideal:face});var getSupportedFacingModeLies=browserDetails.version<61;if(face&&("user"===face.exact||"environment"===face.exact||"user"===face.ideal||"environment"===face.ideal)&&(!navigator.mediaDevices.getSupportedConstraints||!navigator.mediaDevices.getSupportedConstraints().facingMode||getSupportedFacingModeLies)){delete constraints.video.facingMode;var matches;if("environment"===face.exact||"environment"===face.ideal?matches=["back","rear"]:"user"!==face.exact&&"user"!==face.ideal||(matches=["front"]),matches)return navigator.mediaDevices.enumerateDevices().then(function(devices){devices=devices.filter(function(d){return"videoinput"===d.kind});var dev=devices.find(function(d){return matches.some(function(match){return-1!==d.label.toLowerCase().indexOf(match)})});return!dev&&devices.length&&-1!==matches.indexOf("back")&&(dev=devices[devices.length-1]),dev&&(constraints.video.deviceId=face.exact?{exact:dev.deviceId}:{ideal:dev.deviceId}),constraints.video=constraintsToChrome_(constraints.video),logging("chrome: "+JSON.stringify(constraints)),func(constraints)})}constraints.video=constraintsToChrome_(constraints.video)}return logging("chrome: "+JSON.stringify(constraints)),func(constraints)},shimError_=function(e){return{name:{PermissionDeniedError:"NotAllowedError",InvalidStateError:"NotReadableError",DevicesNotFoundError:"NotFoundError",ConstraintNotSatisfiedError:"OverconstrainedError",TrackStartError:"NotReadableError",MediaDeviceFailedDueToShutdown:"NotReadableError",MediaDeviceKillSwitchOn:"NotReadableError"}[e.name]||e.name,message:e.message,constraint:e.constraintName,toString:function(){return this.name+(this.message&&": ")+this.message}}},getUserMedia_=function(constraints,onSuccess,onError){shimConstraints_(constraints,function(c){navigator.webkitGetUserMedia(c,onSuccess,function(e){onError&&onError(shimError_(e))})})};navigator.getUserMedia=getUserMedia_;var getUserMediaPromise_=function(constraints){return new Promise(function(resolve,reject){navigator.getUserMedia(constraints,resolve,reject)})};if(navigator.mediaDevices||(navigator.mediaDevices={getUserMedia:getUserMediaPromise_,enumerateDevices:function(){return new Promise(function(resolve){var kinds={audio:"audioinput",video:"videoinput"};return window.MediaStreamTrack.getSources(function(devices){resolve(devices.map(function(device){return{label:device.label,kind:kinds[device.kind],deviceId:device.id,groupId:""}}))})})},getSupportedConstraints:function(){return{deviceId:!0,echoCancellation:!0,facingMode:!0,frameRate:!0,height:!0,width:!0}}}),navigator.mediaDevices.getUserMedia){var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(cs){return shimConstraints_(cs,function(c){return origGetUserMedia(c).then(function(stream){if(c.audio&&!stream.getAudioTracks().length||c.video&&!stream.getVideoTracks().length)throw stream.getTracks().forEach(function(track){track.stop()}),new DOMException("","NotFoundError");return stream},function(e){return Promise.reject(shimError_(e))})})}}else navigator.mediaDevices.getUserMedia=function(constraints){return getUserMediaPromise_(constraints)};void 0===navigator.mediaDevices.addEventListener&&(navigator.mediaDevices.addEventListener=function(){logging("Dummy mediaDevices.addEventListener called.")}),void 0===navigator.mediaDevices.removeEventListener&&(navigator.mediaDevices.removeEventListener=function(){logging("Dummy mediaDevices.removeEventListener called.")})}},{"../utils.js":13}],7:[function(requirecopy,module,exports){"use strict";function wrapPeerConnectionEvent(window,eventNameToWrap,wrapper){if(window.RTCPeerConnection){var proto=window.RTCPeerConnection.prototype,nativeAddEventListener=proto.addEventListener;proto.addEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap)return nativeAddEventListener.apply(this,arguments);var wrappedCallback=function(e){cb(wrapper(e))};return this._eventMap=this._eventMap||{},this._eventMap[cb]=wrappedCallback,nativeAddEventListener.apply(this,[nativeEventName,wrappedCallback])};var nativeRemoveEventListener=proto.removeEventListener;proto.removeEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap||!this._eventMap||!this._eventMap[cb])return nativeRemoveEventListener.apply(this,arguments);var unwrappedCb=this._eventMap[cb];return delete this._eventMap[cb],nativeRemoveEventListener.apply(this,[nativeEventName,unwrappedCb])},Object.defineProperty(proto,"on"+eventNameToWrap,{get:function(){return this["_on"+eventNameToWrap]},set:function(cb){this["_on"+eventNameToWrap]&&(this.removeEventListener(eventNameToWrap,this["_on"+eventNameToWrap]),delete this["_on"+eventNameToWrap]),cb&&this.addEventListener(eventNameToWrap,this["_on"+eventNameToWrap]=cb)}})}}var SDPUtils=requirecopy("sdp");module.exports={shimRTCIceCandidate:function(window){if(!(window.RTCIceCandidate&&"foundation"in window.RTCIceCandidate.prototype)){var NativeRTCIceCandidate=window.RTCIceCandidate;window.RTCIceCandidate=function(args){"object"==typeof args&&args.candidate&&0===args.candidate.indexOf("a=")&&(args=JSON.parse(JSON.stringify(args)),args.candidate=args.candidate.substr(2));var nativeCandidate=new NativeRTCIceCandidate(args),parsedCandidate=SDPUtils.parseCandidate(args.candidate),augmentedCandidate=Object.assign(nativeCandidate,parsedCandidate);return augmentedCandidate.toJSON=function(){return{candidate:augmentedCandidate.candidate,sdpMid:augmentedCandidate.sdpMid,sdpMLineIndex:augmentedCandidate.sdpMLineIndex,usernameFragment:augmentedCandidate.usernameFragment}},augmentedCandidate},wrapPeerConnectionEvent(window,"icecandidate",function(e){return e.candidate&&Object.defineProperty(e,"candidate",{value:new window.RTCIceCandidate(e.candidate),writable:"false"}),e})}}}},{sdp:2}],8:[function(requirecopy,module,exports){"use strict";var utils=requirecopy("../utils"),shimRTCPeerConnection=requirecopy("rtcpeerconnection-shim");module.exports={shimGetUserMedia:requirecopy("./getusermedia"),shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if(window.RTCIceGatherer&&(window.RTCIceCandidate||(window.RTCIceCandidate=function(args){return args}),window.RTCSessionDescription||(window.RTCSessionDescription=function(args){return args}),browserDetails.version<15025)){var origMSTEnabled=Object.getOwnPropertyDescriptor(window.MediaStreamTrack.prototype,"enabled");Object.defineProperty(window.MediaStreamTrack.prototype,"enabled",{set:function(value){origMSTEnabled.set.call(this,value);var ev=new Event("enabled");ev.enabled=value,this.dispatchEvent(ev)}})}!window.RTCRtpSender||"dtmf"in window.RTCRtpSender.prototype||Object.defineProperty(window.RTCRtpSender.prototype,"dtmf",{get:function(){return void 0===this._dtmf&&("audio"===this.track.kind?this._dtmf=new window.RTCDtmfSender(this):"video"===this.track.kind&&(this._dtmf=null)),this._dtmf}}),window.RTCPeerConnection=shimRTCPeerConnection(window,browserDetails.version)},shimReplaceTrack:function(window){!window.RTCRtpSender||"replaceTrack"in window.RTCRtpSender.prototype||(window.RTCRtpSender.prototype.replaceTrack=window.RTCRtpSender.prototype.setTrack)}}},{"../utils":13,"./getusermedia":9,"rtcpeerconnection-shim":1}],9:[function(requirecopy,module,exports){"use strict";module.exports=function(window){var navigator=window&&window.navigator,shimError_=function(e){return{name:{PermissionDeniedError:"NotAllowedError"}[e.name]||e.name,message:e.message,constraint:e.constraint,toString:function(){return this.name}}},origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e))})}}},{}],10:[function(requirecopy,module,exports){"use strict";var utils=requirecopy("../utils"),firefoxShim={shimOnTrack:function(window){"object"!=typeof window||!window.RTCPeerConnection||"ontrack"in window.RTCPeerConnection.prototype||Object.defineProperty(window.RTCPeerConnection.prototype,"ontrack",{get:function(){return this._ontrack},set:function(f){this._ontrack&&(this.removeEventListener("track",this._ontrack),this.removeEventListener("addstream",this._ontrackpoly)),this.addEventListener("track",this._ontrack=f),this.addEventListener("addstream",this._ontrackpoly=function(e){e.stream.getTracks().forEach(function(track){var event=new Event("track");event.track=track,event.receiver={track:track},event.transceiver={receiver:event.receiver},event.streams=[e.stream],this.dispatchEvent(event)}.bind(this))}.bind(this))}}),"object"==typeof window&&window.RTCPeerConnection&&"receiver"in window.RTCTrackEvent.prototype&&!("transceiver"in window.RTCTrackEvent.prototype)&&Object.defineProperty(window.RTCTrackEvent.prototype,"transceiver",{get:function(){return{receiver:this.receiver}}})},shimSourceObject:function(window){"object"==typeof window&&(!window.HTMLMediaElement||"srcObject"in window.HTMLMediaElement.prototype||Object.defineProperty(window.HTMLMediaElement.prototype,"srcObject",{get:function(){return this.mozSrcObject},set:function(stream){this.mozSrcObject=stream}}))},shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if("object"==typeof window&&(window.RTCPeerConnection||window.mozRTCPeerConnection)){window.RTCPeerConnection||(window.RTCPeerConnection=function(pcConfig,pcConstraints){if(browserDetails.version<38&&pcConfig&&pcConfig.iceServers){for(var newIceServers=[],i=0;i55&&"autoGainControl"in navigator.mediaDevices.getSupportedConstraints())){var remap=function(obj,a,b){a in obj&&!(b in obj)&&(obj[b]=obj[a],delete obj[a])},nativeGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);if(navigator.mediaDevices.getUserMedia=function(c){return"object"==typeof c&&"object"==typeof c.audio&&(c=JSON.parse(JSON.stringify(c)),remap(c.audio,"autoGainControl","mozAutoGainControl"),remap(c.audio,"noiseSuppression","mozNoiseSuppression")),nativeGetUserMedia(c)},MediaStreamTrack&&MediaStreamTrack.prototype.getSettings){var nativeGetSettings=MediaStreamTrack.prototype.getSettings;MediaStreamTrack.prototype.getSettings=function(){var obj=nativeGetSettings.apply(this,arguments);return remap(obj,"mozAutoGainControl","autoGainControl"),remap(obj,"mozNoiseSuppression","noiseSuppression"),obj}}if(MediaStreamTrack&&MediaStreamTrack.prototype.applyConstraints){var nativeApplyConstraints=MediaStreamTrack.prototype.applyConstraints;MediaStreamTrack.prototype.applyConstraints=function(c){return"audio"===this.kind&&"object"==typeof c&&(c=JSON.parse(JSON.stringify(c)),remap(c,"autoGainControl","mozAutoGainControl"),remap(c,"noiseSuppression","mozNoiseSuppression")),nativeApplyConstraints.apply(this,[c])}}}navigator.getUserMedia=function(constraints,onSuccess,onError){if(browserDetails.version<44)return getUserMedia_(constraints,onSuccess,onError);utils.deprecated("navigator.getUserMedia","navigator.mediaDevices.getUserMedia"),navigator.mediaDevices.getUserMedia(constraints).then(onSuccess,onError)}}},{"../utils":13}],12:[function(requirecopy,module,exports){"use strict";var utils=requirecopy("../utils"),safariShim={shimLocalStreamsAPI:function(window){if("object"==typeof window&&window.RTCPeerConnection){if("getLocalStreams"in window.RTCPeerConnection.prototype||(window.RTCPeerConnection.prototype.getLocalStreams=function(){return this._localStreams||(this._localStreams=[]),this._localStreams}),"getStreamById"in window.RTCPeerConnection.prototype||(window.RTCPeerConnection.prototype.getStreamById=function(id){var result=null;return this._localStreams&&this._localStreams.forEach(function(stream){stream.id===id&&(result=stream)}),this._remoteStreams&&this._remoteStreams.forEach(function(stream){stream.id===id&&(result=stream)}),result}),!("addStream"in window.RTCPeerConnection.prototype)){var _addTrack=window.RTCPeerConnection.prototype.addTrack;window.RTCPeerConnection.prototype.addStream=function(stream){this._localStreams||(this._localStreams=[]),-1===this._localStreams.indexOf(stream)&&this._localStreams.push(stream);var self=this;stream.getTracks().forEach(function(track){_addTrack.call(self,track,stream)})},window.RTCPeerConnection.prototype.addTrack=function(track,stream){stream&&(this._localStreams?-1===this._localStreams.indexOf(stream)&&this._localStreams.push(stream):this._localStreams=[stream]),_addTrack.call(this,track,stream)}}"removeStream"in window.RTCPeerConnection.prototype||(window.RTCPeerConnection.prototype.removeStream=function(stream){this._localStreams||(this._localStreams=[]);var index=this._localStreams.indexOf(stream);if(-1!==index){this._localStreams.splice(index,1);var self=this,tracks=stream.getTracks();this.getSenders().forEach(function(sender){-1!==tracks.indexOf(sender.track)&&self.removeTrack(sender)})}})}},shimRemoteStreamsAPI:function(window){"object"==typeof window&&window.RTCPeerConnection&&("getRemoteStreams"in window.RTCPeerConnection.prototype||(window.RTCPeerConnection.prototype.getRemoteStreams=function(){return this._remoteStreams?this._remoteStreams:[]}),"onaddstream"in window.RTCPeerConnection.prototype||Object.defineProperty(window.RTCPeerConnection.prototype,"onaddstream",{get:function(){return this._onaddstream},set:function(f){this._onaddstream&&(this.removeEventListener("addstream",this._onaddstream),this.removeEventListener("track",this._onaddstreampoly)),this.addEventListener("addstream",this._onaddstream=f),this.addEventListener("track",this._onaddstreampoly=function(e){var stream=e.streams[0];if(this._remoteStreams||(this._remoteStreams=[]),!(this._remoteStreams.indexOf(stream)>=0)){this._remoteStreams.push(stream);var event=new Event("addstream");event.stream=e.streams[0],this.dispatchEvent(event)}}.bind(this))}}))},shimCallbacksAPI:function(window){if("object"==typeof window&&window.RTCPeerConnection){var prototype=window.RTCPeerConnection.prototype,createOffer=prototype.createOffer,createAnswer=prototype.createAnswer,setLocalDescription=prototype.setLocalDescription,setRemoteDescription=prototype.setRemoteDescription,addIceCandidate=prototype.addIceCandidate;prototype.createOffer=function(successCallback,failureCallback){
var options=arguments.length>=2?arguments[2]:arguments[0],promise=createOffer.apply(this,[options]);return failureCallback?(promise.then(successCallback,failureCallback),Promise.resolve()):promise},prototype.createAnswer=function(successCallback,failureCallback){var options=arguments.length>=2?arguments[2]:arguments[0],promise=createAnswer.apply(this,[options]);return failureCallback?(promise.then(successCallback,failureCallback),Promise.resolve()):promise};var withCallback=function(description,successCallback,failureCallback){var promise=setLocalDescription.apply(this,[description]);return failureCallback?(promise.then(successCallback,failureCallback),Promise.resolve()):promise};prototype.setLocalDescription=withCallback,withCallback=function(description,successCallback,failureCallback){var promise=setRemoteDescription.apply(this,[description]);return failureCallback?(promise.then(successCallback,failureCallback),Promise.resolve()):promise},prototype.setRemoteDescription=withCallback,withCallback=function(candidate,successCallback,failureCallback){var promise=addIceCandidate.apply(this,[candidate]);return failureCallback?(promise.then(successCallback,failureCallback),Promise.resolve()):promise},prototype.addIceCandidate=withCallback}},shimGetUserMedia:function(window){var navigator=window&&window.navigator;navigator.getUserMedia||(navigator.webkitGetUserMedia?navigator.getUserMedia=navigator.webkitGetUserMedia.bind(navigator):navigator.mediaDevices&&navigator.mediaDevices.getUserMedia&&(navigator.getUserMedia=function(constraints,cb,errcb){navigator.mediaDevices.getUserMedia(constraints).then(cb,errcb)}.bind(navigator)))},shimRTCIceServerUrls:function(window){var OrigPeerConnection=window.RTCPeerConnection;window.RTCPeerConnection=function(pcConfig,pcConstraints){if(pcConfig&&pcConfig.iceServers){for(var newIceServers=[],i=0;i=pos&&parseInt(match[pos],10)},detectBrowser:function(window){var navigator=window&&window.navigator,result={};if(result.browser=null,result.version=null,void 0===window||!window.navigator)return result.browser="Not a browser.",result;if(navigator.mozGetUserMedia)result.browser="firefox",result.version=this.extractVersion(navigator.userAgent,/Firefox\/(\d+)\./,1);else if(navigator.webkitGetUserMedia)if(window.webkitRTCPeerConnection)result.browser="chrome",result.version=this.extractVersion(navigator.userAgent,/Chrom(e|ium)\/(\d+)\./,2);else{if(!navigator.userAgent.match(/Version\/(\d+).(\d+)/))return result.browser="Unsupported webkit-based browser with GUM support but no WebRTC support.",result;result.browser="safari",result.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/(\d+)\./,1)}else if(navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))result.browser="edge",result.version=this.extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2);else{if(!navigator.mediaDevices||!navigator.userAgent.match(/AppleWebKit\/(\d+)\./))return result.browser="Not a supported browser.",result;result.browser="safari",result.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/(\d+)\./,1)}return result},shimCreateObjectURL:function(window){var URL=window&&window.URL;if("object"==typeof window&&window.HTMLMediaElement&&"srcObject"in window.HTMLMediaElement.prototype&&URL.createObjectURL&&URL.revokeObjectURL){var nativeCreateObjectURL=URL.createObjectURL.bind(URL),nativeRevokeObjectURL=URL.revokeObjectURL.bind(URL),streams=new Map,newId=0;URL.createObjectURL=function(stream){if("getTracks"in stream){var url="polyblob:"+ ++newId;return streams.set(url,stream),utils.deprecated("URL.createObjectURL(stream)","elem.srcObject = stream"),url}return nativeCreateObjectURL(stream)},URL.revokeObjectURL=function(url){nativeRevokeObjectURL(url),streams.delete(url)};var dsc=Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype,"src");Object.defineProperty(window.HTMLMediaElement.prototype,"src",{get:function(){return dsc.get.apply(this)},set:function(url){return this.srcObject=streams.get(url)||null,dsc.set.apply(this,[url])}});var nativeSetAttribute=window.HTMLMediaElement.prototype.setAttribute;window.HTMLMediaElement.prototype.setAttribute=function(){return 2===arguments.length&&"src"===(""+arguments[0]).toLowerCase()&&(this.srcObject=streams.get(arguments[1])||null),nativeSetAttribute.apply(this,arguments)}}}};module.exports={log:utils.log,deprecated:utils.deprecated,disableLog:utils.disableLog,disableWarnings:utils.disableWarnings,extractVersion:utils.extractVersion,shimCreateObjectURL:utils.shimCreateObjectURL,detectBrowser:utils.detectBrowser.bind(utils)}},{}]},{},[3])(3)}),navigator.mozGetUserMedia?(MediaStreamTrack.getSources=function(successCb){setTimeout(function(){successCb([{kind:"audio",id:"default",label:"",facing:""},{kind:"video",id:"default",label:"",facing:""}])},0)},attachMediaStream=function(element,stream){return element.srcObject=stream,element},reattachMediaStream=function(to,from){return to.srcObject=from.srcObject,to},createIceServer=function(url,username,password){console.warn("createIceServer is deprecated. It should be replaced with an application level implementation.");var iceServer=null,urlParts=url.split(":");if(0===urlParts[0].indexOf("stun"))iceServer={urls:[url]};else if(0===urlParts[0].indexOf("turn"))if(AdapterJS.webrtcDetectedVersion<27){var turnUrlParts=url.split("?");1!==turnUrlParts.length&&0!==turnUrlParts[1].indexOf("transport=udp")||(iceServer={urls:[turnUrlParts[0]],credential:password,username:username})}else iceServer={urls:[url],credential:password,username:username};return iceServer},createIceServers=function(urls,username,password){console.warn("createIceServers is deprecated. It should be replaced with an application level implementation.");var iceServers=[];for(i=0;i=43?element.srcObject=stream:void 0!==element.src?element.src=URL.createObjectURL(stream):console.error("Error attaching stream to element."),element},reattachMediaStream=function(to,from){return AdapterJS.webrtcDetectedVersion>=43?to.srcObject=from.srcObject:to.src=from.src,to},createIceServer=function(url,username,password){console.warn("createIceServer is deprecated. It should be replaced with an application level implementation.");var iceServer=null,urlParts=url.split(":");return 0===urlParts[0].indexOf("stun")?iceServer={url:url}:0===urlParts[0].indexOf("turn")&&(iceServer={url:url,credential:password,username:username}),iceServer},createIceServers=function(urls,username,password){console.warn("createIceServers is deprecated. It should be replaced with an application level implementation.");var iceServers=[];if(AdapterJS.webrtcDetectedVersion>=34)iceServers={urls:urls,credential:password,username:username};else for(i=0;i38?element.srcObject=stream:void 0!==element.src&&(element.src=URL.createObjectURL(stream))}),attachMediaStream=function(element,stream){return"chrome"!==AdapterJS.webrtcDetectedBrowser&&"opera"!==AdapterJS.webrtcDetectedBrowser||stream?attachMediaStream_base(element,stream):element.src="",element},reattachMediaStream_base=reattachMediaStream,reattachMediaStream=function(to,from){return reattachMediaStream_base(to,from),to},window.attachMediaStream=attachMediaStream,window.reattachMediaStream=reattachMediaStream,window.getUserMedia=function(constraints,onSuccess,onFailure){navigator.getUserMedia(constraints,onSuccess,onFailure)},AdapterJS.attachMediaStream=attachMediaStream,AdapterJS.reattachMediaStream=reattachMediaStream,AdapterJS.getUserMedia=getUserMedia,"undefined"==typeof Promise&&(requestUserMedia=null),AdapterJS.maybeThroughWebRTCReady()):("object"==typeof console&&"function"==typeof console.log||(console={}||console,console.log=function(arg){},console.info=function(arg){},console.error=function(arg){},console.dir=function(arg){},console.exception=function(arg){},console.trace=function(arg){},console.warn=function(arg){},console.count=function(arg){},console.debug=function(arg){},console.count=function(arg){},console.time=function(arg){},console.timeEnd=function(arg){},console.group=function(arg){},console.groupCollapsed=function(arg){},console.groupEnd=function(arg){}),AdapterJS.WebRTCPlugin.WaitForPluginReady=function(){for(;AdapterJS.WebRTCPlugin.pluginState!==AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY;);},AdapterJS.WebRTCPlugin.callWhenPluginReady=function(callback){if(AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY)callback();else var checkPluginReadyState=setInterval(function(){AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY&&(clearInterval(checkPluginReadyState),callback())},100)},AdapterJS.WebRTCPlugin.setLogLevel=function(logLevel){AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){AdapterJS.WebRTCPlugin.plugin.setLogLevel(logLevel)})},AdapterJS.WebRTCPlugin.injectPlugin=function(){if(("interactive"===document.readyState||"complete"===document.readyState)&&AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING){if(AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTING,"IE"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion<=10){var frag=document.createDocumentFragment();for(AdapterJS.WebRTCPlugin.plugin=document.createElement("div"),AdapterJS.WebRTCPlugin.plugin.innerHTML='";AdapterJS.WebRTCPlugin.plugin.firstChild;)frag.appendChild(AdapterJS.WebRTCPlugin.plugin.firstChild);document.body.appendChild(frag),AdapterJS.WebRTCPlugin.plugin=document.getElementById(AdapterJS.WebRTCPlugin.pluginInfo.pluginId)}else AdapterJS.WebRTCPlugin.plugin=document.createElement("object"),AdapterJS.WebRTCPlugin.plugin.id=AdapterJS.WebRTCPlugin.pluginInfo.pluginId,"IE"===AdapterJS.webrtcDetectedBrowser?(AdapterJS.WebRTCPlugin.plugin.width="1px",AdapterJS.WebRTCPlugin.plugin.height="1px"):(AdapterJS.WebRTCPlugin.plugin.width="0px",AdapterJS.WebRTCPlugin.plugin.height="0px"),AdapterJS.WebRTCPlugin.plugin.type=AdapterJS.WebRTCPlugin.pluginInfo.type,AdapterJS.WebRTCPlugin.plugin.innerHTML=' '+(AdapterJS.options.getAllCams?'':"")+'',document.body.appendChild(AdapterJS.WebRTCPlugin.plugin);AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTED}},AdapterJS.WebRTCPlugin.isPluginInstalled=function(comName,plugName,plugType,installedCb,notInstalledCb){if("IE"!==AdapterJS.webrtcDetectedBrowser){for(var pluginArray=navigator.mimeTypes,i=0;i=0)return void installedCb();notInstalledCb()}else{try{new ActiveXObject(comName+"."+plugName)}catch(e){return void notInstalledCb()}installedCb()}},AdapterJS.WebRTCPlugin.defineWebRTCInterface=function(){if(AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY)return void console.error("AdapterJS - WebRTC interface has already been defined");AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING,AdapterJS.isDefined=function(variable){return null!==variable&&void 0!==variable},createIceServer=function(url,username,password){var iceServer=null,urlParts=url.split(":");return 0===urlParts[0].indexOf("stun")?iceServer={url:url,hasCredentials:!1}:0===urlParts[0].indexOf("turn")&&(iceServer={url:url,hasCredentials:!0,credential:password,username:username}),iceServer},createIceServers=function(urls,username,password){for(var iceServers=[],i=0;i1)return iceServers&&(servers.iceServers=iceServers),AdapterJS.WebRTCPlugin.plugin.PeerConnection(servers);var mandatory=constraints&&constraints.mandatory?constraints.mandatory:null,optional=constraints&&constraints.optional?constraints.optional:null;return AdapterJS.WebRTCPlugin.plugin.PeerConnection(AdapterJS.WebRTCPlugin.pageId,iceServers,mandatory,optional)},MediaStreamTrack=function(){},MediaStreamTrack.getSources=function(callback){AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){AdapterJS.WebRTCPlugin.plugin.GetSources(callback)})};var constraintsToPlugin=function(c){if("object"!=typeof c||c.mandatory||c.optional)return c;var cc={};return Object.keys(c).forEach(function(key){if("require"!==key&&"advanced"!==key){if("string"==typeof c[key])return void(cc[key]=c[key]);var r="object"==typeof c[key]?c[key]:{ideal:c[key]};void 0!==r.exact&&"number"==typeof r.exact&&(r.min=r.max=r.exact);var oldname=function(prefix,name){return prefix?prefix+name.charAt(0).toUpperCase()+name.slice(1):"deviceId"===name?"sourceId":name};if("sourceId"===oldname("",key)&&void 0!==r.exact&&(r.ideal=r.exact,r.exact=void 0),void 0!==r.ideal){cc.optional=cc.optional||[];var oc={};"number"==typeof r.ideal?(oc[oldname("min",key)]=r.ideal,cc.optional.push(oc),oc={},oc[oldname("max",key)]=r.ideal,cc.optional.push(oc)):(oc[oldname("",key)]=r.ideal,cc.optional.push(oc))}void 0!==r.exact&&"number"!=typeof r.exact?(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname("",key)]=r.exact):["min","max"].forEach(function(mix){void 0!==r[mix]&&(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname(mix,key)]=r[mix])})}}),c.advanced&&(cc.optional=(cc.optional||[]).concat(c.advanced)),cc};getUserMedia=function(constraints,successCallback,failureCallback){var cc={};cc.audio=!!constraints.audio&&constraintsToPlugin(constraints.audio),cc.video=!!constraints.video&&constraintsToPlugin(constraints.video),AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){AdapterJS.WebRTCPlugin.plugin.getUserMedia(cc,successCallback,failureCallback)})},window.navigator.getUserMedia=getUserMedia,"undefined"!=typeof Promise&&(requestUserMedia=function(constraints){return new Promise(function(resolve,reject){try{getUserMedia(constraints,resolve,reject)}catch(error){reject(error)}})},navigator.mediaDevices={getUserMedia:requestUserMedia,enumerateDevices:function(){return new Promise(function(resolve){var kinds={audio:"audioinput",video:"videoinput"};return MediaStreamTrack.getSources(function(devices){resolve(devices.map(function(device){return{label:device.label,kind:kinds[device.kind],id:device.id,deviceId:device.id,groupId:""}}))})})}}),attachMediaStream=function(element,stream){if(element&&element.parentNode){var streamId;null===stream?streamId="":(void 0!==stream.enableSoundTracks&&stream.enableSoundTracks(!0),streamId=stream.id);var elementId=0===element.id.length?Math.random().toString(36).slice(2):element.id,nodeName=element.nodeName.toLowerCase();if("object"!==nodeName){var tag;switch(nodeName){case"audio":tag=AdapterJS.WebRTCPlugin.TAGS.AUDIO;break;case"video":tag=AdapterJS.WebRTCPlugin.TAGS.VIDEO;break;default:tag=AdapterJS.WebRTCPlugin.TAGS.NONE}var frag=document.createDocumentFragment(),temp=document.createElement("div"),classHTML="";for(element.className?classHTML='class="'+element.className+'" ':element.attributes&&element.attributes.class&&(classHTML='class="'+element.attributes.class.value+'" '),temp.innerHTML='';temp.firstChild;)frag.appendChild(temp.firstChild);var height="",width="";element.clientWidth||element.clientHeight?(width=element.clientWidth,height=element.clientHeight):(element.width||element.height)&&(width=element.width,height=element.height),element.parentNode.insertBefore(frag,element),frag=document.getElementById(elementId),frag.width=width,frag.height=height,element.parentNode.removeChild(element)}else{for(var children=element.children,i=0;i!==children.length;++i)if("streamId"===children[i].name){children[i].value=streamId;break}element.setStreamId(streamId)}var newElement=document.getElementById(elementId);return AdapterJS.forwardEventHandlers(newElement,element,Object.getPrototypeOf(element)),newElement}},reattachMediaStream=function(to,from){for(var stream=null,children=from.children,i=0;i!==children.length;++i)if("streamId"===children[i].name){AdapterJS.WebRTCPlugin.WaitForPluginReady(),stream=AdapterJS.WebRTCPlugin.plugin.getStreamWithId(AdapterJS.WebRTCPlugin.pageId,children[i].value);break}if(null!==stream)return attachMediaStream(to,stream);console.log("Could not find the stream associated with this element")},window.attachMediaStream=attachMediaStream,window.reattachMediaStream=reattachMediaStream,window.getUserMedia=getUserMedia,AdapterJS.attachMediaStream=attachMediaStream,AdapterJS.reattachMediaStream=reattachMediaStream,AdapterJS.getUserMedia=getUserMedia,AdapterJS.forwardEventHandlers=function(destElem,srcElem,prototype){var properties=Object.getOwnPropertyNames(prototype);for(var prop in properties)if(prop){var propName=properties[prop];"function"==typeof propName.slice&&"on"===propName.slice(0,2)&&"function"==typeof srcElem[propName]&&AdapterJS.addEvent(destElem,propName.slice(2),srcElem[propName])}var subPrototype=Object.getPrototypeOf(prototype);subPrototype&&AdapterJS.forwardEventHandlers(destElem,srcElem,subPrototype)},RTCIceCandidate=function(candidate){return candidate.sdpMid||(candidate.sdpMid=""),AdapterJS.WebRTCPlugin.WaitForPluginReady(),AdapterJS.WebRTCPlugin.plugin.ConstructIceCandidate(candidate.sdpMid,candidate.sdpMLineIndex,candidate.candidate)},AdapterJS.addEvent(document,"readystatechange",AdapterJS.WebRTCPlugin.injectPlugin),AdapterJS.WebRTCPlugin.injectPlugin()},AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb=AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb||function(){AdapterJS.addEvent(document,"readystatechange",AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCbPriv),AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCbPriv()},AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCbPriv=function(){if(!AdapterJS.options.hidePluginInstallPrompt){var downloadLink=AdapterJS.WebRTCPlugin.pluginInfo.downloadLink;if(downloadLink){var popupString;popupString=AdapterJS.WebRTCPlugin.pluginInfo.portalLink?'This website requires you to install the '+AdapterJS.WebRTCPlugin.pluginInfo.companyName+" WebRTC Plugin to work on this browser.":AdapterJS.TEXT.PLUGIN.REQUIRE_INSTALLATION,AdapterJS.renderNotificationBar(popupString,AdapterJS.TEXT.PLUGIN.BUTTON,function(){window.open(downloadLink,"_top");var pluginInstallInterval=setInterval(function(){"IE"!==AdapterJS.webrtcDetectedBrowser&&navigator.plugins.refresh(!1),AdapterJS.WebRTCPlugin.isPluginInstalled(AdapterJS.WebRTCPlugin.pluginInfo.prefix,AdapterJS.WebRTCPlugin.pluginInfo.plugName,AdapterJS.WebRTCPlugin.pluginInfo.type,function(){clearInterval(pluginInstallInterval),AdapterJS.WebRTCPlugin.defineWebRTCInterface()},function(){})},500)})}else AdapterJS.renderNotificationBar(AdapterJS.TEXT.PLUGIN.NOT_SUPPORTED)}},AdapterJS.WebRTCPlugin.isPluginInstalled(AdapterJS.WebRTCPlugin.pluginInfo.prefix,AdapterJS.WebRTCPlugin.pluginInfo.plugName,AdapterJS.WebRTCPlugin.pluginInfo.type,AdapterJS.WebRTCPlugin.defineWebRTCInterface,AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb)),"undefined"!=typeof exports&&(module.exports=AdapterJS),AdapterJS.TEXT.EXTENSION={REQUIRE_INSTALLATION_FF:"To enable screensharing you need to install the Skylink WebRTC tools Firefox Add-on.",REQUIRE_INSTALLATION_CHROME:"To enable screensharing you need to install the Skylink WebRTC tools Chrome Extension.",REQUIRE_REFRESH:"Please refresh this page after the Skylink WebRTC tools extension has been installed.",BUTTON_FF:"Install Now",BUTTON_CHROME:"Go to Chrome Web Store"},AdapterJS.extensionInfo=AdapterJS.extensionInfo||{chrome:{extensionId:"ljckddiekopnnjoeaiofddfhgnbdoafc",extensionLink:"https://chrome.google.com/webstore/detail/skylink-webrtc-tools/ljckddiekopnnjoeaiofddfhgnbdoafc",iframeLink:"https://cdn.temasys.com.sg/skylink/extensions/detectRTC.html"},firefox:{extensionLink:"https://addons.mozilla.org/en-US/firefox/addon/skylink-webrtc-tools/"},opera:{extensionId:null,extensionLink:null}},AdapterJS._mediaSourcePolyfillIsDefined=!1,AdapterJS._defineMediaSourcePolyfill=function(){if(!AdapterJS._mediaSourcePolyfillIsDefined){AdapterJS._mediaSourcePolyfillIsDefined=!0;var baseGetUserMedia=null,clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=obj.constructor();for(var attr in obj)obj.hasOwnProperty(attr)&&(copy[attr]=obj[attr]);return copy},checkIfConstraintsIsValid=function(constraints,successCb,failureCb){if(!constraints||"object"!=typeof constraints)throw new Error("GetUserMedia: (constraints, .., ..) argument required");if("function"!=typeof successCb)throw new Error("GetUserMedia: (.., successCb, ..) argument required");if("function"!=typeof failureCb)throw new Error("GetUserMedia: (.., .., failureCb) argument required")};if("moz"===AdapterJS.webrtcDetectedType)baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(checkIfConstraintsIsValid(constraints,successCb,failureCb),constraints.video&&"object"==typeof constraints.video&&constraints.video.hasOwnProperty("mediaSource")){var updatedConstraints=clone(constraints),mediaSourcesList=["screen","window","application","browser","camera"],useExtensionErrors=["NotAllowedError","PermissionDeniedError","SecurityError"];if(Array.isArray(updatedConstraints.video.mediaSource)){for(var i=0;i-1){updatedConstraints.video.mediaSource=updatedConstraints.video.mediaSource[i];break}i++}updatedConstraints.video.mediaSource="string"==typeof updatedConstraints.video.mediaSource?updatedConstraints.video.mediaSource:null}if(-1===mediaSourcesList.indexOf(updatedConstraints.video.mediaSource))return void failureCb(new Error('GetUserMedia: Only "screen" and "window" are supported as mediaSource constraints'));var checkIfReady=setInterval(function(){"complete"===document.readyState&&(clearInterval(checkIfReady),updatedConstraints.video.mozMediaSource=updatedConstraints.video.mediaSource,baseGetUserMedia(updatedConstraints,successCb,function(error){useExtensionErrors.indexOf(error.name)>-1&&AdapterJS.webrtcDetectedVersion<52&&"https:"===window.parent.location.protocol?AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_FF,AdapterJS.TEXT.EXTENSION.BUTTON_FF,function(e){window.open(AdapterJS.extensionInfo.firefox.extensionLink,"_blank"),e.target&&e.target.parentElement&&e.target.nextElementSibling&&e.target.nextElementSibling.click&&e.target.nextElementSibling.click(),AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION?AdapterJS.TEXT.EXTENSION.REQUIRE_REFRESH:AdapterJS.TEXT.REFRESH.REQUIRE_REFRESH,AdapterJS.TEXT.REFRESH.BUTTON,function(){window.open("javascript:location.reload()","_top")})}):failureCb(error)}))},1)}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=window.getUserMedia=navigator.getUserMedia;else if("webkit"===AdapterJS.webrtcDetectedType){baseGetUserMedia=window.navigator.getUserMedia;var iframe=document.createElement("iframe");if(navigator.getUserMedia=function(constraints,successCb,failureCb){if(checkIfConstraintsIsValid(constraints,successCb,failureCb),constraints.video&&"object"==typeof constraints.video&&constraints.video.hasOwnProperty("mediaSource")){var updatedConstraints=clone(constraints),mediaSourcesList=["window","screen","tab","audio"];if(navigator.userAgent.toLowerCase().indexOf("android")>-1)return void((Array.isArray(updatedConstraints.video.mediaSource)?updatedConstraints.video.mediaSource.indexOf("screen")>-1:"screen"===updatedConstraints.video.mediaSource)?(updatedConstraints.video.mandatory=updatedConstraints.video.mandatory||{},updatedConstraints.video.mandatory.chromeMediaSource="screen",updatedConstraints.video.mandatory.maxHeight=window.screen.height,updatedConstraints.video.mandatory.maxWidth=window.screen.width,delete updatedConstraints.video.mediaSource,baseGetUserMedia(updatedConstraints,successCb,failureCb)):failureCb(new Error('GetUserMedia: Only "screen" are supported as mediaSource constraints for Android')));if(!("opera"===AdapterJS.webrtcDetectedBrowser?!!AdapterJS.extensionInfo.opera.extensionId:"chrome"===AdapterJS.webrtcDetectedBrowser))return void failureCb(new Error("Current browser does not support screensharing"));if("string"==typeof updatedConstraints.video.mediaSource&&mediaSourcesList.indexOf(updatedConstraints.video.mediaSource)>-1&&"audio"!==updatedConstraints.video.mediaSource)updatedConstraints.video.mediaSource=[updatedConstraints.video.mediaSource];else if(Array.isArray(updatedConstraints.video.mediaSource)){for(var i=0,outputMediaSource=[];i-1&&-1===updatedConstraints.video.mediaSource.indexOf("tab"))return void failureCb(new Error('GetUserMedia: "audio" mediaSource must be provided with ["audio", "tab"]'));if(0===updatedConstraints.video.mediaSource.length)return void failureCb(new Error('GetUserMedia: Only "screen", "window", "tab" are supported as mediaSource constraints'));updatedConstraints.video.mediaSource.indexOf("tab")>-1&&updatedConstraints.video.mediaSource.indexOf("audio")>-1&&!updatedConstraints.audio&&console.warn('Audio must be requested if "tab" and "audio" mediaSource constraints is requested');var fetchStream=function(response){response.success?(updatedConstraints.video.mandatory=updatedConstraints.video.mandatory||{},updatedConstraints.video.mandatory.chromeMediaSource="desktop",updatedConstraints.video.mandatory.maxWidth=window.screen.width>1920?window.screen.width:1920,updatedConstraints.video.mandatory.maxHeight=window.screen.height>1080?window.screen.height:1080,
-updatedConstraints.video.mandatory.chromeMediaSourceId=response.sourceId,Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("tab")>-1&&updatedConstraints.video.mediaSource.indexOf("audio")>-1&&updatedConstraints.audio&&(updatedConstraints.audio="object"==typeof updatedConstraints.audio?updatedConstraints.audio:{},updatedConstraints.audio.mandatory=updatedConstraints.audio.mandatory||{},updatedConstraints.audio.mandatory.chromeMediaSource="desktop",updatedConstraints.audio.mandatory.chromeMediaSourceId=response.sourceId),delete updatedConstraints.video.mediaSource,baseGetUserMedia(updatedConstraints,successCb,failureCb)):(response.extensionLink&&AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_CHROME,AdapterJS.TEXT.EXTENSION.BUTTON_CHROME,function(e){window.open(response.extensionLink,"_blank"),e.target&&e.target.parentElement&&e.target.nextElementSibling&&e.target.nextElementSibling.click&&e.target.nextElementSibling.click(),AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION?AdapterJS.TEXT.EXTENSION.REQUIRE_REFRESH:AdapterJS.TEXT.REFRESH.REQUIRE_REFRESH,AdapterJS.TEXT.REFRESH.BUTTON,function(){window.open("javascript:location.reload()","_top")})}),failureCb(response.error))};if(AdapterJS.extensionInfo.chrome.iframeLink&&"opera"!==AdapterJS.webrtcDetectedBrowser)iframe.getSourceId(updatedConstraints.video.mediaSource,fetchStream);else{var extensionId=AdapterJS.extensionInfo["opera"===AdapterJS.webrtcDetectedBrowser?"opera":"chrome"].extensionId,extensionLink=AdapterJS.extensionInfo["opera"===AdapterJS.webrtcDetectedBrowser?"opera":"chrome"].extensionLink,icon=document.createElement("img");icon.src="chrome-extension://"+extensionId+"/icon.png",icon.onload=function(){chrome.runtime.sendMessage(extensionId,{type:"get-version"},function(versionRes){if(!versionRes||"object"!=typeof versionRes||"send-version"!==versionRes.type)return void fetchStream({success:!1,error:new Error("Extension is disabled")});chrome.runtime.sendMessage(extensionId,{type:"get-source",sources:updatedConstraints.video.mediaSource},function(sourceRes){fetchStream(sourceRes&&"object"==typeof sourceRes?"send-source-error"===sourceRes.type?{success:!1,error:new Error("Permission denied for screen retrieval")}:{success:!0,sourceId:sourceRes.sourceId}:{success:!1,error:new Error("Retrieval failed")})})})},icon.onerror=function(){fetchStream({success:!1,error:new Error("Extension not installed"),extensionLink:extensionLink})}}}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=window.getUserMedia=navigator.getUserMedia,navigator.mediaDevices.getUserMedia=function(constraints){return new Promise(function(resolve,reject){try{window.getUserMedia(constraints,resolve,reject)}catch(error){reject(error)}})},"chrome"===AdapterJS.webrtcDetectedBrowser){var states={loaded:!1,error:!1};if(iframe)try{(document.body||document.documentElement).removeChild(iframe)}catch(e){}if(!AdapterJS.extensionInfo.chrome.iframeLink)return;iframe.onload=function(){states.loaded=!0},iframe.onerror=function(){states.error=!0},iframe.src=AdapterJS.extensionInfo.chrome.iframeLink,iframe.style.display="none";var getSourceIdFromIFrame=function(sources,cb){window.addEventListener("message",function iframeListener(evt){window.removeEventListener("message",iframeListener),cb(evt.data?"not-installed"===evt.data.chromeExtensionStatus?{success:!1,error:new Error("Extension is not installed"),extensionLink:evt.data.data||AdapterJS.extensionInfo.chrome.extensionLink}:"installed-disabled"===evt.data.chromeExtensionStatus?{success:!1,error:new Error("Extension is disabled")}:"PermissionDeniedError"===evt.data.chromeMediaSourceId?{success:!1,error:new Error("Permission denied for screen retrieval")}:evt.data.chromeMediaSourceId&&"string"==typeof evt.data.chromeMediaSourceId?{success:!0,sourceId:evt.data.chromeMediaSourceId}:{success:!1,error:new Error("Failed retrieving selected screen")}:{success:!1,error:new Error("Failed retrieving response")})}),iframe.contentWindow.postMessage({captureSourceId:!0,sources:sources,legacy:!0,extensionId:AdapterJS.extensionInfo.chrome.extensionId,extensionLink:AdapterJS.extensionInfo.chrome.extensionLink},"*")};iframe.getSourceId=function(sources,cb){if(states.error)return void cb({success:!1,error:new Error("iframe is not loaded")});if(states.loaded)getSourceIdFromIFrame(sources,cb);else var endBlocks=0,intervalChecker=setInterval(function(){states.loaded?(clearInterval(intervalChecker),getSourceIdFromIFrame(sources,cb)):50===endBlocks?(clearInterval(intervalChecker),cb({success:!1,error:new Error("iframe failed to load")})):endBlocks++},100)},(document.body||document.documentElement).appendChild(iframe)}}else"edge"===AdapterJS.webrtcDetectedBrowser?console.warn("Edge does not support screensharing feature in getUserMedia"):"AppleWebKit"===AdapterJS.webrtcDetectedType?console.warn("Safari does not support screensharing feature in getUserMedia"):"plugin"===AdapterJS.webrtcDetectedType&&(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(checkIfConstraintsIsValid(constraints,successCb,failureCb),constraints.video&&"object"==typeof constraints.video&&constraints.video.hasOwnProperty("mediaSource")){var updatedConstraints=clone(constraints);AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){if(!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature||!AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable)return void failureCb(new Error("Your version of the WebRTC plugin does not support screensharing"));if(AdapterJS.WebRTCPlugin.plugin.screensharingKeys)if(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("screen")>-1&&updatedConstraints.video.mediaSource.indexOf("window")>-1||updatedConstraints.video.mediaSource===AdapterJS.WebRTCPlugin.plugin.screensharingKey||updatedConstraints.video.mediaSource===AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screenOrWindow)updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screenOrWindow;else if(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("screen")>-1||"screen"===updatedConstraints.video.mediaSource)updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screen;else{if(!(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("window")>-1||"window"===updatedConstraints.video.mediaSource))return void failureCb(new Error('GetUserMedia: Only "screen", "window", ["screen", "window"] are supported as mediaSource constraints'));updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.window}updatedConstraints.video.optional=updatedConstraints.video.optional||[],updatedConstraints.video.optional.push({sourceId:updatedConstraints.video.mediaSource}),baseGetUserMedia(updatedConstraints,successCb,failureCb)})}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=getUserMedia=window.getUserMedia=navigator.getUserMedia,navigator.mediaDevices&&"undefined"!=typeof Promise&&(navigator.mediaDevices.getUserMedia=requestUserMedia))}},"function"!=typeof window.require&&AdapterJS._defineMediaSourcePolyfill(),function(globals){"use strict";function Skylink(){this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._peerInformations={},this._user=null,this._userData="",this._peerPriorityWeight=0,this._autoIntroduce=!0,this._isPrivileged=!1,this._peerList=null,this._selectedRoom=null,this._roomLocked=!1,this._inRoom=!1,this._EVENTS={},this._onceEvents={},this._timestamp={socketMessage:null,shareScreen:null,refreshConnection:null,getUserMedia:null,lastRestart:null},this._socketSession={},this._socketMessageQueue=[],this._socketMessageTimeout=null,this._socketPorts={"http:":[80,3e3],"https:":[443,3443]},this._channelOpen=!1,this._signalingServer=null,this._signalingServerProtocol=window.location.protocol,this._signalingServerPort=null,this._socket=null,this._socketUseXDR=!1,this._enableIceRestart=!1,this._hasMCU=!1,this._path=null,this._readyState=null,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._streams={userMedia:null,screenshare:null},this._streamsDefaultSettings={userMedia:{audio:{stereo:!1},video:{resolution:{width:640,height:480},frameRate:50}},screenshare:{video:!0}},this._streamsMutedSettings={audioMuted:!1,videoMuted:!1},this._streamsBandwidthSettings={googleX:{},bAS:{}},this._streamsStoppedCbs={},this._streamsSession={},this._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},this._publishOnly=!1,this._parentId=null,this._recordings={},this._currentRecordingId=!1,this._recordingStartInterval=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType=this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._bandwidthAdjuster=null,this._peerConnStatus={},this._joinRoomManager={timestamp:0,socketsFn:[]},this._initOptions={}}!function(){Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,r=!{toString:null}.propertyIsEnumerable("toString"),e=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],o=e.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var c=[];for(var l in n)t.call(n,l)&&c.push(l);if(r)for(var p=0;o>p;p++)t.call(n,e[p])&&c.push(e[p]);return c}}())}(),function(){function t(t){return 10>t?"0"+t:t}Date.prototype.toISOString=function(){return this.getUTCFullYear()+"-"+t(this.getUTCMonth()+1)+"-"+t(this.getUTCDate())+"T"+t(this.getUTCHours())+":"+t(this.getUTCMinutes())+":"+t(this.getUTCSeconds())+"."+(this.getUTCMilliseconds()/1e3).toFixed(3).slice(2,5)+"Z"}}(),function(){"function"!=typeof Date.now&&(Date.now=function(){return(new Date).getTime()})}(),function(e,t){function n(e){var n=t[e];t[e]=function(e){return o(n(e))}}function a(t,n,a){return(a=this).attachEvent("on"+t,function(t){var t=t||e.event;t.preventDefault=t.preventDefault||function(){t.returnValue=!1},t.stopPropagation=t.stopPropagation||function(){t.cancelBubble=!0},n.call(a,t)})}function o(e,t){if(t=e.length)for(;t--;)e[t].addEventListener=a;else e.addEventListener=a;return e}e.addEventListener||(o([t,e]),"Element"in e?e.Element.prototype.addEventListener=a:(t.attachEvent("onreadystatechange",function(){o(t.all)}),n("getElementsByTagName"),n("getElementById"),n("createElement"),o(t.all)))}(window,document),function(){if("performance"in window==0&&(window.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in window.performance==0){var a=Date.now();performance.timing&&performance.timing.navigationStart&&(a=performance.timing.navigationStart),window.performance.now=function(){return Date.now()-a}}}(),window.BlobBuilder=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,Array.prototype.forEach||(Array.prototype.forEach=function(callback){var T,k;if(null==this)throw new TypeError("this is null or not defined");var O=Object(this),len=O.length>>>0;if("function"!=typeof callback)throw new TypeError(callback+" is not a function");for(arguments.length>1&&(T=arguments[1]),k=0;k"],error),void self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CREATE_ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))}self._dataChannels[peerId]?self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel.label===channelName&&(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING):(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING,self._dataChannels[peerId]={},log.debug([peerId,"RTCDataChannel",channelProp,"initializing main DataChannel"])),dataChannel.onerror=function(evt){var channelError=evt.error||evt;log.error([peerId,"RTCDataChannel",channelProp,"Datachannel has an exception ->"],channelError),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,channelError,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onbufferedamountlow=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel buffering data transfer low"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.BUFFERED_AMOUNT_LOW,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onmessage=function(event){self._processDataChannelData(event.data,peerId,channelName,channelType)};var onOpenHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has opened"]),dataChannel.bufferedAmountLowThreshold=bufferThreshold||0,self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.OPEN,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))};dataChannel.readyState===self.DATA_CHANNEL_STATE.OPEN?setTimeout(onOpenHandlerFn,1):(self._trigger("dataChannelState",dataChannel.readyState,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),dataChannel.onopen=onOpenHandlerFn);var onCloseHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has closed"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSED,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),self._peerConnections[peerId]&&self._peerConnections[peerId].remoteDescription&&self._peerConnections[peerId].remoteDescription.sdp&&(-1===self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")||self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application 0")>0)||channelType===self.DATA_CHANNEL_TYPE.MESSAGING&&setTimeout(function(){self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[peerId].localDescription&&self._peerConnections[peerId].localDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&(log.debug([peerId,"RTCDataChannel",channelProp,"Reviving Datachannel connection"]),self._createDataChannel(peerId,channelName,bufferThreshold,!0))},100)};if("firefox"===AdapterJS.webrtcDetectedBrowser){var hasTriggeredClose=!1,timeBlockAfterClosing=0;dataChannel.onclose=function(){hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())};var onFFClosed=setInterval(function(){dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSED||hasTriggeredClose||5===timeBlockAfterClosing?(clearInterval(onFFClosed),hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())):dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSING&&timeBlockAfterClosing++},1e3)}else dataChannel.onclose=onCloseHandlerFn;channelType===self.DATA_CHANNEL_TYPE.MESSAGING?self._dataChannels[peerId].main={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}:self._dataChannels[peerId][channelName]={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}},Skylink.prototype._getDataChannelBuffer=function(peerId,channelProp){if("object"==typeof peerId)return{bufferedAmountLow:"number"==typeof peerId.bufferedAmountLow?peerId.bufferedAmountLow:parseInt(peerId.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?peerId.bufferedAmountLowThreshold:parseInt(peerId.bufferedAmountLowThreshold,10)||0};if(!(this._dataChannels[peerId]&&this._dataChannels[peerId][channelProp]&&this._dataChannels[peerId][channelProp].channel))return{bufferedAmountLow:0,bufferedAmountLowThreshold:0};var channel=this._dataChannels[peerId][channelProp].channel;return{bufferedAmountLow:"number"==typeof channel.bufferedAmountLow?channel.bufferedAmountLow:parseInt(channel.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof channel.bufferedAmountLowThreshold?channel.bufferedAmountLowThreshold:parseInt(channel.bufferedAmountLowThreshold,10)||0}},Skylink.prototype._sendMessageToDataChannel=function(peerId,data,channelProp,doNotConvert){var self=this;if(channelProp&&channelProp!==peerId||(channelProp="main"),!("object"==typeof data&&data||data&&"string"==typeof data))return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping invalid data ->"],data);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Peer connection does not exists or is closed ->"],data);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Datachannel connection does not exists ->"],data);var channelName=self._dataChannels[peerId][channelProp].channelName,channelType=self._dataChannels[peerId][channelProp].channelType,readyState=self._dataChannels[peerId][channelProp].channel.readyState,messageType="object"==typeof data&&data.type===self._DC_PROTOCOL_TYPE.MESSAGE?self.DATA_CHANNEL_MESSAGE_ERROR.MESSAGE:self.DATA_CHANNEL_MESSAGE_ERROR.TRANSFER;if(readyState!==self.DATA_CHANNEL_STATE.OPEN){var notOpenError='Failed sending message as Datachannel connection state is not opened. Current readyState is "'+readyState+'"';throw log.error([peerId,"RTCDataChannel",channelProp,notOpenError+" ->"],data),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,new Error(notOpenError),channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),new Error(notOpenError)}try{doNotConvert||"object"!=typeof data?(log.debug([peerId,"RTCDataChannel",channelProp,"Sending data with size ->"],data.size||data.length||data.byteLength),self._dataChannels[peerId][channelProp].channel.send(data)):(log.debug([peerId,"RTCDataChannel",channelProp,'Sending "'+data.type+'" protocol message ->'],data),self._dataChannels[peerId][channelProp].channel.send(JSON.stringify(data)))}catch(error){throw log.error([peerId,"RTCDataChannel",channelProp,"Failed sending "+(doNotConvert||"object"!=typeof data?"data":'"'+data.type+'" protocol message')+" ->"],error),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,error,channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),error}},Skylink.prototype._closeDataChannel=function(peerId,channelProp){var self=this;if(!self._dataChannels[peerId])return void log.warn([peerId,"RTCDataChannel",channelProp||null,"Aborting closing Datachannels as Peer connection does not have Datachannel sessions"]);var closeFn=function(rChannelProp){var channelName=self._dataChannels[peerId][rChannelProp].channelName,channelType=self._dataChannels[peerId][rChannelProp].channelType;self._dataChannels[peerId][rChannelProp].readyState!==self.DATA_CHANNEL_STATE.CLOSED&&(log.debug([peerId,"RTCDataChannel",channelProp,"Closing Datachannel"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSING,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(peerId,rChannelProp)),self._dataChannels[peerId][rChannelProp].channel.close(),delete self._dataChannels[peerId][rChannelProp])};if(channelProp&&"main"!==channelProp){if(!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Aborting closing Datachannel as it does not exists"]);closeFn(channelProp)}else for(var channelNameProp in self._dataChannels)self._dataChannels[peerId].hasOwnProperty(channelNameProp)&&self._dataChannels[peerId][channelNameProp]&&closeFn(channelNameProp)},Skylink.prototype._base64ToBlob=function(dataURL){for(var byteString=atob(dataURL),ab=new ArrayBuffer(byteString.length),ia=new Uint8Array(ab),j=0;jchunkSize){for(;blobByteSize-1>endCount;)endCount=startCount+chunkSize,chunksArray.push(blob.slice(startCount,endCount)),startCount+=chunkSize;blobByteSize-(startCount+1)>0&&chunksArray.push(blob.slice(startCount,blobByteSize-1))}else chunksArray.push(blob);return chunksArray},Skylink.prototype._chunkDataURL=function(dataURL,chunkSize){var outputStr=dataURL,dataURLArray=[],startCount=0,endCount=0,dataByteSize=dataURL.size||dataURL.length;if(dataByteSize>chunkSize){for(;dataByteSize-1>endCount;)endCount=startCount+chunkSize,dataURLArray.push(outputStr.slice(startCount,endCount)),startCount+=chunkSize;dataByteSize-(startCount+1)>0&&chunksArray.push(outputStr.slice(startCount,dataByteSize-1))}else dataURLArray.push(outputStr);return dataURLArray},Skylink.prototype.sendBlobData=function(data,timeout,targetPeerId,sendChunksAsBinary,callback){this._startDataTransfer(data,timeout,targetPeerId,sendChunksAsBinary,callback,"blob")},Skylink.prototype.sendURLData=function(data,timeout,targetPeerId,callback){this._startDataTransfer(data,timeout,targetPeerId,callback,null,"data")},Skylink.prototype.respondBlobRequest=Skylink.prototype.acceptDataTransfer=function(peerId,transferId,accept){var self=this;if("string"!=typeof transferId&&"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as data transfer ID or peer ID is not provided"]);if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as Peer does not have any Datachannel connections"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as invalid transfer ID is provided"]);var channelProp="main",dataChannelStateCbFn=null;self._dataChannels[peerId][transferId]&&(channelProp=transferId),self.once("dataTransferState",function(){dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),delete self._dataTransfers[transferId],self._dataChannels[peerId]&&("main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),channelProp===transferId&&self._closeDataChannel(peerId,transferId))},function(state,evtTransferId,evtPeerId){return evtTransferId===transferId&&evtPeerId===peerId&&[self.DATA_TRANSFER_STATE.ERROR,self.DATA_TRANSFER_STATE.CANCEL,self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED,self.DATA_TRANSFER_STATE.USER_REJECTED].indexOf(state)>-1}),accept?(log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]),dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){log.error([peerId,"RTCDataChannel",channelProp,'Data transfer "'+transferId+'" has been terminated due to connection.']),
-self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD,message:new Error("Data transfer terminated as Peer Datachannel connection closed abruptly.")})},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_STATE.MESSAGING:channelName===transferId)&&[self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED,self.DATA_CHANNEL_STATE.ERROR].indexOf(state)>-1:void self.off("dataChannelState",dataChannelStateCbFn)}),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:0},channelProp),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_STARTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)):(log.warn([peerId,"RTCDataChannel",transferId,"Rejected data transfer and data transfer request has been aborted"]),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:-1},channelProp),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_REJECTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as User has rejected data transfer request."),transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD}))},Skylink.prototype.cancelBlobTransfer=Skylink.prototype.cancelDataTransfer=function(peerId,transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer ID is not provided"]);if(!peerId||"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as peer ID is not provided"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer session does not exists."]);log.debug([peerId,"RTCDataChannel",transferId,"Canceling data transfer ..."]);var emitEventFn=function(peers,transferInfoPeerId){for(var i=0;i0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},"main"),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},transferId),emitEventFn(Object.keys(self._dataTransfers[transferId].peers.main).concat(Object.keys(self._dataTransfers[transferId].peers[transferId])))}else{var channelProp="main";if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as Peer does not have any Datachannel connections"]);self._dataChannels[peerId][transferId]&&(channelProp=transferId),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},channelProp),emitEventFn([peerId],peerId)}},Skylink.prototype.sendP2PMessage=function(message,targetPeerId){var listOfPeers=Object.keys(this._dataChannels),isPrivate=!1;if(Array.isArray(targetPeerId)?(listOfPeers=targetPeerId,isPrivate=!0):targetPeerId&&"string"==typeof targetPeerId&&(listOfPeers=[targetPeerId],isPrivate=!0),!this._inRoom||!this._user||!this._user.sid)return void log.error("Unable to send message as User is not in Room. ->",message);if(!this._initOptions.enableDataChannel)return void log.error("Unable to send message as User does not have Datachannel enabled. ->",message);for(var i=0;i-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeStreamingFn=function(error){log.error(error)};if(!this._inRoom||!this._user||!this._user.sid)return emitErrorBeforeStreamingFn("Unable to start data streaming as User is not in Room.");if(!this._initOptions.enableDataChannel)return emitErrorBeforeStreamingFn("Unable to start data streaming as User does not have Datachannel enabled.");if(0===listOfPeers.length)return emitErrorBeforeStreamingFn("Unable to start data streaming as there are no Peers to start session with.");if(self._hasMCU)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature is current not supported by MCU yet.");if(!self._initOptions.enableSimultaneousTransfers)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature requires simultaneous data transfers to be enabled");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},listenToPeerFn=function(peerId,channelProp){var hasStarted=!1;sessions[peerId]=channelProp,self.once("dataStreamState",function(){},function(state,evtTransferId,evtPeerId,evtSessionInfo){if(evtTransferId===transferId&&evtPeerId===peerId){evtSessionInfo.chunk;return delete clone(evtSessionInfo).chunk,state===self.DATA_STREAM_STATE.SENDING_STARTED?void(hasStarted=!0):hasStarted&&[self.DATA_STREAM_STATE.ERROR,self.DATA_STREAM_STATE.SENDING_STOPPED].indexOf(state)>-1?(channelProp===transferId&&self._closeDataChannel(peerId,transferId),self._dataStreams[transferId]&&self._dataStreams[transferId].sessions[peerId]&&(delete self._dataStreams[transferId].sessions[peerId],0===Object.keys(self._dataStreams[transferId].sessions).length&&delete self._dataStreams[transferId]),!0):void 0}})},i=0;i-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE)};if(peersNonInterop.length>0)if(self._hasMCU)waitForChannelOpenFn("MCU",peersNonInterop);else for(var pni=0;pni0)if(self._hasMCU)startDataSessionFn("MCU","main",peersInterop);else for(var pi=0;piself._CHUNK_DATAURL_SIZE:updatedDataChunk.length>self._BINARY_FILE_SIZE)return void log.error("Failed streaming data chunk as data chunk exceeds maximum chunk limit.");var sessionInfo={chunk:updatedDataChunk,chunkSize:updatedDataChunk.size||updatedDataChunk.length||updatedDataChunk.byteLength,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){var onSendDataFn=function(buffer){self._sendMessageToDataChannel(peerId,buffer,channelProp,!0);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype.stopStreamingData=function(transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error("Failed streaming data chunk as stream session ID is not provided.");if(!(self._inRoom&&self._user&&self._user.sid))return void log.error("Failed streaming data chunk as User is not in the Room.");if(!self._dataStreams[transferId])return void log.error("Failed stopping data streaming session as it does not exists.");if(!self._dataStreams[transferId].isUpload)return void log.error("Failed stopping data streaming session as it is not sending.");if(self._hasMCU)return void log.error("Failed stopping data streaming session as MCU does not support this feature yet.");var sessionInfo={chunk:null,chunkSize:0,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:transferId,size:0,originalSize:0,dataType:"fastBinaryStop",mimeType:null,chunkType:self._dataStreams[transferId].sessionChunkType,chunkSize:0,timeout:0,isPrivate:self._dataStreams[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype._startDataTransfer=function(data,timeout,targetPeerId,sendChunksAsBinary,callback,sessionType){var self=this,transferId=(self._user?self._user.sid:"")+"_"+(new Date).getTime(),transferErrors={},transferCompleted=[],chunks=[],listOfPeers=Object.keys(self._peerConnections),sessionChunkType="string",transferInfo={name:null,size:null,chunkSize:null,chunkType:null,dataType:null,mimeType:null,direction:self.DATA_TRANSFER_TYPE.UPLOAD,timeout:60,isPrivate:!1,percentage:0};"number"==typeof timeout?transferInfo.timeout=timeout:Array.isArray(timeout)?listOfPeers=timeout:timeout&&"string"==typeof timeout?listOfPeers=[timeout]:timeout&&"boolean"==typeof timeout?sessionChunkType="binary":"function"==typeof timeout&&(callback=timeout),Array.isArray(targetPeerId)?listOfPeers=targetPeerId:targetPeerId&&"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:targetPeerId&&"boolean"==typeof targetPeerId?sessionChunkType="binary":"function"==typeof targetPeerId&&(callback=targetPeerId),sendChunksAsBinary&&"boolean"==typeof sendChunksAsBinary?sessionChunkType="binary":"function"==typeof sendChunksAsBinary&&(callback=sendChunksAsBinary),listOfPeers.indexOf("MCU")>-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeDataTransferFn=function(error){if(log.error(error),"function"==typeof callback){var transferErrors={};if(0===listOfPeers.length)transferErrors.self=new Error(error);else for(var i=0;i0){var bsChunkSize="firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_CHUNK_FILE_SIZE:self._CHUNK_FILE_SIZE,bsChunks=self._chunkBlobData(new Blob(chunks),bsChunkSize);self._dataTransfers[transferId].enforceBSInfo={chunkSize:4*Math.ceil(bsChunkSize/3),chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,size:4*Math.ceil(transferInfo.originalSize/3),chunks:bsChunks}}}for(var completeFn=function(peerId,error){transferCompleted.indexOf(peerId)>-1||(log.debug([peerId,"RTCDataChannel",transferId,"Data transfer result. Is errors present? ->"],error),transferCompleted.push(peerId),error&&(transferErrors[peerId]=new Error(error)),listOfPeers.length===transferCompleted.length&&(log.log([null,"RTCDataChannel",transferId,"Data transfer request completed"]),"function"==typeof callback&&(Object.keys(transferErrors).length>0?callback({transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),transferErrors:transferErrors,listOfPeers:listOfPeers},null):callback(null,{transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),listOfPeers:listOfPeers}))))},i=0;i0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,"main",Object.keys(self._dataTransfers[transferId].peers.main)),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,transferId,Object.keys(self._dataTransfers[transferId].peers[transferId])))},Skylink.prototype._startDataTransferToPeer=function(transferId,peerId,callback,channelProp,targetPeers){var self=this,peerConnectionStateCbFn=null,dataChannelStateCbFn=null,emitEventFn=function(cb){for(var peers=targetPeers||[peerId],i=0;i-1&&(log.warn([peerId,"RTCDataChannel",transferId,"Binary data chunks transfer is not yet supported with Peer connecting from Android, iOS and C++ SDK. Fallbacking to binary string data chunks transfer."]),size=self._dataTransfers[transferId].enforceBSInfo.size,chunkSize=self._dataTransfers[transferId].enforceBSInfo.chunkSize,chunkType="string"),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:self._dataTransfers[transferId].name,size:size,originalSize:self._dataTransfers[transferId].originalSize,dataType:self._dataTransfers[transferId].sessionType,mimeType:self._dataTransfers[transferId].mimeType,chunkType:chunkType,chunkSize:chunkSize,timeout:self._dataTransfers[transferId].timeout,isPrivate:self._dataTransfers[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp),emitEventFn(function(evtPeerId){self._trigger("incomingDataRequest",transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_UPLOAD_REQUEST,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)})};if("MCU"!==peerId){var dataTransferStateCbFn=function(state,evtTransferId,evtPeerId,transferInfo,error){peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],callback(peerId,state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?null:error.message.message||error.message.toString()),delete self._dataTransfers[transferId].sessions[peerId],self._hasMCU&&0===Object.keys(self._dataTransfers[transferId].peers.main).length&&self._dataChannels.MCU&&self._dataChannels.MCU.main?self._dataChannels.MCU.main.transferId=null:"main"===channelProp&&self._dataChannels[peerId]&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),0===Object.keys(self._dataTransfers[transferId].sessions).length&&delete self._dataTransfers[transferId]};self.once("dataTransferState",dataTransferStateCbFn,function(state,evtTransferId,evtPeerId){return self._dataTransfers[transferId]&&(self._hasMCU?self._dataTransfers[transferId].peers.main[peerId]||self._dataTransfers[transferId].peers[transferId][peerId]:self._dataTransfers[transferId].sessions[peerId])?evtTransferId===transferId&&evtPeerId===peerId&&[self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,self.DATA_TRANSFER_STATE.ERROR,self.DATA_TRANSFER_STATE.CANCEL,self.DATA_TRANSFER_STATE.REJECTED].indexOf(state)>-1:(dataTransferStateCbFn&&self.off("dataTransferState",dataTransferStateCbFn),peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),void(dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn)))})}if(!self._peerConnections[peerId])return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer connection does not exists.")
-;if(!self._peerInformations[peerId])return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer connection does not exists.");if(self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer connection is not stable.");if(!self._dataTransfers[transferId])return void returnErrorBeforeTransferFn("Unable to start data transfer as data transfer session is not in order.");if(!self._dataChannels[peerId]||!self._dataChannels[peerId].main)return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel connection does not exists.");if(self._dataChannels[peerId].main.channel.readyState!==self.DATA_CHANNEL_STATE.OPEN)return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel connection is not opened.");var streamId=self._dataChannels[peerId].main.streamId;if(streamId&&"main"===channelProp&&self._dataStreams[streamId]&&("string"===self._dataStreams[streamId].sessionChunkType&&("string"===self._dataTransfers[transferId].sessionChunkType||self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1)||"binary"===self._dataStreams[streamId].sessionChunkType&&"binary"===self._dataStreams[streamId].sessionChunkType&&-1===self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)))return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel currently has an active "+self._dataStreams[streamId].sessionChunkType+" data streaming session.");var protocolVer=(self._peerInformations[peerId].agent||{}).DTProtocolVersion||"0.1.0",requireInterop=self._isLowerThanVersion(protocolVer,"0.1.2")||!self._initOptions.enableSimultaneousTransfers;return self._isLowerThanVersion(protocolVer,"0.1.2")&&"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer do not support DATA_URL type of data transfers"):"MCU"!==peerId&&self._hasMCU?(channelProp=requireInterop?"main":transferId,peerConnectionStateCbFn=function(){returnErrorBeforeTransferFn("Data transfer terminated as Peer connection is not stable.")},self.once("peerConnectionState",peerConnectionStateCbFn,function(state,evtPeerId){return self._dataTransfers[transferId]?state!==self.PEER_CONNECTION_STATE.STABLE&&evtPeerId===peerId:void self.off("peerConnectionState",peerConnectionStateCbFn)}),requireInterop):(requireInterop||"main"===channelProp)&&self._dataChannels[peerId].main.transferId?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel has a data transfer in-progress."):(self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0},dataChannelStateCbFn=function(state,evtPeerId,error){self._dataTransfers[transferId].sessions[peerId].ackN>=self._dataTransfers[transferId].chunks.length-1||returnErrorBeforeTransferFn(error?error.message||error.toString():"Data transfer terminated as Peer Datachannel connection closed abruptly.")},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void self.off("dataChannelState",dataChannelStateCbFn);if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId))return state===self.DATA_CHANNEL_STATE.OPEN&&"main"!==channelProp&&channelName===transferId?(self._dataChannels[peerId][channelProp].transferId=transferId,sendWRQFn(),!1):[self.DATA_CHANNEL_STATE.CREATE_ERROR,self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(channelProp="main",self._dataChannels[peerId].main.transferId=transferId,sendWRQFn()):(channelProp=transferId,self._createDataChannel(peerId,transferId,"data"===self._dataTransfers[transferId].sessionType?self._CHUNK_DATAURL_SIZE:"string"===self._dataTransfers[transferId].sessionChunkType?"firefox"===AdapterJS.webrtcDetectedBrowser?16384:65546:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE))))},Skylink.prototype._getTransferInfo=function(transferId,peerId,returnDataProp,hidePercentage,returnDataAtStart){if(!this._dataTransfers[transferId])return{};var transferInfo={name:this._dataTransfers[transferId].name,size:this._dataTransfers[transferId].size,dataType:this._dataTransfers[transferId].dataType||this.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:this._dataTransfers[transferId].mimeType||null,chunkSize:this._dataTransfers[transferId].chunkSize,chunkType:this._dataTransfers[transferId].chunkType,timeout:this._dataTransfers[transferId].timeout,isPrivate:this._dataTransfers[transferId].isPrivate,direction:this._dataTransfers[transferId].direction};if(this._dataTransfers[transferId].originalSize?transferInfo.size=this._dataTransfers[transferId].originalSize:this._dataTransfers[transferId].chunkType===this.DATA_TRANSFER_DATA_TYPE.BINARY_STRING&&(transferInfo.size=Math.ceil(3*transferInfo.size/4)),!hidePercentage){if(transferInfo.percentage=0,!this._dataTransfers[transferId].sessions[peerId])return returnDataProp&&(transferInfo.data=null),transferInfo;if(this._dataTransfers[transferId].direction===this.DATA_TRANSFER_TYPE.DOWNLOAD)this._dataTransfers[transferId].sessions[peerId].receivedSize===this._dataTransfers[transferId].sessions[peerId].size?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].receivedSize/this._dataTransfers[transferId].size*100).toFixed(2),10);else{var chunksLength=this._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?this._dataTransfers[transferId].enforceBSInfo.chunks.length:this._dataTransfers[transferId].chunks.length;this._dataTransfers[transferId].sessions[peerId].ackN===chunksLength?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].ackN/chunksLength*100).toFixed(2),10)}returnDataProp&&("number"!=typeof returnDataAtStart?100===transferInfo.percentage?transferInfo.data=this._getTransferData(transferId):transferInfo.data=null:(transferInfo.percentage=returnDataAtStart,0===returnDataAtStart&&(transferInfo.data=this._getTransferData(transferId))))}return transferInfo},Skylink.prototype._getTransferData=function(transferId){if(!this._dataTransfers[transferId])return null;if(this._dataTransfers[transferId].dataType===this.DATA_TRANSFER_SESSION_TYPE.BLOB){var mimeType={name:this._dataTransfers[transferId].name};return this._dataTransfers[transferId].mimeType&&(mimeType.type=this._dataTransfers[transferId].mimeType),new Blob(this._dataTransfers[transferId].chunks,mimeType)}return this._dataTransfers[transferId].chunks.join("")},Skylink.prototype._handleDataTransferTimeoutForPeer=function(transferId,peerId,setPeerTO){var self=this;if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer does not exists for Peer. Ignoring timeout."]);log.debug([peerId,"RTCDataChannel",transferId,"Clearing data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer&&clearTimeout(self._dataTransfers[transferId].sessions[peerId].timer),self._dataTransfers[transferId].sessions[peerId].timer=null,setPeerTO&&(log.debug([peerId,"RTCDataChannel",transferId,"Setting data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer=setTimeout(function(){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer already ended for Peer. Ignoring expired timeout."]);if(!self._user||!self._user.sid)return void log.debug([peerId,"RTCDataChannel",transferId,"User is not in Room. Ignoring expired timeout."]);if(!self._dataChannels[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Datachannel connection does not exists. Ignoring expired timeout."]);log.error([peerId,"RTCDataChannel",transferId,"Data transfer response has timed out."]);var emitEventFn=function(cb){if("MCU"===peerId){for(var broadcastedPeers=[self._dataTransfers[transferId].peers.main,self._dataTransfers[transferId].peers[transferId]],i=0;i"],rawData);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping data received from Peer as Datachannel connection is not present ->"],rawData);if("string"==typeof rawData)try{var protocolData=JSON.parse(rawData);if(isStreamChunk=!1,log.debug([peerId,"RTCDataChannel",channelProp,'Received protocol "'+protocolData.type+'" message ->'],protocolData),[self._DC_PROTOCOL_TYPE.ACK,self._DC_PROTOCOL_TYPE.ERROR,self._DC_PROTOCOL_TYPE.CANCEL].indexOf(protocolData.type)>-1&&!(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded protocol message as data transfer session is not present ->"],protocolData);switch(protocolData.type){case self._DC_PROTOCOL_TYPE.WRQ:if(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId])return log.warn([peerId,"RTCDataChannel",channelProp,"Rejecting bidirectional data transfer request as it is currently not supported in the SDK ->"],protocolData),void self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,ackN:-1,sender:self._user.sid},channelProp);self._WRQProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ACK:self._ACKProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ERROR:self._ERRORProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.CANCEL:self._CANCELProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.MESSAGE:self._MESSAGEProtocolHandler(peerId,protocolData,channelProp);break;default:log.warn([peerId,"RTCDataChannel",channelProp,'Discarded unknown "'+protocolData.type+'" message ->'],protocolData)}}catch(error){if(rawData.indexOf("{")>-1&&rawData.indexOf("}")>0)throw log.error([peerId,"RTCDataChannel",channelProp,"Failed parsing protocol step data error ->"],{data:rawData,error:error}),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(peerId,channelProp)),error;if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING;if(isStreamChunk||self._dataTransfers[transferId].dataType===self.DATA_TRANSFER_SESSION_TYPE.DATA_URL)log.debug([peerId,"RTCDataChannel",channelProp,"Received string data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.length||rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.STRING,rawData.length||rawData.size||0,channelProp);else{var removeSpaceData=rawData.replace(/\s|\r|\n/g,"");log.debug([peerId,"RTCDataChannel",channelProp,"Received binary string data chunk @"+self._dataTransfers[transferId].sessions[peerId].ackN+" with size ->"],removeSpaceData.length||removeSpaceData.size),self._DATAProtocolHandler(peerId,self._base64ToBlob(removeSpaceData),self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,removeSpaceData.length||removeSpaceData.size||0,channelProp)}}else{if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);if(rawData instanceof Blob)log.debug([peerId,"RTCDataChannel",channelProp,"Received blob data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.BLOB,rawData.size,channelProp);else{var byteArray=rawData,blob=null;if(rawData.constructor&&"Array"===rawData.constructor.name&&(byteArray=new Int8Array(rawData)),"IE"===AdapterJS.webrtcDetectedBrowser){if(window.BlobBuilder){var bb=new BlobBuilder;bb.append(rawData.constructor&&"ArrayBuffer"===rawData.constructor.name?byteArray:new Uint8Array(byteArray).buffer),blob=bb.getBlob()}}else blob=new Blob([byteArray]);log.debug([peerId,"RTCDataChannel",channelProp,"Received arraybuffer data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],blob.size),self._DATAProtocolHandler(peerId,blob,self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,blob.size,channelProp)}}},Skylink.prototype._WRQProtocolHandler=function(peerId,data,channelProp){var self=this,transferId="main"===channelProp?data.transferId||null:channelProp,senderPeerId=data.sender||peerId;if(["fastBinaryStart","fastBinaryStop"].indexOf(data.dataType)>-1)if("fastBinaryStart"===data.dataType){transferId||(transferId="stream_"+peerId+"_"+(new Date).getTime()),self._dataStreams[transferId]={chunkSize:0,chunkType:"string"===data.chunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:data.chunkType,isPrivate:!!data.isPrivate,isStringStream:"string"===data.chunkType,senderPeerId:senderPeerId,isUpload:!1},self._dataChannels[peerId][channelProp].streamId=transferId;self.once("dataChannelState",function(){},function(state,evtPeerId,channelName,channelType,error){if(!self._dataStreams[transferId])return!0;if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId&&channelType===self.DATA_CHANNEL_TYPE.DATA)&&[self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');return self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},updatedError),!0}}),self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STARTED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStarted",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1)}else transferId=self._dataChannels[peerId][channelProp].streamId,self._dataStreams[transferId]&&!self._dataStreams[transferId].isUpload&&(self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STOPPED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStopped",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1),self._dataChannels[peerId][channelProp].streamId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp),delete self._dataStreams[transferId]);else transferId||(transferId="transfer_"+peerId+"_"+(new Date).getTime()),self._dataTransfers[transferId]={name:data.name||transferId,size:data.size||0,chunkSize:data.chunkSize,originalSize:data.originalSize||0,timeout:data.timeout||60,isPrivate:!!data.isPrivate,senderPeerId:data.sender||peerId,dataType:self.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:data.mimeType||null,chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,direction:self.DATA_TRANSFER_TYPE.DOWNLOAD,chunks:[],sessions:{},sessionType:data.dataType||"blob",sessionChunkType:data.chunkType||"string"},"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?(self._dataTransfers[transferId].dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,self._dataTransfers[transferId].chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING):"blob"===self._dataTransfers[transferId].sessionType&&"binary"===self._dataTransfers[transferId].sessionChunkType&&(self._dataTransfers[transferId].chunkType=self._binaryChunkType),self._dataChannels[peerId][channelProp].transferId=transferId,self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0,receivedSize:0},self._trigger("incomingDataRequest",transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!1),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_REQUEST,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)},Skylink.prototype._ACKProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ACK event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};if(data.ackN>-1){if(0===data.ackN)emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_STARTED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,0),null)});else if(self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?data.ackN===self._dataTransfers[transferId].enforceBSInfo.chunks.length:data.ackN===self._dataTransfers[transferId].chunks.length)return self._dataTransfers[transferId].sessions[peerId].ackN=data.ackN,emitEventFn(function(evtPeerId){self._trigger("incomingData",self._getTransferData(transferId),transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,100),null)}),void(self._dataChannels[peerId][channelProp]&&(self._dataChannels[peerId][channelProp].transferId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp)));var uploadFn=function(chunk){self._sendMessageToDataChannel(peerId,chunk,channelProp,!0),data.ackN-1?self._blobToBase64(self._dataTransfers[transferId].enforceBSInfo.chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING?self._blobToBase64(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER?self._blobToArrayBuffer(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):uploadFn(self._dataTransfers[transferId].chunks[data.ackN])}else self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.REJECTED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as Peer has rejected data transfer request"),transferType:self.DATA_TRANSFER_TYPE.UPLOAD})},Skylink.prototype._MESSAGEProtocolHandler=function(peerId,data,channelProp){var senderPeerId=data.sender||peerId;log.log([senderPeerId,"RTCDataChannel",channelProp,"Received P2P message from peer:"],data),this._trigger("incomingMessage",{content:data.data,isPrivate:data.isPrivate,isDataChannel:!0,targetPeerId:this._user.sid,senderPeerId:senderPeerId},senderPeerId,this.getPeerInfo(senderPeerId),!1)},Skylink.prototype._ERRORProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ERROR event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,evtPeerId,self._getTransferInfo(transferId,peerID,!0,!1,!1),{message:new Error(data.content),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._CANCELProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of CANCEL event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(peerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.CANCEL,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error(data.content||"Peer has terminated data transfer."),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._DATAProtocolHandler=function(peerId,chunk,chunkType,chunkSize,channelProp){var self=this,transferId=channelProp,senderPeerId=peerId;if(self._dataChannels[peerId]&&self._dataChannels[peerId][channelProp]){var streamId=self._dataChannels[peerId][channelProp].streamId;if(streamId&&self._dataStreams[streamId]&&("string"==typeof chunk&&"string"===self._dataStreams[streamId].sessionChunkType||chunk instanceof Blob&&"binary"===self._dataStreams[streamId].sessionChunkType))return senderPeerId=self._dataStreams[streamId].senderPeerId||peerId,self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVED,streamId,senderPeerId,{chunk:chunk,chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},null),void self._trigger("incomingDataStream",chunk,transferId,senderPeerId,{chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},!1);if("main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._dataTransfers[transferId].senderPeerId&&(senderPeerId=self._dataTransfers[transferId].senderPeerId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1),self._dataTransfers[transferId].chunkType=chunkType,self._dataTransfers[transferId].sessions[peerId].receivedSize+=chunkSize,self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN]=chunk,self._dataTransfers[transferId].sessions[peerId].receivedSize>=self._dataTransfers[transferId].size)return log.log([peerId,"RTCDataChannel",channelProp,"Data transfer has been completed. Computed size ->"],self._dataTransfers[transferId].sessions[peerId].receivedSize),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN+1},channelProp),self._trigger("incomingData",self._getTransferData(transferId),transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),null),void self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null);self._dataTransfers[transferId].sessions[peerId].ackN+=1,self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN},channelProp),self._handleDataTransferTimeoutForPeer(transferId,peerId,!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOADING,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)}},Skylink.prototype._onIceCandidate=function(targetMid,candidate){var self=this,pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCIceCandidate",null,"Ignoring of ICE candidate event as Peer connection does not exists ->"],candidate);if(candidate.candidate){pc.gathering||(log.log([targetMid,"RTCIceCandidate",null,"ICE gathering has started."]),pc.gathering=!0,pc.gathered=!1,self._trigger("candidateGenerationState",self.CANDIDATE_GENERATION_STATE.GATHERING,targetMid));var candidateType=candidate.candidate.split(" ")[7];if(log.debug([targetMid,"RTCIceCandidate",candidateType,"Generated ICE candidate ->"],candidate),"endOfCandidates"===candidateType||!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].localDescription&&self._peerConnections[targetMid].localDescription.sdp&&self._peerConnections[targetMid].localDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return void log.warn([targetMid,"RTCIceCandidate",candidateType,"Dropping of sending ICE candidate end-of-candidates signal or unused ICE candidates to prevent errors ->"],candidate);if(self._initOptions.filterCandidatesType[candidateType]){if(!self._hasMCU||!self._initOptions.forceTURN)return void log.warn([targetMid,"RTCIceCandidate",candidateType,"Dropping of sending ICE candidate as it matches ICE candidate filtering flag ->"],candidate);log.warn([targetMid,"RTCIceCandidate",candidateType,"Not dropping of sending ICE candidate as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured ->"],candidate)}if(self._gatheredCandidates[targetMid]||(self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),self._gatheredCandidates[targetMid].sending[candidateType].push({sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate}),!self._initOptions.enableIceTrickle)return void log.warn([targetMid,"RTCIceCandidate",candidateType,"Dropping of sending ICE candidate as trickle ICE is disabled ->"],candidate);log.debug([targetMid,"RTCIceCandidate",candidateType,"Sending ICE candidate ->"],candidate),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.CANDIDATE,label:candidate.sdpMLineIndex,id:candidate.sdpMid,candidate:candidate.candidate,mid:self._user.sid,target:targetMid,rid:self._room.id})}else{if(log.log([targetMid,"RTCIceCandidate",null,"ICE gathering has completed."]),pc.gathered)return;if(pc.gathering=!1,pc.gathered=!0,self._trigger("candidateGenerationState",self.CANDIDATE_GENERATION_STATE.COMPLETED,targetMid),self._initOptions.enableIceTrickle)self._gatheredCandidates[targetMid]&&self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.END_OF_CANDIDATES,noOfExpectedCandidates:self._gatheredCandidates[targetMid].sending.srflx.length+self._gatheredCandidates[targetMid].sending.host.length+self._gatheredCandidates[targetMid].sending.relay.length,mid:self._user.sid,target:targetMid,rid:self._room.id});else{var sessionDescription=self._peerConnections[targetMid].localDescription;if(!(sessionDescription&&sessionDescription.type&&sessionDescription.sdp))return void log.warn([targetMid,"RTCSessionDescription",null,"Not sending any session description after ICE gathering completed as it is not present."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,userInfo:self._getUserInfo(targetMid),target:targetMid,rid:self._room.id})}}},Skylink.prototype._addIceCandidateToQueue=function(targetMid,canId,candidate){var candidateType=candidate.candidate.split(" ")[7];log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Buffering ICE candidate."]),
-this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.BUFFERED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[],this._peerCandidatesQueue[targetMid].push([canId,candidate])},Skylink.prototype._addIceCandidateFromQueue=function(targetMid){this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[];for(var i=0;i"],error),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},error)};if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Adding ICE candidate."]),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESSING,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[targetMid].remoteDescription&&self._peerConnections[targetMid].remoteDescription.sdp&&self._peerConnections[targetMid].remoteDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),void self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed."));try{self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)}catch(error){onErrorCbFn(error)}},Skylink.prototype._setIceServers=function(passedIceServers){var self=this,iceServerName=null,iceServerProtocol="stun",iceServerPorts={udp:[3478,19302,19303,19304],tcp:[80,443],both:[19305,19306,19307,19308]},iceServers=[{urls:[]},{urls:[]}];return passedIceServers.forEach(function(server){if(0===server.url.indexOf("stun:"))server.url.indexOf("temasys")>0?iceServerName=(server.url.split(":")[1]||"").split("?")[0]||null:iceServers[0].urls.push(server.url);else if(0===server.url.indexOf("turn:")&&server.url.indexOf("@")>0&&server.credential&&!iceServers[1].username&&!iceServers[1].credential){var parts=server.url.split(":"),urlParts=(parts[1]||"").split("@");iceServerName=(urlParts[1]||"").split("?")[0],iceServers[1].username=urlParts[0],iceServers[1].credential=server.credential,iceServerProtocol="turn"}}),self._initOptions.iceServer?iceServers=[{urls:self._initOptions.iceServer.urls,username:iceServers[1].username||null,credential:iceServers[1].credential||null}]:(iceServerName=iceServerName||"turn.temasys.io","turn"!==iceServerProtocol||self._initOptions.enableTURNServer||self._initOptions.forceTURNSSL?"edge"===AdapterJS.webrtcDetectedBrowser?(iceServerPorts.udp=[3478],iceServerPorts.tcp=[],iceServerPorts.both=[],iceServerProtocol="turn"):self._initOptions.forceTURNSSL?"firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion<53?(iceServerPorts.udp=[],iceServerPorts.tcp=[443],iceServerPorts.both=[],iceServerProtocol="turn"):(iceServerPorts.udp=[],iceServerProtocol="turns"):"firefox"===AdapterJS.webrtcDetectedBrowser&&(iceServerPorts.udp=[3478],iceServerPorts.tcp=[443,80]):iceServerProtocol="stun",self._initOptions.TURNServerTransport!==self.TURN_TRANSPORT.UDP||self._initOptions.forceTURNSSL?self._initOptions.TURNServerTransport===self.TURN_TRANSPORT.TCP?(iceServerPorts.tcp=iceServerPorts.tcp.concat(iceServerPorts.both),iceServerPorts.udp=[],iceServerPorts.both=[]):self._initOptions.TURNServerTransport===self.TURN_TRANSPORT.NONE&&(iceServerPorts.tcp=[],iceServerPorts.udp=[]):(iceServerPorts.udp=iceServerPorts.udp.concat(iceServerPorts.both),iceServerPorts.tcp=[],iceServerPorts.both=[]),"stun"===iceServerProtocol&&(iceServerPorts.tcp=[]),"stun"!==iceServerProtocol||self._initOptions.enableSTUNServer?(iceServerPorts.tcp.forEach(function(tcpPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+tcpPort+"?transport=tcp")}),iceServerPorts.udp.forEach(function(udpPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+udpPort+"?transport=udp")}),iceServerPorts.both.forEach(function(bothPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+bothPort)}),self._initOptions.usePublicSTUN||iceServers.splice(0,1)):iceServers=[]),log.log("Output iceServers configuration:",iceServers),{iceServers:iceServers}},Skylink.prototype.refreshConnection=function(targetPeerId,iceRestart,options,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),doIceRestart=!1,bwOptions={};Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:"boolean"==typeof targetPeerId?doIceRestart=targetPeerId:targetPeerId&&"object"==typeof targetPeerId?bwOptions=targetPeerId:"function"==typeof targetPeerId&&(callback=targetPeerId),"boolean"==typeof iceRestart?doIceRestart=iceRestart:iceRestart&&"object"==typeof iceRestart?bwOptions=iceRestart:"function"==typeof iceRestart&&(callback=iceRestart),options&&"object"==typeof options?bwOptions=options:"function"==typeof options&&(callback=options);var emitErrorForPeersFn=function(error){if(log.error(error),"function"==typeof callback){var listOfPeerErrors={};if(0===listOfPeers.length)listOfPeerErrors.self=new Error(error);else for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}},refreshSinglePeer=function(peerId,peerCallback){if(!self._peerConnections[peerId])return error="There is currently no existing peer connection made with the peer. Unable to restart connection",log.error([peerId,null,null,error]),void peerCallback(error);log.log([peerId,"PeerConnection",null,"Restarting peer connection"]),self._restartPeerConnection(peerId,doIceRestart,bwOptions,peerCallback)};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?refreshSinglePeer(peerId,refreshSinglePeerCallback(peerId)):(error="Peer connection with peer does not exists. Unable to restart",log.error([peerId,"PeerConnection",null,error]),refreshSinglePeerCallback(peerId)(error))}}},Skylink.prototype.getConnectionStatus=function(targetPeerId,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),listOfPeerStats={},listOfPeerErrors={};if(Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId&&targetPeerId?listOfPeers=[targetPeerId]:"function"==typeof targetPeerId&&(callback=targetPeerId,targetPeerId=void 0),0===listOfPeers.length)return listOfPeerErrors.self=new Error("There is currently no peer connections to retrieve connection status"),log.error([null,"RTCStatsReport",null,"Retrieving request failure ->"],listOfPeerErrors.self),void("function"==typeof callback&&callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null));"edge"===AdapterJS.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){-1===completedTaskCounter.indexOf(peerId)&&completedTaskCounter.push(peerId),completedTaskCounter.length===listOfPeers.length&&"function"==typeof callback&&(Object.keys(listOfPeerErrors).length>0?callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null):callback(null,{listOfPeers:listOfPeers,connectionStats:listOfPeerStats}))},statsFn=function(peerId){var retrieveFn=function(firstRetrieval,nextCb){return function(err,result){if(err)return log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],error),listOfPeerErrors[peerId]=error,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,error),checkCompletedFn(peerId),void(firstRetrieval&&delete self._peerStats[peerId]);firstRetrieval?nextCb():(listOfPeerStats[peerId]=result,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_SUCCESS,peerId,listOfPeerStats[peerId],null),checkCompletedFn(peerId))}};if(!self._peerStats[peerId])return self._peerStats[peerId]={},log.debug([peerId,"RTCStatsReport",null,"Retrieving first report to tabulate results"]),void self._retrieveStats(peerId,retrieveFn(!0,function(){self._retrieveStats(peerId,retrieveFn())}),!0);self._retrieveStats(peerId,retrieveFn())},i=0;i"],listOfPeerErrors[peerId]),self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,listOfPeerErrors[peerId]),checkCompletedFn(peerId))}},Skylink.prototype._retrieveStats=function(peerId,callback,beSilentOnLogs,isAutoBwStats){var self=this,pc=self._peerConnections[peerId],output={raw:{},connection:{},audio:{sending:{},receiving:{}},video:{sending:{},receiving:{}},selectedCandidate:{local:{},remote:{},consentResponses:{},consentRequests:{},responses:{},requests:{}},certificate:{}};if(!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));if(!pc)return callback(new Error("Peer connection is not initialised"));"edge"!==AdapterJS.webrtcDetectedBrowser&&"AppleWebKit"!==AdapterJS.webrtcDetectedType||log.warn("Current connection stats may not be complete as it is in beta"),output.connection.iceConnectionState=pc.iceConnectionState,output.connection.iceGatheringState=pc.iceGatheringState,output.connection.signalingState=pc.signalingState,output.connection.remoteDescription={type:pc.remoteDescription&&pc.remoteDescription.type||"",sdp:pc.remoteDescription&&pc.remoteDescription.sdp||""},output.connection.localDescription={type:pc.localDescription&&pc.localDescription.type||"",sdp:pc.localDescription&&pc.localDescription.sdp||""},output.connection.candidates={sending:self._getSDPICECandidates(peerId,pc.localDescription,beSilentOnLogs),receiving:self._getSDPICECandidates(peerId,pc.remoteDescription,beSilentOnLogs)},output.connection.dataChannels={},output.connection.constraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,output.connection.optional=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,output.connection.sdpConstraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null,output.audio.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),output.video.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),output.audio.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"audio",beSilentOnLogs),output.video.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"video",beSilentOnLogs),output.certificate.local=self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),output.certificate.remote=self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs);var inboundSSRCs=self._getSDPMediaSSRC(peerId,pc.remoteDescription,beSilentOnLogs);output.audio.receiving.ssrc=inboundSSRCs.audio,output.video.receiving.ssrc=inboundSSRCs.video;var outboundSSRCs=self._getSDPMediaSSRC(peerId,pc.localDescription,beSilentOnLogs);output.audio.sending.ssrc=outboundSSRCs.audio,output.video.sending.ssrc=outboundSSRCs.video,Object.keys(self._dataChannels[peerId]||{}).forEach(function(prop){var channel=self._dataChannels[peerId][prop];output.connection.dataChannels[channel.channel.label]={label:channel.channel.label,readyState:channel.channel.readyState,channelType:self.DATA_CHANNEL_TYPE["main"===prop?"MESSAGING":"DATA"],currentTransferId:channel.transferId||null,currentStreamId:channel.streamId||null}});var certificateFn=function(item,prop){if(0===prop.indexOf("RTCCertificate_"))item.fingerprint===output.certificate.local.fingerprint?(output.certificate.local.derBase64=item.base64Certificate,output.certificate.local.fingerprintAlgorithm=item.fingerprintAlgorithm):item.fingerprint===output.certificate.remote.fingerprint&&(output.certificate.remote.derBase64=item.base64Certificate,output.certificate.remote.fingerprintAlgorithm=item.fingerprintAlgorithm);else if(0===prop.indexOf("ssrc_")&&item.transportId){var pairItem=output.raw[item.transportId]||{};output.certificate.srtpCipher=pairItem.srtpCipher,output.certificate.dtlsCipher=pairItem.dtlsCipher;var localCertItem=output.raw[pairItem.localCertificateId||""]||{};output.certificate.local.fingerprint=localCertItem.googFingerprint,output.certificate.local.fingerprintAlgorithm=localCertItem.googFingerprintAlgorithm,output.certificate.local.derBase64=localCertItem.googDerBase64;var remoteCertItem=output.raw[pairItem.remoteCertificateId||""]||{};output.certificate.remote.fingerprint=remoteCertItem.googFingerprint,output.certificate.remote.fingerprintAlgorithm=remoteCertItem.googFingerprintAlgorithm,output.certificate.remote.derBase64=remoteCertItem.googDerBase64}},candidatePairFn=function(item,prop){if(0===prop.indexOf("RTCIceCandidatePair_")){if("succeeded"!==item.state||output.selectedCandidate.nominated||item.prioirty<(output.selectedCandidate.priority||0))return;for(var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],sending=pc.localDescription&&pc.localDescription.sdp&&pc.localDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],receiving=pc.remoteDescription&&pc.remoteDescription&&pc.remoteDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],computePrioirtyFn=function(controller,controlled){return Math.pow(2,32)*Math.min(controller,controlled)+2*Math.max(controller,controlled)+(controller>controlled?1:0)},computeCanTypeFn=function(type){return"relay"===type?"relayed":"host"===type?"local":"srflx"===type?"serverreflexive":type},s=0;s0?"sending":"receiving";item.codecImplementationName="unknown"===item.codecImplementationName?null:item.codecImplementationName,output[item.mediaType][direction].codec.implementation=item.codecImplementationName||null,item.googCodecName="unknown"===item.googCodecName?null:item.googCodecName,output[item.mediaType][direction].codec.name=item.googCodecName||output[item.mediaType][direction].codec.name}},audioStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPAudioStream")){if(output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.audio.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),"function"!=typeof pc.getReceivers)return}else if(0===prop.indexOf("RTCMediaStreamTrack_remote_audio_"))output.audio.receiving.audioOutputLevel=item.audioLevel;else if(0===prop.indexOf("RTCOutboundRTPAudioStream"))output.audio.sending.targetBitrate=item.targetBitrate||0,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"audio"===item.mediaType&&item.isRemote)output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"audio"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"audio"===item.mediaType)if(prop.indexOf("_recv")>0){output.audio.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.audio.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.audio.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.audio.receiving.totalBytes=bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.audio.receiving.totalPackets=packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.audio.receiving.totalPacketsLost=packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost")}else{output.audio.sending.rtt=parseInt(item.googRtt||"0",10),output.audio.sending.audioInputLevel=parseInt(item.audioInputLevel||"0",10),output.audio.sending.echoReturnLoss=parseInt(item.googEchoCancellationReturnLoss||"0",10),output.audio.sending.echoReturnLossEnhancement=parseInt(item.googEchoCancellationReturnLossEnhancement||"0",10);var bytesSent=parseInt(item.bytesSent||"0",10);output.audio.sending.totalBytes=bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.audio.sending.totalPackets=packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent")}else if(0===prop.indexOf("inbound_rtp_audio"))output.audio.receiving.jitter=item.jitter||0,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if(0===prop.indexOf("outbound_rtp_audio")){output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.audio.sending.rtt=rtcpItem.roundTripTime||0}}else{output.audio.sending.targetBitrate=item.targetBitrate,output.audio.sending.rtt=item.roundTripTime,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.audio.sending.audioInputLevel=trackItem.audioLevel,output.audio.sending.echoReturnLoss=trackItem.echoReturnLoss,output.audio.sending.echoReturnLossEnhancement=trackItem.echoReturnLossEnhancement}},videoStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPVideoStream"))output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.framesDecoded=item.framesDecoded,output.video.receiving.qpSum=item.qpSum,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.video.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if(0===prop.indexOf("RTCMediaStreamTrack_remote_video_"))output.video.receiving.frameHeight=item.frameHeight,output.video.receiving.frameWidth=item.frameWidth,output.video.receiving.framesCorrupted=item.framesCorrupted,output.video.receiving.framesPerSecond=item.framesPerSecond,
-output.video.receiving.framesDropped=item.framesDropped,output.video.receiving.totalFrames=item.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,item,"framesReceived");else if(0===prop.indexOf("RTCOutboundRTPVideoStream"))output.video.sending.qpSum=item.qpSum,output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"video"===item.mediaType&&item.isRemote){output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.receiving.framesCorrupted=trackItem.framesCorrupted,output.video.receiving.framesDropped=trackItem.framesDropped,output.video.receiving.framesDecoded=trackItem.framesDecoded,output.video.receiving.totalFrames=trackItem.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,trackItem,"framesReceived")}else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"video"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType)if(prop.indexOf("_recv")>0){output.video.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.video.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.video.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10),output.video.receiving.renderDelayMs=parseInt(item.googRenderDelayMs||"0",10),output.video.receiving.frameWidth=parseInt(item.googFrameWidthReceived||"0",10),output.video.receiving.frameHeight=parseInt(item.googFrameHeightReceived||"0",10),output.video.receiving.framesDecoded=parseInt(item.framesDecoded||"0",10),output.video.receiving.frameRateOutput=parseInt(item.googFrameRateOutput||"0",10),output.video.receiving.frameRateDecoded=parseInt(item.googFrameRateDecoded||"0",10),output.video.receiving.frameRateReceived=parseInt(item.googFrameRateReceived||"0",10),output.video.receiving.qpSum=parseInt(item.qpSum||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.video.receiving.totalBytes=bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.video.receiving.totalPackets=packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.video.receiving.totalPacketsLost=packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost");var nacksSent=parseInt(item.googNacksSent||"0",10);output.video.receiving.totalNacks=nacksSent,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"googNacksSent");var plisSent=parseInt(item.googPlisSent||"0",10);output.video.receiving.totalPlis=plisSent,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"googPlisSent");var firsSent=parseInt(item.googFirsSent||"0",10);output.video.receiving.totalFirs=firsSent,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"googFirsSent")}else{output.video.sending.rtt=parseInt(item.googRtt||"0",10),output.video.sending.frameWidth=parseInt(item.googFrameWidthSent||"0",10),output.video.sending.frameHeight=parseInt(item.googFrameHeightSent||"0",10),output.video.sending.framesEncoded=parseInt(item.framesEncoded||"0",10),output.video.sending.frameRateInput=parseInt(item.googFrameRateInput||"0",10),output.video.sending.frameRateEncoded=parseInt(item.googFrameRateEncoded||"0",10),output.video.sending.frameRateSent=parseInt(item.googFrameRateSent||"0",10),output.video.sending.cpuLimitedResolution="true"===item.googCpuLimitedResolution,output.video.sending.bandwidthLimitedResolution="true"===item.googBandwidthLimitedResolution;var bytesSent=parseInt(item.bytesSent||"0",10);output.video.sending.totalBytes=bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.video.sending.totalPackets=packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent");var nacksReceived=parseInt(item.googNacksReceived||"0",10);output.video.sending.totalNacks=nacksReceived,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"googNacksReceived");var plisReceived=parseInt(item.googPlisReceived||"0",10);output.video.sending.totalPlis=plisReceived,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"googPlisReceived");var firsReceived=parseInt(item.googFirsReceived||"0",10);output.video.sending.totalFirs=firsReceived,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"googFirsReceived")}else if(0===prop.indexOf("inbound_rtp_video"))output.video.receiving.jitter=item.jitter||0,output.video.receiving.framesDecoded=item.framesDecoded||0,output.video.receiving.frameRateMean=item.framerateMean||0,output.video.receiving.frameRateStdDev=item.framerateStdDev||0,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount");else if(0===prop.indexOf("outbound_rtp_video")){output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.frameRateMean=item.framerateMean||0,output.video.sending.frameRateStdDev=item.framerateStdDev||0,output.video.sending.framesDropped=item.droppedFrames||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.video.sending.rtt=rtcpItem.roundTripTime||0}}else{output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.roundTripTime=item.roundTripTime||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.sending.frameHeight=trackItem.frameHeight,output.video.sending.frameWidth=trackItem.frameWidth,output.video.sending.framesPerSecond=trackItem.framesPerSecond,output.video.sending.totalFrames=trackItem.framesSent,output.video.sending.frames=self._parseConnectionStats(prevStats,trackItem,"framesSent")}},videoE2EStatsFn=function(item,prop){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType){var captureStartNtpTimeMs=parseInt(item.googCaptureStartNtpTimeMs||"0",10),remoteStream=pc.getRemoteStreams()[0];if(!(captureStartNtpTimeMs>0&&prop.indexOf("_recv")>0&&remoteStream&&document&&"function"==typeof document.getElementsByTagName))return;try{var elements=document.getElementsByTagName("plugin"===AdapterJS.webrtcDetectedType?"object":"video");"plugin"!==AdapterJS.webrtcDetectedType&&0===elements.length&&(elements=document.getElementsByTagName("audio"));for(var e=0;e0))break;for(var ec=0;ec"],error)}}},successCbFn=function(stats){"function"==typeof stats.forEach?stats.forEach(function(item,prop){output.raw[prop]=item}):output.raw=stats;var edgeTracksKind={remote:{},local:{}};"edge"===AdapterJS.webrtcDetectedBrowser&&(pc.remoteStream&&pc.remoteStream.getTracks().forEach(function(track){edgeTracksKind.remote[track.id]=track.kind}),pc.localStream&&pc.localStream.getTracks().forEach(function(track){edgeTracksKind.local[track.id]=track.kind})),Object.keys(output.raw).forEach(function(prop){if(0!==prop.indexOf("ssrc_")||output.raw[prop].mediaType){if("edge"===AdapterJS.webrtcDetectedBrowser&&!output.raw[prop].mediaType&&["inboundrtp","outboundrtp"].indexOf(output.raw[prop].type)>-1){var trackItem=output.raw[output.raw[prop].mediaTrackId]||{};output.raw[prop].mediaType=edgeTracksKind[output.raw[prop].isRemote?"remote":"local"][trackItem.trackIdentifier]||""}}else output.raw[prop].mediaType=output.raw[prop].audioInputLevel||output.raw[prop].audioOutputLevel?"audio":"video";certificateFn(output.raw[prop],prop),candidatePairFn(output.raw[prop],prop),codecsFn(output.raw[prop],prop),audioStatsFn(output.raw[prop],prop),videoStatsFn(output.raw[prop],prop),videoE2EStatsFn(output.raw[prop],prop),isAutoBwStats&&!self._peerBandwidth[peerId][prop]?self._peerBandwidth[peerId][prop]=output.raw[prop]:isAutoBwStats||self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=output.raw[prop])}),output.audio.sending.bytes=output.audio.sending.bytes||0,output.audio.sending.packets=output.audio.sending.packets||0,output.audio.sending.totalBytes=output.audio.sending.totalBytes||0,output.audio.sending.totalPackets=output.audio.sending.totalPackets||0,output.video.sending.bytes=output.video.sending.bytes||0,output.video.sending.packets=output.video.sending.packets||0,output.video.sending.totalBytes=output.video.sending.totalBytes||0,output.video.sending.totalPackets=output.video.sending.totalPackets||0,output.audio.receiving.bytes=output.audio.receiving.bytes||0,output.audio.receiving.packets=output.audio.receiving.packets||0,output.audio.receiving.totalBytes=output.audio.receiving.totalBytes||0,output.audio.receiving.totalPackets=output.audio.receiving.totalPackets||0,output.video.receiving.bytes=output.video.receiving.bytes||0,output.video.receiving.packets=output.video.receiving.packets||0,output.video.receiving.totalBytes=output.video.receiving.totalBytes||0,output.video.receiving.totalPackets=output.video.receiving.totalPackets||0,callback(null,output)},errorCbFn=function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)};if("function"!=typeof pc.getStats)return errorCbFn(new Error("getStats() API is not available."));"plugin"===AdapterJS.webrtcDetectedType?pc.getStats(null,successCbFn,errorCbFn):pc.getStats(null).then(successCbFn).catch(errorCbFn)},Skylink.prototype._addPeer=function(targetMid,cert,peerBrowser,receiveOnly,isSS){var self=this;return self._peerConnections[targetMid]?void log.error([targetMid,null,null,"Connection to peer has already been made"]):(self._peerConnStatus[targetMid]={connected:!1,init:!1},log.log([targetMid,null,null,"Starting the connection to peer. Options provided:"],{peerBrowser:peerBrowser,receiveOnly:receiveOnly,enableDataChannel:self._initOptions.enableDataChannel}),log.info("Adding peer",isSS),self._peerConnections[targetMid]=self._createPeerConnection(targetMid,!!isSS,cert),self._peerConnections[targetMid]?(self._peerConnStatus[targetMid].init=!0,void(self._peerConnections[targetMid].hasScreen=!!isSS)):void log.error([targetMid,null,null,"Failed creating the connection to peer."]))},Skylink.prototype._restartPeerConnection=function(peerId,doIceRestart,bwOptions,callback){var self=this;if(!self._peerConnections[peerId])return void log.error([peerId,null,null,"Peer does not have an existing connection. Unable to restart"]);var pc=self._peerConnections[peerId],agent=(self.getPeerInfo(peerId)||{}).agent||{};if(self._isLowerThanVersion(agent.SMProtocolVersion||"","0.1.2")){var notSupportedError=new Error("Failed restarting with other agents connecting from other SDKs as re-negotiation is not supported by other SDKs");return log.warn([peerId,"RTCPeerConnection",null,"Ignoring restart request as agent's SDK does not support it"],notSupportedError),void("function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(notSupportedError)))}if(pc.signalingState===self.PEER_CONNECTION_STATE.STABLE&&self._peerConnections[peerId]){log.log([peerId,null,null,"Sending restart message to signaling server ->"],{iceRestart:doIceRestart,options:bwOptions}),self._peerCustomConfigs[peerId]=self._peerCustomConfigs[peerId]||{},self._peerCustomConfigs[peerId].bandwidth=self._peerCustomConfigs[peerId].bandwidth||{},self._peerCustomConfigs[peerId].googleXBandwidth=self._peerCustomConfigs[peerId].googleXBandwidth||{},bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._peerCustomConfigs[peerId].bandwidth.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._peerCustomConfigs[peerId].bandwidth.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._peerCustomConfigs[peerId].bandwidth.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._peerCustomConfigs[peerId].googleXBandwidth.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._peerCustomConfigs[peerId].googleXBandwidth.max=bwOptions.googleXBandwidth.max));var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===doIceRestart&&self._enableIceRestart&&self._peerInformations[peerId]&&self._peerInformations[peerId].config.enableIceRestart,isRestartResend:!1,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._peerEndOfCandidatesCounter[peerId]=self._peerEndOfCandidatesCounter[peerId]||{},self._peerEndOfCandidatesCounter[peerId].len=0,self._sendChannelMessage(restartMsg),self._trigger("peerRestart",peerId,self.getPeerInfo(peerId),!0,!0===doIceRestart),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart callback"]),callback(null))}else if(pc.signalingState===self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER){var hasLocalDescription=pc.localDescription&&pc.localDescription.sdp;if(hasLocalDescription)self._sendChannelMessage({type:pc.localDescription.type,sdp:pc.localDescription.sdp,mid:self._user.sid,target:peerId,rid:self._room.id,restart:!0});else{var noLocalDescriptionError="Failed re-sending localDescription as there is no localDescription set to connection. There could be a handshaking step error";log.error([peerId,"RTCPeerConnection",null,noLocalDescriptionError],{localDescription:pc.localDescription,remoteDescription:pc.remoteDescription}),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(noLocalDescriptionError)))}}else{var unableToRestartError="Failed restarting as peer connection state is "+pc.signalingState;log.warn([peerId,"RTCPeerConnection",null,unableToRestartError]),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(unableToRestartError)))}},Skylink.prototype._removePeer=function(peerId){if(!this._peerConnections[peerId]&&!this._peerInformations[peerId])return void log.debug([peerId,"RTCPeerConnection",null,"Dropping the hangup from Peer as not connected to Peer at all."]);var peerInfo=clone(this.getPeerInfo(peerId))||{userData:"",settings:{audio:!1,video:!1,data:!1},mediaStatus:{audioMuted:!0,videoMuted:!0},agent:{name:"unknown",version:0,os:"",pluginVersion:null},config:{enableDataChannel:!0,enableIceRestart:!1,enableIceTrickle:!0,priorityWeight:0,publishOnly:!1,receiveOnly:!0},parentId:null,room:clone(this._selectedRoom)};"MCU"!==peerId?this._trigger("peerLeft",peerId,peerInfo,!1):(this._hasMCU=!1,log.log([peerId,null,null,"MCU has stopped listening and left"]),this._trigger("serverPeerLeft",peerId,this.SERVER_PEER_TYPE.MCU)),this._peerConnections[peerId]&&(this._peerConnections[peerId].signalingState!==this.PEER_CONNECTION_STATE.CLOSED&&(this._peerConnections[peerId].close(),"AppleWebKit"===AdapterJS.webrtcDetectedType&&(this._peerConnections[peerId].signalingStateClosed||(this._peerConnections[peerId].signalingStateClosed=!0,this._trigger("peerConnectionState",this.PEER_CONNECTION_STATE.CLOSED,peerId)),this._peerConnections[peerId].iceConnectionStateClosed||(this._peerConnections[peerId].iceConnectionStateClosed=!0,this._trigger("iceConnectionState",this.ICE_CONNECTION_STATE.CLOSED,peerId)))),"MCU"!==peerId&&this._handleEndedStreams(peerId),delete this._peerConnections[peerId]),this._peerInformations[peerId]&&delete this._peerInformations[peerId],this._peerMessagesStamps[peerId]&&delete this._peerMessagesStamps[peerId],this._streamsSession[peerId]&&delete this._streamsSession[peerId],this._peerEndOfCandidatesCounter[peerId]&&delete this._peerEndOfCandidatesCounter[peerId],this._peerCandidatesQueue[peerId]&&delete this._peerCandidatesQueue[peerId],this._sdpSessions[peerId]&&delete this._sdpSessions[peerId],this._peerStats[peerId]&&delete this._peerStats[peerId],this._peerBandwidth[peerId]&&delete this._peerBandwidth[peerId],this._gatheredCandidates[peerId]&&delete this._gatheredCandidates[peerId],this._peerCustomConfigs[peerId]&&delete this._peerCustomConfigs[peerId],this._peerConnStatus[peerId]&&delete this._peerConnStatus[peerId],this._dataChannels[peerId]&&this._closeDataChannel(peerId),log.log([peerId,"RTCPeerConnection",null,"Successfully removed peer"])},Skylink.prototype._createPeerConnection=function(targetMid,isScreenSharing,cert){var pc,self=this;if(self._inRoom&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)){var constraints={iceServers:self._room.connection.peerConfig.iceServers,iceTransportPolicy:self._initOptions.filterCandidatesType.host&&self._initOptions.filterCandidatesType.srflx&&!self._initOptions.filterCandidatesType.relay?"relay":"all",bundlePolicy:self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.NONE?self.BUNDLE_POLICY.BALANCED:self._peerConnectionConfig.bundlePolicy,rtcpMuxPolicy:self._peerConnectionConfig.rtcpMuxPolicy,iceCandidatePoolSize:self._peerConnectionConfig.iceCandidatePoolSize},optional={optional:[{DtlsSrtpKeyAgreement:!0},{googIPv6:!0}]};cert&&(constraints.certificates=[cert]),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].constraints=constraints,self._peerConnStatus[targetMid].optional=optional);try{log.debug([targetMid,"RTCPeerConnection",null,"Creating peer connection ->"],{constraints:constraints,optional:optional}),pc=new(self._initOptions.useEdgeWebRTC&&window.msRTCPeerConnection?window.msRTCPeerConnection:RTCPeerConnection)(constraints,optional)}catch(error){return log.error([targetMid,null,null,"Failed creating peer connection:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),null}pc.setOffer="",pc.setAnswer="",pc.hasStream=!1,pc.hasScreen=!!isScreenSharing,pc.hasMainChannel=!1,pc.firefoxStreamId="",pc.processingLocalSDP=!1,pc.processingRemoteSDP=!1,pc.gathered=!1,pc.gathering=!1,pc.localStream=null,pc.localStreamId=null,pc.remoteStream=null,pc.remoteStreamId=null,pc.iceConnectionStateClosed=!1,pc.signalingStateClosed=!1,self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}},self._streamsSession[targetMid]=self._streamsSession[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._sdpSessions[targetMid]={local:{},remote:{}},self._peerBandwidth[targetMid]={};var bandwidth=null;return pc.ondatachannel=function(event){var dc=event.channel||event;if(log.debug([targetMid,"RTCDataChannel",dc.label,"Received datachannel ->"],dc),self._initOptions.enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel){self.DATA_CHANNEL_TYPE.DATA,dc.label;pc.hasMainChannel||(self.DATA_CHANNEL_TYPE.MESSAGING,"main",pc.hasMainChannel=!0),self._createDataChannel(targetMid,dc)}else log.warn([targetMid,"RTCDataChannel",dc.label,"Not adding datachannel as enable datachannel is set to false"])},pc.onaddstream=function(evt){if(self._peerConnections[targetMid]){var stream=evt.stream||evt;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received empty remote stream ->"],stream);pc.remoteStream=stream,pc.remoteStreamId=pc.remoteStreamId||stream.id||stream.label;var peerSettings=clone(self.getPeerInfo(targetMid).settings);self._streamsSession[targetMid][pc.remoteStreamId]=peerSettings,0===stream.getAudioTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].audio=!1),0===stream.getVideoTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].video=!1),pc.hasStream=!0,pc.hasScreen=peerSettings.video&&"object"==typeof peerSettings.video&&peerSettings.video.screenshare,self._onRemoteStreamAdded(targetMid,stream,!!pc.hasScreen)}},pc.onicecandidate=function(event){self._onIceCandidate(targetMid,event.candidate||event)},pc.oniceconnectionstatechange=function(evt){var iceConnectionState=pc.iceConnectionState;if(log.debug([targetMid,"RTCIceConnectionState",null,"Ice connection state changed ->"],iceConnectionState),"edge"===AdapterJS.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),"AppleWebKit"===AdapterJS.webrtcDetectedType&&iceConnectionState===self.ICE_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.iceConnectionStateClosed||self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.CLOSED,targetMid)},10);if(self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._initOptions.enableIceTrickle&&self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.TRICKLE_FAILED,targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].connected=[self.ICE_CONNECTION_STATE.COMPLETED,self.ICE_CONNECTION_STATE.CONNECTED].indexOf(iceConnectionState)>-1),!self._hasMCU&&[self.ICE_CONNECTION_STATE.CONNECTED,self.ICE_CONNECTION_STATE.COMPLETED].indexOf(iceConnectionState)>-1&&self._bandwidthAdjuster&&!bandwidth&&"edge"!==AdapterJS.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),"AppleWebKit"===AdapterJS.webrtcDetectedType&&pc.signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.signalingStateClosed||self._trigger("peerConnectionState",self.PEER_CONNECTION_STATE.CLOSED,targetMid)},10);self._trigger("peerConnectionState",pc.signalingState,targetMid)},pc.onicegatheringstatechange=function(){log.log([targetMid,"RTCIceGatheringState",null,"Ice gathering state changed ->"],pc.iceGatheringState),self._trigger("candidateGenerationState",pc.iceGatheringState,targetMid)},"firefox"===AdapterJS.webrtcDetectedBrowser&&(pc.removeStream=function(stream){for(var senders=pc.getSenders(),s=0;s"],restartMsg),self._sendChannelMessage(restartMsg)};bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=bwOptions.googleXBandwidth.max));for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers},null):callback(null,{listOfPeers:listOfPeers}))};self.once("peerJoined",peerJoinedFn,function(peerId,peerInfo,isSelf){return isSelf}),self.leaveRoom(!1,function(error,success){if(error){if("function"==typeof callback){for(var i=0;i=self._peerEndOfCandidatesCounter[targetMid].expectedLen&&(!self._peerCandidatesQueue[targetMid]||0===self._peerCandidatesQueue[targetMid].length)&&!self._peerEndOfCandidatesCounter[targetMid].hasSet){log.debug([targetMid,"RTCPeerConnection",null,"Signaling of end-of-candidates remote ICE gathering."]),self._peerEndOfCandidatesCounter[targetMid].hasSet=!0;try{if("edge"===AdapterJS.webrtcDetectedBrowser){for(var mLineCounter=-1,addedMids=[],sdpLines=self._peerConnections[targetMid].remoteDescription.sdp.split("\r\n"),rejected=!1,i=0;i"],error)}}},Skylink.prototype.setUserData=function(userData){var self=this,updatedUserData="";void 0!==userData&&null!==userData&&(updatedUserData=userData),this._userData=updatedUserData,self._inRoom?(log.log("Updated userData -> ",updatedUserData),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.UPDATE_USER,mid:self._user.sid,rid:self._room.id,userData:updatedUserData,stamp:(new Date).getTime()}),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0)):log.warn("User is not in the room. Broadcast of updated information will be dropped")},Skylink.prototype.getUserData=function(peerId){if(peerId&&this._peerInformations[peerId]){var userData=this._peerInformations[peerId].userData;return null!==userData&&void 0===userData||(userData=""),userData}return this._userData},Skylink.prototype.getPeerInfo=function(peerId){var peerInfo=null;return"string"==typeof peerId&&"object"==typeof this._peerInformations[peerId]?(peerInfo=clone(this._peerInformations[peerId]),peerInfo.room=clone(this._selectedRoom),peerInfo.settings.bandwidth=peerInfo.settings.bandwidth||{},peerInfo.settings.googleXBandwidth=peerInfo.settings.googleXBandwidth||{},"boolean"==typeof peerInfo.settings.video||peerInfo.settings.video&&"object"==typeof peerInfo.settings.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"==typeof peerInfo.settings.audio||peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.audioMuted&&(peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.videoMuted&&(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.maxBandwidth&&(peerInfo.settings.bandwidth=clone(peerInfo.settings.maxBandwidth),delete peerInfo.settings.maxBandwidth),peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&peerInfo.settings.video.customSettings&&"object"==typeof peerInfo.settings.video.customSettings&&(peerInfo.settings.video.customSettings.frameRate&&(peerInfo.settings.video.frameRate=clone(peerInfo.settings.video.customSettings.frameRate)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode)),peerInfo.settings.video.customSettings.width&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.width=clone(peerInfo.settings.video.customSettings.width)),peerInfo.settings.video.customSettings.height&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.height=clone(peerInfo.settings.video.customSettings.height)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode))),peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&(peerInfo.settings.audio.stereo=!0===peerInfo.settings.audio.stereo),null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),peerInfo.parentId=peerInfo.parentId||null,"MCU"===peerId?(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1):this._hasMCU&&(peerInfo.config.receiveOnly=!1,peerInfo.config.publishOnly=!0),this._sdpSettings.direction.audio.receive||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.direction.video.receive||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.data=!!(this._dataChannels[peerId]&&this._dataChannels[peerId].main&&this._dataChannels[peerId].main.channel&&this._dataChannels[peerId].main.channel.readyState===this.DATA_CHANNEL_STATE.OPEN),peerInfo.connected=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].connected,peerInfo.init=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].init,this._sdpSessions[peerId]&&this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&"object"==typeof this._sdpSessions[peerId].remote.connection&&(this._sdpSessions[peerId].remote.connection.audio&&this._sdpSessions[peerId].remote.connection.audio.indexOf("send")>-1||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSessions[peerId].remote.connection.video&&this._sdpSessions[peerId].remote.connection.video.indexOf("send")>-1||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSessions[peerId].remote.connection.data&&this._sdpSessions[peerId].remote.connection.data.indexOf("send")>-1||(peerInfo.settings.data=!1))):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,os:window.navigator.platform,pluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:this.SMProtocolVersion,DTProtocolVersion:this.DTProtocolVersion},room:clone(this._selectedRoom),config:{enableDataChannel:this._initOptions.enableDataChannel,enableIceTrickle:this._initOptions.enableIceTrickle,enableIceRestart:this._enableIceRestart,priorityWeight:this._peerPriorityWeight,receiveOnly:!1,publishOnly:!!this._publishOnly},connected:null,init:null},null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),this._streams.screenshare?peerInfo.settings=clone(this._streams.screenshare.settings):this._streams.userMedia&&(peerInfo.settings=clone(this._streams.userMedia.settings)),peerInfo.settings.bandwidth=clone(this._streamsBandwidthSettings.bAS),peerInfo.settings.googleXBandwidth=clone(this._streamsBandwidthSettings.googleX),peerInfo.parentId=this._parentId?this._parentId:null,peerInfo.config.receiveOnly=!peerInfo.settings.video&&!peerInfo.settings.audio,peerInfo.settings.data=this._initOptions.enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._initOptions.codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._initOptions.codecParams.audio.opus.stereo),"boolean"==typeof this._initOptions.codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._initOptions.codecParams.audio.opus.usedtx),"number"==typeof this._initOptions.codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._initOptions.codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._initOptions.codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._initOptions.codecParams.audio.opus.useinbandfec))),peerInfo.settings.audio||(peerInfo.mediaStatus.audioMuted=!0),peerInfo.settings.video||(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.audio||peerInfo.settings.video||(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1),peerInfo},Skylink.prototype.getPeersInRoom=function(){for(var listOfPeersInfo={},listOfPeers=Object.keys(this._peerInformations),i=0;i-1||(customSettings.settings.audio=!1,customSettings.mediaStatus.audioMuted=!0),self._sdpSessions[usePeerId].local.connection.video&&self._sdpSessions[usePeerId].local.connection.video.indexOf("send")>-1||(customSettings.settings.video=!1,customSettings.mediaStatus.videoMuted=!0),self._sdpSessions[usePeerId].local.connection.data&&self._sdpSessions[usePeerId].local.connection.data.indexOf("send")>-1||(customSettings.settings.data=!1)),customSettings},Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo()),userCustomInfoForPeer=peerId?this._getPeerCustomSettings(peerId):null;return userCustomInfoForPeer&&"object"==typeof userCustomInfoForPeer&&(userInfo.settings=userCustomInfoForPeer.settings,userInfo.mediaStatus=userCustomInfoForPeer.mediaStatus),userInfo.settings.video&&"object"==typeof userInfo.settings.video&&(userInfo.settings.video.customSettings={},userInfo.settings.video.frameRate&&"object"==typeof userInfo.settings.video.frameRate&&(userInfo.settings.video.customSettings.frameRate=clone(userInfo.settings.video.frameRate),userInfo.settings.video.frameRate=-1),userInfo.settings.video.facingMode&&"object"==typeof userInfo.settings.video.facingMode&&(userInfo.settings.video.customSettings.facingMode=clone(userInfo.settings.video.facingMode),userInfo.settings.video.facingMode="-1"),userInfo.settings.video.resolution&&"object"==typeof userInfo.settings.video.resolution&&(userInfo.settings.video.resolution.width&&"object"==typeof userInfo.settings.video.resolution.width&&(userInfo.settings.video.customSettings.width=clone(userInfo.settings.video.width),userInfo.settings.video.resolution.width=-1),userInfo.settings.video.resolution.height&&"object"==typeof userInfo.settings.video.resolution.height&&(userInfo.settings.video.customSettings.height=clone(userInfo.settings.video.height),userInfo.settings.video.resolution.height=-1))),userInfo.settings.bandwidth&&(userInfo.settings.maxBandwidth=clone(userInfo.settings.bandwidth),delete userInfo.settings.bandwidth),this._getSDPCommonSupports(peerId).video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._getSDPCommonSupports(peerId).audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype._doOffer=function(targetMid,iceRestart){var self=this,pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of creating of offer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription","offer",'Dropping of creating of offer as signalingState is not "'+self.PEER_CONNECTION_STATE.STABLE+'" ->'],pc.signalingState);var offerConstraints={offerToReceiveAudio:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).video,offerToReceiveVideo:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).audio,iceRestart:!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,voiceActivityDetection:self._voiceActivityDetection};self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._initOptions.enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._dataChannels[targetMid]&&self._dataChannels[targetMid].main||(self._createDataChannel(targetMid),self._peerConnections[targetMid].hasMainChannel=!0)),log.debug([targetMid,null,null,"Creating offer with config:"],offerConstraints),pc.endOfCandidates=!1,self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=offerConstraints);var onSuccessCbFn=function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)};pc.createOffer(onSuccessCbFn,onErrorCbFn,"plugin"===AdapterJS.webrtcDetectedType?{mandatory:{OfferToReceiveAudio:offerConstraints.offerToReceiveAudio,OfferToReceiveVideo:offerConstraints.offerToReceiveVideo,iceRestart:offerConstraints.iceRestart,voiceActivityDetection:offerConstraints.voiceActivityDetection}}:offerConstraints)},Skylink.prototype._doAnswer=function(targetMid){var self=this;log.log([targetMid,null,null,"Creating answer with config:"],self._room.connection.sdpConstraints);var pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of creating of answer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription","answer",'Dropping of creating of answer as signalingState is not "'+self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER+'" ->'],pc.signalingState);var answerConstraints="edge"===AdapterJS.webrtcDetectedBrowser?{offerToReceiveVideo:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).video,offerToReceiveAudio:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).audio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints);var onSuccessCbFn=function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},onErrorCbFn=function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.createAnswer(onSuccessCbFn,onErrorCbFn,answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,_sessionDescription){var self=this,pc=self._peerConnections[targetMid];if(!_sessionDescription||!_sessionDescription.sdp)return void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],_sessionDescription);if(!pc)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as connection does not exists ->"],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(pc.processingLocalSDP)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as another is being processed ->"],_sessionDescription);pc.processingLocalSDP=!0;var sessionDescription={type:_sessionDescription.type,sdp:_sessionDescription.sdp};sessionDescription.sdp=self._removeSDPFirefoxH264Pref(targetMid,sessionDescription),sessionDescription.sdp=self._setSDPCodecParams(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPUnknownAptRtx(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPCodecs(targetMid,sessionDescription),sessionDescription.sdp=self._handleSDPConnectionSettings(targetMid,sessionDescription,"local"),sessionDescription.sdp=self._removeSDPREMBPackets(targetMid,sessionDescription),log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description updated ->"],sessionDescription.sdp);var onSuccessCbFn=function(){if(log.debug([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description has been set ->"],sessionDescription),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",sessionDescription.type,targetMid),sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER?pc.setAnswer="local":pc.setOffer="local",!self._initOptions.enableIceTrickle&&!pc.gathered)return void log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description sending is halted to complete ICE gathering."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},onErrorCbFn=function(error){log.error([targetMid,"RTCSessionDescription",sessionDescription.type,"Local description failed setting ->"],error),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.setLocalDescription(new RTCSessionDescription(sessionDescription),onSuccessCbFn,onErrorCbFn)},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._initOptions.appKey?("function"==typeof showAll&&(callback=showAll,showAll=!1),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.GET_PEERS,showAll:showAll||!1}),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.ENQUIRED,self._user.sid,null),log.log("Enquired server for peers within the realm"),void("function"==typeof callback&&self.once("getPeersStateChange",function(state,privilegedPeerId,peerList){callback(null,peerList)},function(state,privilegedPeerId,peerList){return state===self.GET_PEERS_STATE.RECEIVED}))):void log.warn("App key is not defined. Please authenticate again."):void log.warn("Please upgrade your key to privileged to use this function")},Skylink.prototype.introducePeer=function(sendingPeerId,receivingPeerId){var self=this;if(!self._isPrivileged)return log.warn("Please upgrade your key to privileged to use this function"),void self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,sendingPeerId,receivingPeerId,"notPrivileged");self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.INTRODUCE,sendingPeerId:sendingPeerId,receivingPeerId:receivingPeerId}),self._trigger("introduceStateChange",self.INTRODUCE_STATE.INTRODUCING,self._user.sid,sendingPeerId,receivingPeerId,null),log.log("Introducing",sendingPeerId,"to",receivingPeerId)},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._initOptions.defaultRoom,previousRoom=self._selectedRoom,mediaOptions={},timestamp=(new Date).getTime()+Math.floor(1e4*Math.random());self._joinRoomManager.timestamp=timestamp,room&&"string"==typeof room?selectedRoom=room:room&&"object"==typeof room?mediaOptions=room:"function"==typeof room&&(callback=room),options&&"object"==typeof options?mediaOptions=options:"function"==typeof options&&(callback=options);var resolveAsErrorFn=function(error,tryRoom,readyState){log.error(error),"function"==typeof callback&&callback({room:tryRoom,errorCode:readyState||null,error:error instanceof Error?error:new Error(JSON.stringify(error))})},joinRoomFn=function(){if(self._joinRoomManager.timestamp!==timestamp)return void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom);self._initSelectedRoom(selectedRoom,function(initError,initSuccess){return initError?void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState):self._joinRoomManager.timestamp!==timestamp?void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom):void self._waitForOpenChannel(mediaOptions||{},timestamp,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);if(self._joinRoomManager.timestamp!==timestamp)return void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom);if("AppleWebKit"===AdapterJS.webrtcDetectedType){var checkStream=self._streams.screenshare&&self._streams.screenshare.stream?self._streams.screenshare.stream:self._streams.userMedia&&self._streams.userMedia.stream?self._streams.userMedia.stream:null;checkStream&&0!==checkStream.getTracks().length?0===checkStream.getAudioTracks().length?log.warn("Note that receiving audio streams may fail as safari 11 needs stream with audio and video tracks and not just with video tracks"):0===checkStream.getVideoTracks().length&&log.warn("Note that receiving video streams may fail as safari 11 needs stream with audio and video tracks and not just with audio tracks"):log.warn("Note that receiving audio and video streams may fail as safari 11 needs stream with audio and video tracks")}if("function"==typeof callback){var peerOnJoin=function(peerId,peerInfo,isSelf){self.off("systemAction",peerFailedJoin),self.off("channelClose",peerSocketFailedJoin),log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo})},peerFailedJoin=function(action,message){self.off("peerJoined",peerOnJoin),self.off("channelClose",peerSocketFailedJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room ->"],message),
-resolveAsErrorFn(new Error(message),self._selectedRoom,self._readyState)},peerSocketFailedJoin=function(){self.off("systemAction",peerFailedJoin),self.off("peerJoined",peerOnJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room due to abrupt disconnection."]),resolveAsErrorFn(new Error("Channel closed abruptly before session was established"),self._selectedRoom,self._readyState)};self.once("peerJoined",peerOnJoin,function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),self.once("systemAction",peerFailedJoin,function(action){return action===self.SYSTEM_ACTION.REJECT}),self.once("channelClose",peerSocketFailedJoin)}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.JOIN_ROOM,uid:self._user.uid,cid:self._key,rid:self._room.id,userCred:self._user.token,timeStamp:self._user.timeStamp,apiOwner:self._appKeyOwner,roomCred:self._room.token,start:self._room.startDateTime,len:self._room.duration,isPrivileged:!0===self._isPrivileged,autoIntroduce:!1!==self._autoIntroduce,key:self._initOptions.appKey})})})};if(null===room||["number","boolean"].indexOf(typeof room)>-1)return void resolveAsErrorFn("Invalid room name is provided",room);if(null===options||["number","boolean"].indexOf(typeof options)>-1)return void resolveAsErrorFn("Invalid mediaOptions is provided",selectedRoom);self._joinRoomManager.socketsFn.forEach(function(fnItem){fnItem(timestamp)}),self._joinRoomManager.socketsFn=[];var stopStream=!1===mediaOptions.audio&&!1===mediaOptions.video;self._inRoom?self.leaveRoom({userMedia:stopStream},function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()}):(stopStream&&self.stopStream(),joinRoomFn())},Skylink.prototype.leaveRoom=function(stopMediaOptions,callback){var self=this,stopUserMedia=!0,stopScreenshare=!0,previousRoom=self._selectedRoom,previousUserPeerId=self._user?self._user.sid:null,peersThatLeft=[],isNotInRoom=!self._inRoom;"boolean"==typeof stopMediaOptions?!1===stopMediaOptions&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=!1!==stopMediaOptions.userMedia,stopScreenshare=!1!==stopMediaOptions.screenshare):"function"==typeof stopMediaOptions&&(callback=stopMediaOptions);for(var infoPeerId in self._peerInformations)self._peerInformations.hasOwnProperty(infoPeerId)&&self._peerInformations[infoPeerId]&&(peersThatLeft.push(infoPeerId),self._removePeer(infoPeerId));for(var connPeerId in self._peerConnections)self._peerConnections.hasOwnProperty(connPeerId)&&self._peerConnections[connPeerId]&&-1===peersThatLeft.indexOf(connPeerId)&&(peersThatLeft.push(connPeerId),self._removePeer(connPeerId));if(self._inRoom=!1,self._closeChannel(),isNotInRoom){var notInRoomError="Unable to leave room as user is not in any room";return log.error([null,"Room",previousRoom,notInRoomError]),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}self._stopStreams({userMedia:stopUserMedia,screenshare:stopScreenshare}),self._wait(function(){log.log([null,"Room",previousRoom,"User left the room"]),self._trigger("peerLeft",previousUserPeerId,self.getPeerInfo(),!0),"function"==typeof callback&&callback(null,{peerId:previousUserPeerId,previousRoom:previousRoom})},function(){return!self._channelOpen})},Skylink.prototype.lockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!0),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!0}),this._roomLocked=!0,this._trigger("roomLock",!0,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype.unlockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!1),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!1}),this._roomLocked=!1,this._trigger("roomLock",!1,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype._waitForOpenChannel=function(mediaOptions,joinRoomTimestamp,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){var onChannelOpen=function(){self.off("socketError",onChannelError),setTimeout(function(){if(mediaOptions=mediaOptions||{},self._userData=mediaOptions.userData||self._userData||"",self._streamsBandwidthSettings={googleX:{},bAS:{}},self._publishOnly=!1,self._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},self._voiceActivityDetection="boolean"!=typeof mediaOptions.voiceActivityDetection||mediaOptions.voiceActivityDetection,self._peerConnectionConfig={bundlePolicy:self.BUNDLE_POLICY.BALANCED,rtcpMuxPolicy:self.RTCP_MUX_POLICY.REQUIRE,iceCandidatePoolSize:0,certificate:self.PEER_CERTIFICATE.AUTO},self._bandwidthAdjuster=null,mediaOptions.bandwidth&&("number"==typeof mediaOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=mediaOptions.bandwidth.audio),"number"==typeof mediaOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=mediaOptions.bandwidth.video),"number"==typeof mediaOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=mediaOptions.bandwidth.data)),mediaOptions.googleXBandwidth&&("number"==typeof mediaOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=mediaOptions.googleXBandwidth.min),"number"==typeof mediaOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=mediaOptions.googleXBandwidth.max)),mediaOptions.sdpSettings&&(mediaOptions.sdpSettings.direction&&(mediaOptions.sdpSettings.direction.audio&&(self._sdpSettings.direction.audio.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.receive||mediaOptions.sdpSettings.direction.audio.receive,self._sdpSettings.direction.audio.send="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.send||mediaOptions.sdpSettings.direction.audio.send),mediaOptions.sdpSettings.direction.video&&(self._sdpSettings.direction.video.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.video.receive||mediaOptions.sdpSettings.direction.video.receive,self._sdpSettings.direction.video.send="boolean"!=typeof mediaOptions.sdpSettings.direction.video.send||mediaOptions.sdpSettings.direction.video.send)),mediaOptions.sdpSettings.connection&&(self._sdpSettings.connection.audio="boolean"!=typeof mediaOptions.sdpSettings.connection.audio||mediaOptions.sdpSettings.connection.audio,self._sdpSettings.connection.video="boolean"!=typeof mediaOptions.sdpSettings.connection.video||mediaOptions.sdpSettings.connection.video,self._sdpSettings.connection.data="boolean"!=typeof mediaOptions.sdpSettings.connection.data||mediaOptions.sdpSettings.connection.data)),mediaOptions.publishOnly&&(self._sdpSettings.direction.audio.send=!0,self._sdpSettings.direction.audio.receive=!1,self._sdpSettings.direction.video.send=!0,self._sdpSettings.direction.video.receive=!1,self._publishOnly=!0,"object"==typeof mediaOptions.publishOnly&&mediaOptions.publishOnly.parentId&&"string"==typeof mediaOptions.publishOnly.parentId&&(self._parentId=mediaOptions.publishOnly.parentId)),mediaOptions.parentId&&(self._parentId=mediaOptions.parentId),mediaOptions.peerConnection&&"object"==typeof mediaOptions.peerConnection){if("string"==typeof mediaOptions.peerConnection.bundlePolicy)for(var bpProp in self.BUNDLE_POLICY)self.BUNDLE_POLICY.hasOwnProperty(bpProp)&&self.BUNDLE_POLICY[bpProp]===mediaOptions.peerConnection.bundlePolicy&&(self._peerConnectionConfig.bundlePolicy=mediaOptions.peerConnection.bundlePolicy);if("string"==typeof mediaOptions.peerConnection.rtcpMuxPolicy)for(var rmpProp in self.RTCP_MUX_POLICY)self.RTCP_MUX_POLICY.hasOwnProperty(rmpProp)&&self.RTCP_MUX_POLICY[rmpProp]===mediaOptions.peerConnection.rtcpMuxPolicy&&(self._peerConnectionConfig.rtcpMuxPolicy=mediaOptions.peerConnection.rtcpMuxPolicy);if("number"==typeof mediaOptions.peerConnection.iceCandidatePoolSize&&mediaOptions.peerConnection.iceCandidatePoolSize>0&&(self._peerConnectionConfig.iceCandidatePoolSize=mediaOptions.peerConnection.iceCandidatePoolSize),"string"==typeof mediaOptions.peerConnection.certificate)for(var pcProp in self.PEER_CERTIFICATE)self.PEER_CERTIFICATE.hasOwnProperty(pcProp)&&self.PEER_CERTIFICATE[pcProp]===mediaOptions.peerConnection.certificate&&(self._peerConnectionConfig.certificate=mediaOptions.peerConnection.certificate)}if(mediaOptions.autoBandwidthAdjustment&&(self._bandwidthAdjuster={interval:10,limitAtPercentage:100,useUploadBwOnly:!1},"object"==typeof mediaOptions.autoBandwidthAdjustment&&("number"==typeof mediaOptions.autoBandwidthAdjustment.interval&&mediaOptions.autoBandwidthAdjustment.interval>=10&&(self._bandwidthAdjuster.interval=mediaOptions.autoBandwidthAdjustment.interval),"number"==typeof mediaOptions.autoBandwidthAdjustment.limitAtPercentage&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage>=0&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage<=100&&(self._bandwidthAdjuster.limitAtPercentage=mediaOptions.autoBandwidthAdjustment.limitAtPercentage),"boolean"==typeof mediaOptions.autoBandwidthAdjustment.useUploadBwOnly&&(self._bandwidthAdjuster.useUploadBwOnly=mediaOptions.autoBandwidthAdjustment.useUploadBwOnly))),!0===mediaOptions.manualGetUserMedia){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){!0===mediaAccessRequiredFailure?self._onUserMediaError(new Error("Waiting for stream timeout"),!1,!1):callback(null,self._streams.userMedia.stream)},function(){return current50Block+=1,600===current50Block?(mediaAccessRequiredFailure=!0,!0):!(!self._streams.userMedia||!self._streams.userMedia.stream)||void 0},50)}if(mediaOptions.audio||mediaOptions.video)return void self.getUserMedia({useExactConstraints:!!mediaOptions.useExactConstraints,audio:mediaOptions.audio,video:mediaOptions.video},function(error,success){error?callback(error,null):callback(null,success)});callback(null,null)},1)},onChannelError=function(errorState,error){self.off("channelOpen",onChannelOpen),callback(error)};self._channelOpen?onChannelOpen():(self.once("channelOpen",onChannelOpen),self.once("socketError",onChannelError,function(errorState){return errorState===self.SOCKET_ERROR.RECONNECTION_ABORTED}),self._openChannel(joinRoomTimestamp))},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.generateUUID=function(){var d=(new Date).getTime();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"===c?r:r&&15).toString(16)})},Skylink.prototype.init=function(_options,_callback){var self=this,options={},callback=function(){};if("function"==typeof _options?callback=_options:_options&&"object"==typeof _options?(options=clone(_options),options.appKey&&"string"==typeof options.appKey||!options.apiKey||"string"!=typeof options.apiKey||(options.appKey=options.apiKey)):_options&&"string"==typeof _options&&(options.appKey=_options),"function"==typeof _callback&&(callback=_callback),options.defaultRoom=options.defaultRoom&&"string"==typeof options.defaultRoom?options.defaultRoom:options.appKey,options.roomServer=options.roomServer&&"string"==typeof options.roomServer?options.roomServer:"//api.temasys.io",options.enableIceTrickle=!1!==options.enableIceTrickle,options.enableDataChannel=!1!==options.enableDataChannel,options.enableSTUNServer=!1!==options.enableSTUNServer,options.enableTURNServer=!1!==options.enableTURNServer,options.audioFallback=!0===options.audioFallback,options.forceSSL=!1!==options.forceSSL,options.socketTimeout="number"==typeof options.socketTimeout&&options.socketTimeout>=5e3?options.socketTimeout:7e3,options.apiTimeout="number"==typeof options.apiTimeout?options.apiTimeout:4e3,options.forceTURNSSL=!0===options.forceTURNSSL,options.forceTURN=!0===options.forceTURN,options.usePublicSTUN=!0===options.usePublicSTUN,options.disableVideoFecCodecs=!0===options.disableVideoFecCodecs,options.disableComfortNoiseCodec=!0===options.disableComfortNoiseCodec,options.disableREMB=!0===options.disableREMB,options.throttleShouldThrowError=!0===options.throttleShouldThrowError,options.mcuUseRenegoRestart=!0===options.mcuUseRenegoRestart,options.useEdgeWebRTC=!0===options.useEdgeWebRTC,options.enableSimultaneousTransfers=!1!==options.enableSimultaneousTransfers,options.priorityWeightScheme=self._containsInList("PRIORITY_WEIGHT_SCHEME",options.priorityWeightScheme,"AUTO"),options.TURNServerTransport=self._containsInList("TURN_TRANSPORT",options.TURNServerTransport,"ANY"),options.credentials=options.credentials&&"object"==typeof options.credentials&&options.credentials.startDateTime&&"string"==typeof options.credentials.startDateTime&&options.credentials.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration?options.credentials:null,options.filterCandidatesType=options.filterCandidatesType&&"object"==typeof options.filterCandidatesType?options.filterCandidatesType:{},options.filterCandidatesType.host=!0===options.filterCandidatesType.host,options.filterCandidatesType.srflx=!0===options.filterCandidatesType.srflx,options.filterCandidatesType.relay=!0===options.filterCandidatesType.relay,options.throttleIntervals=options.throttleIntervals&&"object"==typeof options.throttleIntervals?options.throttleIntervals:{},options.throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:1e4,options.throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:5e3,options.throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:0,options.iceServer&&"string"==typeof options.iceServer?options.iceServer={urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0?options.iceServer={urls:options.iceServer}:options.iceServer=null,options.socketServer&&"string"==typeof options.socketServer?options.socketServer=options.socketServer:options.socketServer&&"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url?options.socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)?options.socketServer.ports:[],protocol:options.socketServer.protocol?options.socketServer.protocol:null}:options.socketServer=null,options.audioCodec&&"object"==typeof options.audioCodec&&self._containsInList("AUDIO_CODEC",options.audioCodec.codec,"-")?options.audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels?options.audioCodec.channels:null}:options.audioCodec=self._containsInList("AUDIO_CODEC",options.audioCodec,"AUTO"),options.videoCodec&&"object"==typeof options.videoCodec&&self._containsInList("VIDEO_CODEC",options.videoCodec.codec,"-")?options.videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate?options.videoCodec.samplingRate:null}:options.videoCodec=self._containsInList("VIDEO_CODEC",options.videoCodec,"AUTO"),options.codecParams=options.codecParams&&"object"==typeof options.codecParams?options.codecParams:{},options.codecParams.audio=options.codecParams.audio&&"object"==typeof options.codecParams.audio?options.codecParams.audio:{},options.codecParams.video=options.codecParams.video&&"object"==typeof options.codecParams.video?options.codecParams.video:{},options.codecParams.audio.opus=options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus?options.codecParams.audio.opus:{},options.codecParams.audio.opus.stereo="boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,options.codecParams.audio.opus["sprop-stereo"]="boolean"==typeof options.codecParams.audio.opus["sprop-stereo"]?options.codecParams.audio.opus["sprop-stereo"]:null,options.codecParams.audio.opus.usedtx="boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,options.codecParams.audio.opus.useinbandfec="boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,options.codecParams.audio.opus.maxplaybackrate="number"==typeof options.codecParams.audio.opus.maxplaybackrate&&options.codecParams.audio.opus.maxplaybackrate>=8e3&&options.codecParams.audio.opus.maxplaybackrate<=48e3?options.codecParams.audio.opus.maxplaybackrate:null,options.codecParams.audio.opus.minptime="number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null,options.codecParams.video.h264=options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264?options.codecParams.video.h264:{},options.codecParams.video.h264.profileLevelId=options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,options.codecParams.video.h264.levelAsymmetryAllowed="boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,options.codecParams.video.h264.packetizationMode="boolean"==typeof options.codecParams.video.h264.packetizationMode?!0===options.codecParams.video.h264.packetizationMode?1:0:"number"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null,options.codecParams.video.vp8=options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8?options.codecParams.video.vp8:{},options.codecParams.video.vp8.maxFs="number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,options.codecParams.video.vp8.maxFr="number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null,options.codecParams.video.vp9=options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9?options.codecParams.video.vp9:{},options.codecParams.video.vp9.maxFs="number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,options.codecParams.video.vp9.maxFr="number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null,options.forceTURN&&(options.enableTURNServer=!0,options.enableSTUNServer=!1,options.filterCandidatesType.host=!0,options.filterCandidatesType.srflx=!0,options.filterCandidatesType.relay=!1),self.once("readyStateChange",function(){},function(state,error){if(state===self.READY_STATE_CHANGE.ERROR)return log.error("Failed init() process ->",error),callback({error:error.content,errorCode:error.errorCode,status:error.status},null),!0;if(state===self.READY_STATE_CHANGE.COMPLETED){log.info("Completed init() successfully ->",options);var success=clone(self._initOptions);return success.serverUrl=self._path,success.readyState=self._readyState,success.selectedRoom=self._selectedRoom,success.TURNTransport=success.TURNServerTransport,callback(null,success),!0}}),self._initOptions=options,self._readyState=self.READY_STATE_CHANGE.INIT,self._selectedRoom=self._initOptions.defaultRoom,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),!options||!options.appKey||"string"!=typeof options.appKey)return self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{content:new Error("Please provide an app key"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH,status:-2},self._selectedRoom);self._path=self._initOptions.roomServer+"/api/"+self._initOptions.appKey+"/"+self._selectedRoom+(self._initOptions.credentials?"/"+self._initOptions.credentials.startDateTime+"/"+self._initOptions.credentials.duration+"?cred="+self._initOptions.credentials.credentials:"")+(self._initOptions.credentials?"&":"?")+"rand="+Date.now(),self._loadInfo()},Skylink.prototype._containsInList=function(listName,value,defaultProperty){var self=this;for(var property in self[listName])if(self[listName].hasOwnProperty(property)&&self[listName][property]===value)return value;return self[listName][defaultProperty]},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,retries=0;self._socketUseXDR="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest,url=self._initOptions.forceSSL?"https:"+url:url,function requestFn(){var xhr=new XMLHttpRequest,completed=!1;self._socketUseXDR&&(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest for CORS authentication."]),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}),xhr.onload=function(){if(!completed){completed=!0;var response=JSON.parse(xhr.responseText||xhr.response||"{}"),status=xhr.status||(response.success?200:400);if(response.success)return log.debug([null,"XMLHttpRequest",method,"Received sessions parameters ->"],response),void callback(response);log.error([null,"XMLHttpRequest",method,"Failed retrieving sessions parameters ->"],response),self._readyState=self.READY_STATE_CHANGE.ERROR,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:new Error(response.info||"XMLHttpRequest status not OK\nStatus was: "+status),errorCode:response.error||status},self._selectedRoom)}},xhr.onerror=function(error){completed||(completed=!0,log.error([null,"XMLHttpRequest",method,"Failed retrieving information with status ->"],xhr.status),self._readyState=self.READY_STATE_CHANGE.ERROR,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||-1,content:new Error("Network error occurred. (Status: "+xhr.status+")"),errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom))},xhr.onprogress=function(){log.debug([null,"XMLHttpRequest",method,"Retrieving information and config from webserver ->"],{url:url,params:params})};try{xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()}catch(error){return completed=!0,self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||-1,content:new Error("Failed starting XHR process."),errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom)}setTimeout(function(){completed||(completed=!0,xhr.onload=null,xhr.onerror=null,xhr.onprogress=null,retries<2?(retries++,requestFn()):(self._readyState=self.READY_STATE_CHANGE.ERROR,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||-1,content:new Error("Response timed out from API server"),errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_NO_REPONSE_ERROR},self._selectedRoom)))},self._initOptions.apiTimeout)}()},Skylink.prototype._parseInfo=function(info){if(log.log("Parsing parameter from server",info),!info.pc_constraints&&!info.offer_constraints)return void this._trigger("readyStateChange",this.READY_STATE_CHANGE.ERROR,{status:200,content:info.info,errorCode:info.error},self._selectedRoom);log.debug("Peer connection constraints:",info.pc_constraints),log.debug("Offer constraints:",info.offer_constraints),this._key=info.cid,this._appKeyOwner=info.apiOwner,this._signalingServer=info.ipSigserver,this._isPrivileged=info.isPrivileged,this._autoIntroduce=info.autoIntroduce,this._user={uid:info.username,token:info.userCred,timeStamp:info.timeStamp,streams:[],info:{}},this._room={id:info.room_key,token:info.roomCred,startDateTime:info.start,duration:info.len,connection:{peerConstraints:JSON.parse(info.pc_constraints),peerConfig:null,offerConstraints:JSON.parse(info.offer_constraints),sdpConstraints:{mandatory:{OfferToReceiveAudio:!0,OfferToReceiveVideo:!0}},mediaConstraints:JSON.parse(info.media_constraints)}},this._socketPorts={"http:":Array.isArray(info.httpPortList)&&info.httpPortList.length>0?info.httpPortList:[80,3e3],"https:":Array.isArray(info.httpsPortList)&&info.httpsPortList.length>0?info.httpsPortList:[443,3443]},this._readyState=this.READY_STATE_CHANGE.COMPLETED,this._trigger("readyStateChange",this.READY_STATE_CHANGE.COMPLETED,null,this._selectedRoom),log.info("Parsed parameters from webserver. Ready for web-realtime communication")},Skylink.prototype._loadInfo=function(){var self=this;if("function"!=typeof(globals.AdapterJS||window.AdapterJS||{}).webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used"),errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return globals.io||window.io?window.XMLHttpRequest?self._path?void AdapterJS.webRTCReady(function(){if(self._enableIceRestart="firefox"!==AdapterJS.webrtcDetectedBrowser||AdapterJS.webrtcDetectedVersion>=48,self._binaryChunkType="firefox"===AdapterJS.webrtcDetectedBrowser?self.DATA_TRANSFER_DATA_TYPE.BLOB:self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&"plugin"===AdapterJS.webrtcDetectedType?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("plugin"===AdapterJS.webrtcDetectedType&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error(error.message||error.toString()),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):0===Object.keys(self._currentCodecSupport.audio).length&&0===Object.keys(self._currentCodecSupport.video).length?(log.error("No audio/video codecs available to start connection."),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("No audio/video codecs available to start connection"),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=self.READY_STATE_CHANGE.LOADING,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(response){self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("No API Path is found"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH},self._selectedRoom)):(log.error("XMLHttpRequest not supported. Please upgrade your browser"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("XMLHttpRequest not available"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_XMLHTTPREQUEST_SUPPORT},self._selectedRoom)):(log.error("Socket.io not loaded. Please load socket.io"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("Socket.io not found"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_SOCKET_IO},self._selectedRoom))},Skylink.prototype._initSelectedRoom=function(room,callback){var self=this;if("function"==typeof room||void 0===room)return log.error("Invalid room provided. Room:",room),void callback(new Error("Invalid room provided"),null);var defaultRoom=self._initOptions.defaultRoom,options=clone(self._initOptions);options.iceServer=options.iceServer?options.iceServer.urls:null,options.defaultRoom!==room&&(options.defaultRoom=room),self.init(options,function(error,success){self._initOptions.defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})};var _LOG_KEY="SkylinkJS",_LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!1,_printTimestamp=!1,_storedLogs=[],_getStoredLogsFn=function(logLevel){if(void 0===logLevel)return _storedLogs;for(var returnLogs=[],i=0;i<_storedLogs.length;i++)_storedLogs[i][1]===_LOG_LEVELS[logLevel]&&returnLogs.push(_storedLogs[i]);return returnLogs},_clearAllStoredLogsFn=function(){_storedLogs=[]},_printAllStoredLogsFn=function(){for(var i=0;i<_storedLogs.length;i++){var timestamp=_storedLogs[i][0],log="undefined"!==console[_storedLogs[i][1]]?_storedLogs[i][1]:"log",message=_storedLogs[i][2],debugObject=_storedLogs[i][3];void 0!==debugObject?console[log](message,debugObject,timestamp):console[log](message,timestamp)}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="",datetime=new Date;if("object"==typeof message){if(outputLog+=message[0]?" ["+message[0]+"] -":" -",outputLog+=message[1]?" <<"+message[1]+">>":"",message[2])if(outputLog+=" ","object"==typeof message[2])for(var i=0;i=logLevel)if(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace){void 0===console.trace&&logLevel[3];void 0!==debugObject?(console[_LOG_LEVELS[logLevel]](outputLog,debugObject),void 0!==console.trace&&console.trace("")):(console[_LOG_LEVELS[logLevel]](outputLog),void 0!==console.trace&&console.trace(""))}else void 0!==debugObject?console[_LOG_LEVELS[logLevel]](outputLog,debugObject):console[_LOG_LEVELS[logLevel]](outputLog)},log={debug:function(message,object){_logFn(4,message,object)},log:function(message,object){_logFn(3,message,object)},info:function(message,object){_logFn(2,message,object)},warn:function(message,object){_logFn(1,message,object)},error:function(message,object){_logFn(0,message,object)}};Skylink.prototype.setLogLevel=function(logLevel){for(var level in this.LOG_LEVEL)if(this.LOG_LEVEL[level]===logLevel)return _logLevel=logLevel,void log.log([null,"Log",level,"Log level exists. Level is set"]);log.error([null,"Log",level,"Log level does not exist. Level is not set"])},Skylink.prototype.setDebugMode=function(isDebugMode){isDebugMode&&"object"==typeof isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0===isDebugMode.trace,_enableDebugStack=!0===isDebugMode.storeLogs,_printTimestamp=!0===isDebugMode.printTimestamp):!0===isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0,_printTimestamp=!1):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1,_printTimestamp=!1)};Skylink.prototype.on=function(eventName,callback){"function"==typeof callback?(this._EVENTS[eventName]=this._EVENTS[eventName]||[],this._EVENTS[eventName].push(callback),log.log([null,"Event",eventName,"Event is subscribed"])):log.error([null,"Event",eventName,"Provided parameter is not a function"])},Skylink.prototype.once=function(eventName,callback,condition,fireAlways){"boolean"==typeof condition&&(fireAlways=condition,condition=null),fireAlways=void 0!==fireAlways&&fireAlways,condition="function"!=typeof condition?function(){
-return!0}:condition,"function"==typeof callback?(this._onceEvents[eventName]=this._onceEvents[eventName]||[],this._onceEvents[eventName].push([callback,condition,fireAlways]),log.log([null,"Event",eventName,"Event is subscribed on condition"])):log.error([null,"Event",eventName,"Provided callback is not a function"])},Skylink.prototype.off=function(eventName,callback){if(eventName&&"string"==typeof eventName){if(void 0===callback)return this._EVENTS[eventName]=[],this._onceEvents[eventName]=[],void log.log([null,"Event",eventName,"All events are unsubscribed"]);for(var arr=this._EVENTS[eventName]||[],once=this._onceEvents[eventName]||[],i=0;i"],message);self._user.sid&&!self._peerMessagesStamps[self._user.sid]&&(self._peerMessagesStamps[self._user.sid]={userData:0,audioMuted:0,videoMuted:0});var checkStampFn=function(statusMessage){return statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].userData:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].videoMuted:statusMessage.type!==self._SIG_MESSAGE_TYPE.MUTE_AUDIO||!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].audioMuted},setStampFn=function(statusMessage){statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?self._peerMessagesStamps[self._user.sid].userData=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?self._peerMessagesStamps[self._user.sid].videoMuted=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&(self._peerMessagesStamps[self._user.sid].audioMuted=statusMessage.stamp)},setQueueFn=function(){log.debug([null,"Socket",null,"Starting queue timeout"]),self._socketMessageTimeout=setTimeout(function(){if((new Date).getTime()-self._timestamp.socketMessage<=interval)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},interval-((new Date).getTime()-self._timestamp.socketMessage))},triggerEventFn=function(eventMessage){eventMessage.type===self._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE&&self._trigger("incomingMessage",{content:eventMessage.data,isPrivate:!1,targetPeerId:null,listOfPeers:Object.keys(self._peerInformations),isDataChannel:!1,senderPeerId:self._user.sid},self._user.sid,self.getPeerInfo(),!0)},sendGroupMessageFn=function(groupMessageList){if(self._socketMessageTimeout=null,!(self._channelOpen&&self._user&&self._user.sid&&self._socket))return void log.warn([message.target||"Server","Socket",null,"Dropping of group messages as Socket connection is not opened or is at incorrect step ->"],groupMessageList);for(var strGroupMessageList=[],stamps={userData:0,audioMuted:0,videoMuted:0},k=0;kself._peerMessagesStamps[self._user.sid].userData&&groupMessageList[k].stamp>stamps.userData?stamps.userData=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].audioMuted&&groupMessageList[k].stamp>stamps.audioMuted?stamps.audioMuted=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].videoMuted&&groupMessageList[k].stamp>stamps.videoMuted&&(stamps.videoMuted=groupMessageList[k].stamp));for(var i=0;i"],clone(groupMessageList[i])),groupMessageList.splice(i,1),i--):strGroupMessageList.push(JSON.stringify(groupMessageList[i]));if(strGroupMessageList.length>0){var groupMessage={type:self._SIG_MESSAGE_TYPE.GROUP,lists:strGroupMessageList,mid:self._user.sid,rid:self._room.id};log.log([message.target||"Server","Socket",groupMessage.type,"Sending queued grouped message (max: 16 per group) ->"],clone(groupMessage)),self._socket.send(JSON.stringify(groupMessage)),self._timestamp.socketMessage=(new Date).getTime();for(var j=0;j0&&(self._socketMessageQueue.length-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=interval)log.debug([message.target||"Server","Socket",message.type,"Queueing socket message to prevent message drop ->"],clone(message)),self._socketMessageQueue.push(message),self._socketMessageTimeout||setQueueFn();else{if(!checkStampFn(message))return void log.warn([message.target||"Server","Socket",message.type,"Dropping of outdated status message ->"],clone(message));self._socketMessageTimeout&&clearTimeout(self._socketMessageTimeout),log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),setStampFn(message),triggerEventFn(message),self._timestamp.socketMessage=(new Date).getTime()}else log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),message.type===self._SIG_MESSAGE_TYPE.BYE&&self._inRoom&&self._user&&self._user.sid&&message.mid===self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo()))},Skylink.prototype._createSocket=function(type,joinRoomTimestamp){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._initOptions.socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._initOptions.socketServer&&"object"==typeof self._initOptions.socketServer&&Array.isArray(self._initOptions.socketServer.ports)&&self._initOptions.socketServer.ports.length>0?self._initOptions.socketServer.ports:self._socketPorts[self._signalingServerProtocol],fallbackType=null;null===self._signalingServerPort?(self._signalingServerPort=ports[0],fallbackType=self.SOCKET_FALLBACK.NON_FALLBACK):ports.indexOf(self._signalingServerPort)===ports.length-1||"string"==typeof self._initOptions.socketServer?"WebSocket"===type?(type="Polling",self._signalingServerPort=ports[0]):self._socketSession.finalAttempts++:self._signalingServerPort=ports[ports.indexOf(self._signalingServerPort)+1],"Polling"===type&&(options.reconnectionDelayMax=1e3,options.reconnectionAttempts=4,options.transports=["xhr-polling","jsonp-polling","polling"]);var url=self._signalingServerProtocol+"//"+self._signalingServer+":"+self._signalingServerPort+"?rand="+Date.now(),retries=0;self._initOptions.socketServer&&(url="string"==typeof self._initOptions.socketServer?self._initOptions.socketServer:(self._initOptions.socketServer.protocol?self._initOptions.socketServer.protocol:self._signalingServerProtocol)+"//"+self._initOptions.socketServer.url+":"+self._signalingServerPort),self._socketSession.transportType=type,self._socketSession.socketOptions=options,self._socketSession.socketServer=url,null===fallbackType&&(fallbackType="http:"===self._signalingServerProtocol?"Polling"===type?self.SOCKET_FALLBACK.LONG_POLLING:self.SOCKET_FALLBACK.FALLBACK_PORT:"Polling"===type?self.SOCKET_FALLBACK.LONG_POLLING_SSL:self.SOCKET_FALLBACK.FALLBACK_SSL_PORT,self._socketSession.attempts++,self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ATTEMPT,null,fallbackType,clone(self._socketSession)),self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))),self._socket&&self._closeChannel(),self._channelOpen=!1,log.log("Opening channel with signaling server url:",clone(self._socketSession));var socket=null;try{socket=io.connect(url,options)}catch(error){return log.error("Failed creating socket connection object ->",error),fallbackType===self.SOCKET_FALLBACK.NON_FALLBACK?self._trigger("socketError",self.SOCKET_ERROR.CONNECTION_FAILED,error,fallbackType,clone(self._socketSession)):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_FAILED,error,fallbackType,clone(self._socketSession)),void self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ABORTED,new Error("Reconnection aborted as there no more available ports, transports and final attempts left."),fallbackType,clone(self._socketSession))}socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),socket.on("reconnect_failed",function(){fallbackType===self.SOCKET_FALLBACK.NON_FALLBACK?self._trigger("socketError",self.SOCKET_ERROR.CONNECTION_FAILED,new Error('Failed connection with transport "'+type+'" and port '+self._signalingServerPort+"."),fallbackType,clone(self._socketSession)):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_FAILED,new Error('Failed reconnection with transport "'+type+'" and port '+self._signalingServerPort+"."),fallbackType,clone(self._socketSession)),self._socketSession.finalAttempts<2?self._createSocket(type,joinRoomTimestamp):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ABORTED,new Error("Reconnection aborted as there no more available ports, transports and final attempts left."),fallbackType,clone(self._socketSession))}),socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),socket.on("error",function(error){if(error&&error.message.indexOf("xhr poll error")>-1)return log.error([null,"Socket",null,"XHR poll connection unstable. Disconnecting.. ->"],error),void self._closeChannel();log.error([null,"Socket",null,"Exception occurred ->"],error),self._trigger("channelError",error,clone(self._socketSession))}),socket.on("disconnect",function(){self._channelOpen&&(self._channelOpen=!1,self._trigger("channelClose",clone(self._socketSession)),log.log([null,"Socket",null,"Channel closed"]),self._inRoom&&self._user&&self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo())))}),socket.on("message",function(messageStr){var message=JSON.parse(messageStr);if(log.log([null,"Socket",null,"Received message ->"],message),message.type===self._SIG_MESSAGE_TYPE.GROUP){log.debug("Bundle of "+message.lists.length+" messages");for(var i=0;i",message);for(var i=0;i-1:state===self.RECORDING_STATE.STOP})}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.STOP_RECORDING,rid:self._room.id,target:"MCU"}),log.debug(["MCU","Recording",null,"Stopping recording"])},Skylink.prototype.getRecordings=function(){return clone(this._recordings)},Skylink.prototype._processSigMessage=function(message,session){var origin=message.mid;if(origin&&origin!==this._user.sid||(origin="Server"),log.debug([origin,"Socket",message.type,"Received from peer ->"],clone(message)),message.mid===this._user.sid&&message.type!==this._SIG_MESSAGE_TYPE.REDIRECT&&message.type!==this._SIG_MESSAGE_TYPE.IN_ROOM)return void log.debug([origin,"Socket",message.type,"Ignoring message ->"],clone(message));switch(message.type){case this._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE:this._publicMessageHandler(message);break;case this._SIG_MESSAGE_TYPE.PRIVATE_MESSAGE:this._privateMessageHandler(message);break;case this._SIG_MESSAGE_TYPE.IN_ROOM:this._inRoomHandler(message);break;case this._SIG_MESSAGE_TYPE.ENTER:this._enterHandler(message);break;case this._SIG_MESSAGE_TYPE.WELCOME:this._welcomeHandler(message);break;case this._SIG_MESSAGE_TYPE.RESTART:this._restartHandler(message);break;case this._SIG_MESSAGE_TYPE.OFFER:this._offerHandler(message);break;case this._SIG_MESSAGE_TYPE.ANSWER:this._answerHandler(message);break;case this._SIG_MESSAGE_TYPE.CANDIDATE:this._candidateHandler(message);break;case this._SIG_MESSAGE_TYPE.BYE:this._byeHandler(message);break;case this._SIG_MESSAGE_TYPE.REDIRECT:this._redirectHandler(message);break;case this._SIG_MESSAGE_TYPE.UPDATE_USER:this._updateUserEventHandler(message);break;case this._SIG_MESSAGE_TYPE.MUTE_VIDEO:this._muteVideoEventHandler(message);break;case this._SIG_MESSAGE_TYPE.MUTE_AUDIO:this._muteAudioEventHandler(message);break;case this._SIG_MESSAGE_TYPE.STREAM:this._streamEventHandler(message);break;case this._SIG_MESSAGE_TYPE.ROOM_LOCK:this._roomLockEventHandler(message);break;case this._SIG_MESSAGE_TYPE.PEER_LIST:this._peerListEventHandler(message);break;case this._SIG_MESSAGE_TYPE.INTRODUCE_ERROR:this._introduceErrorEventHandler(message);break;case this._SIG_MESSAGE_TYPE.APPROACH:this._approachEventHandler(message);break;case this._SIG_MESSAGE_TYPE.RECORDING:this._recordingEventHandler(message);break;case this._SIG_MESSAGE_TYPE.END_OF_CANDIDATES:this._endOfCandidatesHandler(message);break;default:log.error([message.mid,"Socket",message.type,"Unsupported message ->"],clone(message))}},Skylink.prototype._peerListEventHandler=function(message){var self=this;self._peerList=message.result,log.log(["Server",null,message.type,"Received list of peers"],self._peerList),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.RECEIVED,self._user.sid,self._peerList)},Skylink.prototype._endOfCandidatesHandler=function(message){var self=this,targetMid=message.mid;self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&(self._peerEndOfCandidatesCounter[targetMid].expectedLen=message.noOfExpectedCandidates||0,self._signalingEndOfCandidates(targetMid))},Skylink.prototype._introduceErrorEventHandler=function(message){var self=this;log.log(["Server",null,message.type,"Introduce failed. Reason: "+message.reason]),self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,message.sendingPeerId,message.receivingPeerId,message.reason)},Skylink.prototype._approachEventHandler=function(message){var self=this;log.log(["Server",null,message.type,"Approaching peer"],message.target),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._redirectHandler=function(message){if(log.log(["Server",null,message.type,"System action warning:"],{message:message.info,reason:message.reason,action:message.action}),message.action===this.SYSTEM_ACTION.REJECT)for(var key in this._peerConnections)this._peerConnections.hasOwnProperty(key)&&this._removePeer(key);"toClose"===message.reason&&(message.reason="toclose"),this._trigger("systemAction",message.action,message.info,message.reason)},Skylink.prototype._updateUserEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer updated userData:"],message.userData),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].userData=message.stamp}this._peerInformations[targetMid].userData=message.userData||{},this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._roomLockEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,message.type,"Room lock status:"],message.lock),this._trigger("roomLock",message.lock,targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._muteAudioEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's audio muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].audioMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.audioMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,message.type,"Peer does not have any user information"])},Skylink.prototype._muteVideoEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's video muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].videoMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.videoMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._streamEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Peer's stream status:"],message.status),this._peerInformations[targetMid]&&message.streamId?(this._streamsSession[targetMid]=this._streamsSession[targetMid]||{},"ended"===message.status&&(message.settings&&"object"==typeof message.settings&&void 0===this._streamsSession[targetMid][message.streamId]&&(this._streamsSession[targetMid][message.streamId]={audio:message.settings.audio,video:message.settings.video}),this._handleEndedStreams(targetMid,message.streamId))):log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._byeHandler=function(message){var targetMid=message.mid;(this._user||{}).sid!==targetMid?(log.log([targetMid,null,message.type,"Peer has left the room"]),this._removePeer(targetMid)):log.log([targetMid,null,message.type,"Self has left the room"])},Skylink.prototype._privateMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received private message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!0,targetPeerId:message.target,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._publicMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received public message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!1,targetPeerId:null,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._recordingEventHandler=function(message){var self=this;if(log.debug(["MCU","Recording",null,"Received recording message ->"],message),"on"===message.action)self._recordings[message.recordingId]||(log.debug(["MCU","Recording",message.recordingId,"Started recording"]),self._currentRecordingId=message.recordingId,self._recordings[message.recordingId]={active:!0,state:self.RECORDING_STATE.START,startedDateTime:(new Date).toISOString(),endedDateTime:null,mixingDateTime:null,links:null,error:null},self._recordingStartInterval=setTimeout(function(){log.log(["MCU","Recording",message.recordingId,"4 seconds has been recorded. Recording can be stopped now"]),self._recordingStartInterval=null},4e3),self._trigger("recordingState",self.RECORDING_STATE.START,message.recordingId,null,null));else if("off"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,'Received request of "off" but the session is empty']);self._currentRecordingId=null,self._recordingStartInterval&&(clearTimeout(self._recordingStartInterval),log.warn(["MCU","Recording",message.recordingId,"Recording stopped abruptly before 4 seconds"]),self._recordingStartInterval=null),log.debug(["MCU","Recording",message.recordingId,"Stopped recording"]),self._recordings[message.recordingId].active=!1,self._recordings[message.recordingId].state=self.RECORDING_STATE.STOP,self._recordings[message.recordingId].endedDateTime=(new Date).toISOString(),self._trigger("recordingState",self.RECORDING_STATE.STOP,message.recordingId,null,null)}else if("url"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,"Received URL but the session is empty"]);var links={};if(Array.isArray(message.urls))for(var i=0;i"],recordingError);log.error(["MCU","Recording",message.recordingId,"Recording failure ->"],recordingError),self._recordings[message.recordingId].state=self.RECORDING_STATE.ERROR,self._recordings[message.recordingId].error=recordingError,
-self._recordings[message.recordingId].active&&(log.debug(["MCU","Recording",message.recordingId,"Stopped recording abruptly"]),self._recordings[message.recordingId].active=!1),self._trigger("recordingState",self.RECORDING_STATE.ERROR,message.recordingId,null,recordingError)}},Skylink.prototype._inRoomHandler=function(message){var self=this;log.log(["Server",null,message.type,"User is now in the room and functionalities are now available. Config received:"],message.pc_config),self._room.connection.peerConfig=self._setIceServers((message.pc_config||{}).iceServers||[]),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._initOptions.priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._initOptions.priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.ENFORCE_OFFERER?2e15:-2e15),self._trigger("peerJoined",self._user.sid,self.getPeerInfo(),!0),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var streamId=null;self._streams.screenshare&&self._streams.screenshare.stream?(streamId=self._streams.screenshare.stream.id||self._streams.screenshare.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.screenshare.stream,!0,self.getPeerInfo(),!0,streamId)):self._streams.userMedia&&self._streams.userMedia.stream&&(streamId=self._streams.userMedia.stream.id||self._streams.userMedia.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.userMedia.stream,!0,self.getPeerInfo(),!1,streamId));var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._enterHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "enter" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid)}self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0};var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),receiveOnly:self.getPeerInfo().config.receiveOnly,os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg),isNewPeer&&self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._restartHandler=function(message){var self=this,targetMid=message.mid,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "restart" received ->'],message),!self._peerInformations[targetMid])return void log.error([targetMid,"RTCPeerConnection",null,"Peer does not have an existing session. Ignoring restart process."]);if("MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId or publishOnly case ->'],message);if(self._hasMCU&&!self._initOptions.mcuUseRenegoRestart)return log.warn([targetMid,"RTCPeerConnection",null,"Dropping restart request as MCU does not support re-negotiation. Restart workaround is to re-join Room for Peer."]),void self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!1);if(self._peerInformations[targetMid]=userInfo,self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid].len=0,self._peerPriorityWeight>message.weight){if(log.debug([targetMid,"RTCPeerConnection",null,"Re-negotiating new offer/answer."]),self._peerMessagesStamps[targetMid].hasRestart)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "restart" received.']);self._peerMessagesStamps[targetMid].hasRestart=!0,self._doOffer(targetMid,!0===message.doIceRestart,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start re-negotiation."]);var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===message.doIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,isRestartResend:!0,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._sendChannelMessage(restartMsg)}self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!0===message.doIceRestart)},Skylink.prototype._welcomeHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "welcome" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)}if(self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0,hasWelcome:!1},self._hasMCU||self._peerPriorityWeight>message.weight){if(self._peerMessagesStamps[targetMid].hasWelcome)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "welcome" received.']);log.debug([targetMid,"RTCPeerConnection",null,"Starting negotiation"]),self._peerMessagesStamps[targetMid].hasWelcome=!0,self._doOffer(targetMid,!1,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start negotiation."]);var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg)}};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._offerHandler=function(message){var self=this,targetMid=message.mid,pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for offer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}log.log([targetMid,null,message.type,"Received offer from peer. Session description:"],clone(message));var offer={type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],offer),offer.sdp=self._removeSDPFilteredCandidates(targetMid,offer),offer.sdp=self._setSDPCodec(targetMid,offer),offer.sdp=self._setSDPBitrate(targetMid,offer),offer.sdp=self._setSDPCodecParams(targetMid,offer),offer.sdp=self._removeSDPCodecs(targetMid,offer),offer.sdp=self._removeSDPREMBPackets(targetMid,offer),offer.sdp=self._handleSDPConnectionSettings(targetMid,offer,"remote"),offer.sdp=self._removeSDPUnknownAptRtx(targetMid,offer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "stable" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.resend});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,offer);var onSuccessCbFn=function(){log.debug([targetMid,"RTCSessionDescription",message.type,"Remote description set"]),pc.setOffer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.OFFER,targetMid),self._addIceCandidateFromQueue(targetMid),self._doAnswer(targetMid)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,offer:offer})};pc.setRemoteDescription(new RTCSessionDescription(offer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._candidateHandler=function(message){var targetMid=message.mid;if(!message.candidate&&!message.id)return void log.warn([targetMid,"RTCIceCandidate",null,"Received invalid ICE candidate message ->"],message);var canId="can-"+(new Date).getTime(),candidateType=message.candidate.split(" ")[7]||"",candidate=new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate,sdpMid:message.id});if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Received ICE candidate ->"],candidate),this._peerEndOfCandidatesCounter[targetMid]=this._peerEndOfCandidatesCounter[targetMid]||{},this._peerEndOfCandidatesCounter[targetMid].len=this._peerEndOfCandidatesCounter[targetMid].len||0,this._peerEndOfCandidatesCounter[targetMid].hasSet=!1,this._peerEndOfCandidatesCounter[targetMid].len++,this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.RECEIVED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!this._peerConnections[targetMid]||this._peerConnections[targetMid].signalingState===this.PEER_CONNECTION_STATE.CLOSED)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed.")),void this._signalingEndOfCandidates(targetMid);if(this._initOptions.filterCandidatesType[candidateType]){if(!this._hasMCU||!this._initOptions.forceTURN)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping received ICE candidate as it matches ICE candidate filtering flag ->"],candidate),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Dropping of processing ICE candidate as it matches ICE candidate filtering flag.")),void this._signalingEndOfCandidates(targetMid);log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Not dropping received ICE candidate as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured ->"],candidate)}this._peerConnections[targetMid].remoteDescription&&this._peerConnections[targetMid].remoteDescription.sdp&&this._peerConnections[targetMid].localDescription&&this._peerConnections[targetMid].localDescription.sdp?this._addIceCandidate(targetMid,canId,candidate):this._addIceCandidateToQueue(targetMid,canId,candidate),this._signalingEndOfCandidates(targetMid),this._gatheredCandidates[targetMid]||(this._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),this._gatheredCandidates[targetMid].receiving[candidateType].push({sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate})},Skylink.prototype._answerHandler=function(message){var self=this,targetMid=message.mid;log.log([targetMid,null,message.type,"Received answer from peer. Session description:"],clone(message));var pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for answer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}var answer={type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],answer),answer.sdp=self._removeSDPFilteredCandidates(targetMid,answer),answer.sdp=self._setSDPCodec(targetMid,answer),answer.sdp=self._setSDPBitrate(targetMid,answer),answer.sdp=self._setSDPCodecParams(targetMid,answer),answer.sdp=self._removeSDPCodecs(targetMid,answer),answer.sdp=self._removeSDPREMBPackets(targetMid,answer),answer.sdp=self._handleSDPConnectionSettings(targetMid,answer,"remote"),answer.sdp=self._removeSDPUnknownAptRtx(targetMid,answer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "have-local-offer" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.restart});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,answer);var onSuccessCbFn=function(){log.debug([targetMid,null,message.type,"Remote description set"]),pc.setAnswer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ANSWER,targetMid),self._addIceCandidateFromQueue(targetMid),self._peerMessagesStamps[targetMid]&&(self._peerMessagesStamps[targetMid].hasRestart=!1),self._dataChannels[targetMid]&&(-1===pc.remoteDescription.sdp.indexOf("m=application")||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,answer:answer})};pc.setRemoteDescription(new RTCSessionDescription(answer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=(agentVer||"").split("."),partsB=(requiredVer||"").split("."),i=0;i0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for sendStream() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream)):"function"==typeof callback&&callback(null,stream)};if(!("object"==typeof options&&null!==options||AdapterJS&&AdapterJS.WebRTCPlugin&&AdapterJS.WebRTCPlugin.plugin&&["function","object"].indexOf(typeof options)>-1)){var invalidOptionsError="Provided stream settings is invalid";return log.error(invalidOptionsError,options),void("function"==typeof callback&&callback(new Error(invalidOptionsError),null))}if(self._inRoom||log.warn("There are no peers to send stream to as not in room!"),"edge"===AdapterJS.webrtcDetectedBrowser){var edgeNotSupportError="Edge browser currently does not support renegotiation.";return log.error(edgeNotSupportError,options),void("function"==typeof callback&&callback(new Error(edgeNotSupportError),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0&&(useMediaSource=enableAudioArr)}else enableAudio&&"object"==typeof enableAudio?enableAudio.sourceId&&enableAudio.mediaSource||(enableAudioSettings={usedtx:"boolean"==typeof enableAudio.usedtx?enableAudio.usedtx:null,useinbandfec:"boolean"==typeof enableAudio.useinbandfec?enableAudio.useinbandfec:null,stereo:!0===enableAudio.stereo,echoCancellation:!1!==enableAudio.echoCancellation,deviceId:enableAudio.deviceId}):!0===enableAudio?enableAudioSettings=!0===enableAudio&&{usedtx:null,useinbandfec:null,stereo:!1,echoCancellation:!0,deviceId:null}:"function"==typeof enableAudio&&(callback=enableAudio,enableAudio=!1);if(mediaSource&&"string"==typeof mediaSource||mediaSource&&"object"==typeof mediaSource&&mediaSource.sourceId&&mediaSource.mediaSource)checkIfSourceExistsFn("object"==typeof mediaSource?mediaSource.mediaSource:mediaSource)&&(useMediaSource=["object"==typeof mediaSource?mediaSource.mediaSource:mediaSource]),useMediaSourceId="object"==typeof mediaSource?mediaSource.sourceId:null;else if(Array.isArray(mediaSource)){for(var mediaSourceArr=[],i=0;i0&&(useMediaSource=mediaSourceArr)}else"function"==typeof mediaSource&&(callback=mediaSource);useMediaSource.indexOf("audio")>-1&&-1===useMediaSource.indexOf("tab")&&(useMediaSource.splice(useMediaSource.indexOf("audio"),1),0===useMediaSource.length&&(useMediaSource=[self.MEDIA_SOURCE.SCREEN])),self._throttle(function(runFn){if(runFn){var settings={settings:{audio:enableAudioSettings,video:{screenshare:!0,exactConstraints:!1}},getUserMediaSettings:{audio:!1,video:{mediaSource:useMediaSource}}};"plugin"===AdapterJS.webrtcDetectedType&&useMediaSourceId&&(settings.getUserMediaSettings.video.optional=[{screenId:useMediaSourceId}]);var mediaAccessSuccessFn=function(stream){self.off("mediaAccessError",mediaAccessErrorFn),self._inRoom?(self._trigger("incomingStream",self._user.sid,stream,!0,self.getPeerInfo(),!0,stream.id||stream.label),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0),Object.keys(self._peerConnections).length>0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for shareScreen() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream)):"function"==typeof callback&&callback(null,stream)},mediaAccessErrorFn=function(error){self.off("mediaAccessSuccess",mediaAccessSuccessFn),"function"==typeof callback&&callback(error,null)};self.once("mediaAccessSuccess",mediaAccessSuccessFn,function(stream,isScreensharing){return isScreensharing}),self.once("mediaAccessError",mediaAccessErrorFn,function(error,isScreensharing){return isScreensharing});var getUserMediaAudioSettings=!!enableAudioSettings&&{echoCancellation:enableAudioSettings.echoCancellation};try{var hasDefaultAudioTrack=!1;enableAudioSettings&&("firefox"===AdapterJS.webrtcDetectedBrowser?(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio=getUserMediaAudioSettings):useMediaSource.indexOf("audio")>-1&&useMediaSource.indexOf("tab")>-1&&(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio={}));var onSuccessCbFn=function(stream){if(hasDefaultAudioTrack||!enableAudioSettings)return void self._onStreamAccessSuccess(stream,settings,!0,!1);settings.getUserMediaSettings.audio=getUserMediaAudioSettings;var onAudioSuccessCbFn=function(audioStream){try{audioStream.addTrack(stream.getVideoTracks()[0]),self.once("mediaAccessSuccess",function(){self._streams.screenshare.streamClone=stream},function(stream,isScreensharing){return isScreensharing}),self._onStreamAccessSuccess(audioStream,settings,!0,!1)}catch(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)}},onAudioErrorCbFn=function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)};navigator.getUserMedia({audio:getUserMediaAudioSettings},onAudioSuccessCbFn,onAudioErrorCbFn)},onErrorCbFn=function(error){self._onStreamAccessError(error,settings,!0,!1)};if("function"!=typeof(AdapterJS||{}).webRTCReady)return onErrorCbFn(new Error("Failed to call getUserMedia() as AdapterJS is not yet loaded!"));AdapterJS.webRTCReady(function(){navigator.getUserMedia(settings.getUserMediaSettings,onSuccessCbFn,onErrorCbFn)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._initOptions.throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._initOptions.throttleIntervals.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._initOptions.throttleIntervals.shareScreen)},Skylink.prototype.stopScreen=function(){this._streams.screenshare&&(this._stopStreams({screenshare:!0}),this._inRoom&&(this._streams.userMedia&&this._streams.userMedia.stream&&(this._trigger("incomingStream",this._user.sid,this._streams.userMedia.stream,!0,this.getPeerInfo(),!1,this._streams.userMedia.stream.id||this._streams.userMedia.stream.label),this._trigger("peerUpdated",this._user.sid,this.getPeerInfo(),!0)),this._refreshPeerConnection(Object.keys(this._peerConnections),{},!1)))},Skylink.prototype.getStreamSources=function(callback){var outputSources={audio:{input:[],output:[]},video:{input:[]}};if("function"!=typeof callback)return log.error("Please provide the callback.");var sourcesListFn=function(sources){sources.forEach(function(sourceItem){var item={deviceId:sourceItem.deviceId||sourceItem.sourceId||"default",label:sourceItem.label,groupId:sourceItem.groupId||null};item.label=item.label||"Source for "+item.deviceId,["audio","audioinput"].indexOf(sourceItem.kind)>-1?outputSources.audio.input.push(item):["video","videoinput"].indexOf(sourceItem.kind)>-1?outputSources.video.input.push(item):"audiooutput"===sourceItem.kind&&outputSources.audio.output.push(item)}),callback(outputSources)};navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.enumerateDevices?navigator.mediaDevices.enumerateDevices().then(sourcesListFn):window.MediaStreamTrack&&"function"==typeof MediaStreamTrack.getSources?MediaStreamTrack.getSources(sourcesListFn):sourcesListFn("function"==typeof navigator.getUserMedia?[{deviceId:"default",kind:"audioinput",label:"Default Audio Track"},{deviceId:"default",kind:"videoinput",label:"Default Video Track"}]:[])},Skylink.prototype.getScreenSources=function(callback){var outputSources={mediaSource:[],mediaSourceInput:[]};return"function"!=typeof callback?log.error("Please provide the callback."):navigator.userAgent.toLowerCase().indexOf("android")>-1?("chrome"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=59&&(outputSources.mediaSource=["screen"]),void callback(outputSources)):"plugin"===AdapterJS.webrtcDetectedType?void AdapterJS.webRTCReady(function(){if(AdapterJS.WebRTCPlugin.plugin&&AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable&&AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature&&(outputSources.mediaSource=["window","screen"],"function"==typeof AdapterJS.WebRTCPlugin.plugin.getScreensharingSources))return void AdapterJS.WebRTCPlugin.plugin.getScreensharingSources(function(sources){sources.forEach(sources,function(sourceItem){var item={sourceId:sourceItem.id||sourceItem.sourceId||"default",label:sourceItem.label,mediaSource:sourceItem.kind||"screen"};item.label=item.label||"Source for "+item.sourceId,outputSources.mediaSourceInput.push(item)}),callback(outputSources)});callback(outputSources)}):(("chrome"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=34||"firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=38||"opera"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=21)&&("opera"!==AdapterJS.webrtcDetectedBrowser||AdapterJS.extensionInfo&&AdapterJS.extensionInfo.opera&&AdapterJS.extensionInfo.opera.extensionId||log.warn("Please ensure that your application allows Opera screensharing!"),outputSources.mediaSource=["window","screen"],"chrome"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=52||"opera"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=39?outputSources.mediaSource.push("tab","audio"):"firefox"===AdapterJS.webrtcDetectedBrowser&&outputSources.mediaSource.push("browser","camera","application")),void callback(outputSources))},Skylink.prototype._muteStreams=function(){var self=this,hasVideo=!1,hasAudio=!1,muteFn=function(stream){for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",self._streamsMutedSettings),{hasVideo:hasVideo,hasAudio:hasAudio}},Skylink.prototype._stopStreams=function(options){var self=this,stopFn=function(stream){var streamId=stream.id||stream.label;log.debug([null,"MediaStream",streamId,"Stopping Stream ->"],stream);try{for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",options)},Skylink.prototype._parseStreamSettings=function(options){var settings={settings:{audio:!1,video:!1},mutedSettings:{shouldAudioMuted:!1,shouldVideoMuted:!1},getUserMediaSettings:{audio:!1,video:!1}};return options.audio&&(settings.settings.audio={stereo:!1,exactConstraints:!!options.useExactConstraints,echoCancellation:!0},settings.getUserMediaSettings.audio={echoCancellation:!0},"object"==typeof options.audio&&("boolean"==typeof options.audio.stereo&&(settings.settings.audio.stereo=options.audio.stereo),"boolean"==typeof options.audio.useinbandfec&&(settings.settings.audio.useinbandfec=options.audio.useinbandfec),"boolean"==typeof options.audio.usedtx&&(settings.settings.audio.usedtx=options.audio.usedtx),"number"==typeof options.audio.maxplaybackrate&&options.audio.maxplaybackrate>=8e3&&options.audio.maxplaybackrate<=48e3&&(settings.settings.audio.maxplaybackrate=options.audio.maxplaybackrate),"boolean"==typeof options.audio.mute&&(settings.mutedSettings.shouldAudioMuted=options.audio.mute),"edge"!==AdapterJS.webrtcDetectedBrowser&&("boolean"==typeof options.audio.echoCancellation&&(settings.settings.audio.echoCancellation=options.audio.echoCancellation,settings.getUserMediaSettings.audio.echoCancellation=options.audio.echoCancellation),Array.isArray(options.audio.optional)&&(settings.settings.audio.optional=clone(options.audio.optional),settings.getUserMediaSettings.audio.optional=clone(options.audio.optional)),options.audio.deviceId&&"string"==typeof options.audio.deviceId&&"firefox"!==AdapterJS.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,settings.getUserMediaSettings.audio.deviceId=options.useExactConstraints?{exact:options.audio.deviceId}:{ideal:options.audio.deviceId}))),"edge"===AdapterJS.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio=!0)),options.video&&(settings.settings.video={resolution:clone(this.VIDEO_RESOLUTION.VGA),screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video={},"object"==typeof options.video?("boolean"==typeof options.video.mute&&(settings.mutedSettings.shouldVideoMuted=options.video.mute),Array.isArray(options.video.optional)&&(settings.settings.video.optional=clone(options.video.optional),settings.getUserMediaSettings.video.optional=clone(options.video.optional)),options.video.deviceId&&"string"==typeof options.video.deviceId&&"firefox"!==AdapterJS.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,settings.getUserMediaSettings.video.deviceId=options.useExactConstraints?{exact:options.video.deviceId}:{ideal:options.video.deviceId}),options.video.resolution&&"object"==typeof options.video.resolution&&((options.video.resolution.width&&"object"==typeof options.video.resolution.width||"number"==typeof options.video.resolution.width)&&(settings.settings.video.resolution.width=options.video.resolution.width),(options.video.resolution.height&&"object"==typeof options.video.resolution.height||"number"==typeof options.video.resolution.height)&&(settings.settings.video.resolution.height=options.video.resolution.height)),settings.getUserMediaSettings.video.width="object"==typeof settings.settings.video.resolution.width?settings.settings.video.resolution.width:options.useExactConstraints?{exact:settings.settings.video.resolution.width}:{max:settings.settings.video.resolution.width},settings.getUserMediaSettings.video.height="object"==typeof settings.settings.video.resolution.height?settings.settings.video.resolution.height:options.useExactConstraints?{exact:settings.settings.video.resolution.height}:{max:settings.settings.video.resolution.height},(options.video.frameRate&&"object"==typeof options.video.frameRate||"number"==typeof options.video.frameRate&&"plugin"!==AdapterJS.webrtcDetectedType)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}),options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&"plugin"===AdapterJS.webrtcDetectedType&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):settings.getUserMediaSettings.video={width:options.useExactConstraints?{exact:settings.settings.video.resolution.width}:{max:settings.settings.video.resolution.width},height:options.useExactConstraints?{exact:settings.settings.video.resolution.height}:{max:settings.settings.video.resolution.height}},"edge"===AdapterJS.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,streamHasEnded=!1;if(log.log([null,"MediaStream",streamId,"Has access to stream ->"],stream),!isScreenSharing&&self._streams.userMedia?self._stopStreams({userMedia:!0,screenshare:!1}):isScreenSharing&&self._streams.screenshare&&self._stopStreams({userMedia:!1,screenshare:!0}),self._streamsStoppedCbs[streamId]=function(){log.log([null,"MediaStream",streamId,"Stream has ended"]),streamHasEnded=!0,self._trigger("mediaAccessStopped",!!isScreenSharing,!!isAudioFallback,streamId),self._inRoom&&(log.debug([null,"MediaStream",streamId,"Sending Stream ended status to Peers"]),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.STREAM,mid:self._user.sid,rid:self._room.id,cid:self._key,streamId:streamId,settings:settings.settings,status:"ended"}),self._trigger("streamEnded",self._user.sid,self.getPeerInfo(),!0,!!isScreenSharing,streamId),isScreenSharing&&self._streams.screenshare&&self._streams.screenshare.stream&&(self._streams.screenshare.stream.id||self._streams.screenshare.stream.label)===streamId?self._streams.screenshare=null:!isScreenSharing&&self._streams.userMedia&&self._streams.userMedia.stream&&(self._streams.userMedia.stream.id||self._streams.userMedia.stream.label)===streamId&&(self._streams.userMedia=null))},["chrome","opera"].indexOf(AdapterJS.webrtcDetectedBrowser)>-1?(stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},isScreenSharing&&stream.getVideoTracks().length>0&&(stream.getVideoTracks()[0].onended=function(){setTimeout(function(){!streamHasEnded&&self._inRoom&&self.stopScreen()},350)})):"firefox"===AdapterJS.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._initOptions.audioFallback){log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0);var onAudioSuccessCbFn=function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},onAudioErrorCbFn=function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)};return void navigator.getUserMedia({audio:!0},onAudioSuccessCbFn,onAudioErrorCbFn)}log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this,streamId=self._peerConnections[targetMid]&&self._peerConnections[targetMid].remoteStreamId||stream.id||stream.label;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",streamId,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",streamId,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",streamId,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,streamId),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId];if(pc){var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)&&self._getSDPCommonSupports(peerId,pc.remoteDescription).video,offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPCommonSupports(peerId,pc.remoteDescription).audio;if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){if(!updatedStream||(!pc.localStreamId||updatedStream.id!==pc.localStreamId)){if("edge"!==AdapterJS.webrtcDetectedBrowser||self._initOptions.useEdgeWebRTC&&window.msRTCPeerConnection?pc.getLocalStreams().forEach(function(stream){pc.removeStream(stream)}):pc.getSenders().forEach(function(sender){pc.removeTrack(sender)}),!offerToReceiveAudio&&!offerToReceiveVideo)return;updatedStream&&("edge"!==AdapterJS.webrtcDetectedBrowser||self._initOptions.useEdgeWebRTC&&window.msRTCPeerConnection?pc.addStream(updatedStream):updatedStream.getTracks().forEach(function(track){"audio"===track.kind&&!offerToReceiveAudio||"video"===track.kind&&!offerToReceiveVideo||pc.addTrack(track,updatedStream)}),pc.localStreamId=updatedStream.id||updatedStream.label,pc.localStream=updatedStream)}};self._streams.screenshare&&self._streams.screenshare.stream?(log.debug([peerId,"MediaStream",null,"Sending screen"],self._streams.screenshare.stream),updateStreamFn(self._streams.screenshare.stream)):self._streams.userMedia&&self._streams.userMedia.stream?(log.debug([peerId,"MediaStream",null,"Sending stream"],self._streams.userMedia.stream),updateStreamFn(self._streams.userMedia.stream)):(log.warn([peerId,"MediaStream",null,"No media to send. Will be only receiving"]),updateStreamFn(null))}else log.warn([peerId,"MediaStream",null,"Not adding any stream as signalingState is closed"])}else log.warn([peerId,"MediaStream",self._mediaStream,"Not adding stream as peerconnection object does not exists"])}catch(error){(error.message||"").indexOf("already added")>-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){if(self._streamsSession[peerId][streamId]){var peerInfo=clone(self.getPeerInfo(peerId));peerInfo.settings.audio=clone(self._streamsSession[peerId][streamId].audio),peerInfo.settings.video=clone(self._streamsSession[peerId][streamId].video);var hasScreenshare=peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&!!peerInfo.settings.video.screenshare;self._streamsSession[peerId][streamId]=!1,self._trigger("streamEnded",peerId,peerInfo,!1,hasScreenshare,streamId)}};if(checkStreamId)renderEndedFn(checkStreamId);else if(self._peerConnections[peerId])for(var streamId in self._streamsSession[peerId])self._streamsSession[peerId].hasOwnProperty(streamId)&&self._streamsSession[peerId][streamId]&&renderEndedFn(streamId)},Skylink.prototype._setSDPCodecParams=function(targetMid,sessionDescription){var self=this,parseFn=function(type,codecName,samplingRate,settings){var mLine=sessionDescription.sdp.match(new RegExp("m="+type+" .*\r\n","gi"));if(Array.isArray(mLine)&&mLine.length>0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-1===cLineIndex?void log.error([targetMid,"RTCSessionDesription",sessionDescription.type,'Failed setting "'+type+'" bandwidth as c-line is missing.']):(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Limiting maximum sending "'+type+'" bandwidth ->'],bw),void sdpLines.splice(cLineIndex+1,0,"firefox"===window.webrtcDetectedBrowser?"b=TIAS:"+(1e3*bw*(window.webrtcDetectedVersion>52&&window.webrtcDetectedVersion<55?1e3:1)).toFixed(0):"b=AS:"+bw)):void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not limiting "'+type+'" bandwidth'])},bASAudioBw=this._streamsBandwidthSettings.bAS.audio,bASVideoBw=this._streamsBandwidthSettings.bAS.video,bASDataBw=this._streamsBandwidthSettings.bAS.data,googleXMinBw=this._streamsBandwidthSettings.googleX.min,googleXMaxBw=this._streamsBandwidthSettings.googleX.max;if(this._peerCustomConfigs[targetMid]&&(this._peerCustomConfigs[targetMid].bandwidth&&"object"==typeof this._peerCustomConfigs[targetMid].bandwidth&&("number"==typeof this._peerCustomConfigs[targetMid].bandwidth.audio&&(bASAudioBw=this._peerCustomConfigs[targetMid].bandwidth.audio),
-"number"==typeof this._peerCustomConfigs[targetMid].bandwidth.video&&(bASVideoBw=this._peerCustomConfigs[targetMid].bandwidth.video),"number"==typeof this._peerCustomConfigs[targetMid].bandwidth.data&&(bASDataBw=this._peerCustomConfigs[targetMid].bandwidth.data)),this._peerCustomConfigs[targetMid].googleXBandwidth&&"object"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth&&("number"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth.min&&(googleXMinBw=this._peerCustomConfigs[targetMid].googleXBandwidth.min),"number"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth.max&&(googleXMaxBw=this._peerCustomConfigs[targetMid].googleXBandwidth.max))),parseFn("audio",bASAudioBw),parseFn("video",bASVideoBw),parseFn("data",bASDataBw),"number"==typeof googleXMinBw||"number"==typeof googleXMaxBw){for(var codec=null,codecRtpMapLineIndex=-1,codecFmtpLineIndex=-1,j=0;j-1){var xGoogleParams="";"number"==typeof googleXMinBw&&(xGoogleParams+="x-google-min-bitrate="+googleXMinBw+";"),"number"==typeof googleXMaxBw&&(xGoogleParams+="x-google-max-bitrate="+googleXMaxBw+";"),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Limiting x-google-bitrate ->"],xGoogleParams),codecFmtpLineIndex>-1?sdpLines[codecFmtpLineIndex]+=(sdpLines[codecFmtpLineIndex].split(" ")[1]?";":"")+xGoogleParams:sdpLines.splice(codecRtpMapLineIndex+1,0,"a=fmtp:"+codec+" "+xGoogleParams)}}return sdpLines.join("\r\n")},Skylink.prototype._setSDPCodec=function(targetMid,sessionDescription,overrideSettings){var self=this,parseFn=function(type,codecSettings){var codec="object"==typeof codecSettings?codecSettings.codec:codecSettings,samplingRate="object"==typeof codecSettings?codecSettings.samplingRate:null,channels="object"==typeof codecSettings?codecSettings.channels:null;if(codec===self["audio"===type?"AUDIO_CODEC":"VIDEO_CODEC"].AUTO)return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not preferring any codec for "'+type+'" streaming. Using browser selection.']);var mLine=sessionDescription.sdp.match(new RegExp("m="+type+" .*\r\n","gi"));if(!(Array.isArray(mLine)&&mLine.length>0))return void log.error([targetMid,"RTCSessionDesription",sessionDescription.type,'Not preferring any codec for "'+type+'" streaming as m= line is not found.']);var setLineFn=function(codecsList,isSROk,isChnlsOk){if(Array.isArray(codecsList)&&codecsList.length>0){isSROk||(samplingRate=null),isChnlsOk||(channels=null),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Preferring "'+codec+'" (samplingRate: '+(samplingRate||"n/a")+", channels: "+(channels||"n/a")+') for "'+type+'" streaming.']);var line=mLine[0],lineParts=line.replace("\r\n","").split(" ");line=lineParts[0]+" "+lineParts[1]+" "+lineParts[2]+" ",lineParts.splice(0,3);for(var i=0;i0?(lineParts.splice(j,1),j--):sessionDescription.sdp.match(new RegExp("a=rtpmap:"+lineParts[j]+" "+codec+"/.*\r\n","gi"))&&(line+=lineParts[j]+" ",lineParts.splice(j,1),j--);return line+=lineParts.join(" ")+"\r\n",sessionDescription.sdp=sessionDescription.sdp.replace(mLine[0],line),!0}};if(samplingRate){if("audio"===type&&channels&&setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/"+samplingRate+(1===channels?"[/1]*":"/"+channels)+"\r\n","gi")),!0,!0))return;if(setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/"+samplingRate+"[/]*.*\r\n","gi")),!0))return}"audio"===type&&channels&&setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/.*/"+channels+"\r\n","gi")),!1,!0)||setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/.*\r\n","gi")))};return parseFn("audio",overrideSettings?overrideSettings.audio:self._initOptions.audioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._initOptions.videoCodec),sessionDescription.sdp},Skylink.prototype._removeSDPFirefoxH264Pref=function(targetMid,sessionDescription){return log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing Firefox experimental H264 flag to ensure interopability reliability"]),sessionDescription.sdp.replace(/a=fmtp:0 profile-level-id=0x42e00c;packetization-mode=1\r\n/g,"")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var mediaLines=(sessionDescription.sdp.split("\r\n"),sessionDescription.sdp.split("m=")),formatRtx=function(str){return(str.match(/a=rtpmap:.*\ rtx\/.*\r\n/gi)||[]).forEach(function(line){var payload=(line.split("a=rtpmap:")[1]||"").split(" ")[0]||"",fmtpLine=(str.match(new RegExp("a=fmtp:"+payload+" .*\r\n","gi"))||[])[0];if(!fmtpLine)return void(str=str.replace(new RegExp(line,"g"),""));var codecPayload=(fmtpLine.split(" apt=")[1]||"").replace(/\r\n/gi,"");str.match(new RegExp("a=rtpmap:"+codecPayload+" .*\r\n","gi"))||(str=str.replace(new RegExp(line,"g"),""),str=str.replace(new RegExp(fmtpLine,"g"),""))}),str},formatFmtpRtcpFb=function(str){return(str.match(/a=(fmtp|rtcp-fb):.*\ rtx\/.*\r\n/gi)||[]).forEach(function(line){var payload=(line.split("a="+(line.indexOf("rtcp")>0?"rtcp-fb":"fmtp"))[1]||"").split(" ")[0]||"";str.match(new RegExp("a=rtpmap:"+payload+" .*\r\n","gi"))||(str=str.replace(new RegExp(line,"g"),""))}),str},m=0;m0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._initOptions.disableVideoFecCodecs&&(this._hasMCU?log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "ulpfec" or "red" codecs as connected to MCU to prevent connectivity issues.']):(parseFn("video","red"),parseFn("video","ulpfec"))),this._initOptions.disableComfortNoiseCodec&&audioSettings&&"object"==typeof audioSettings&&audioSettings.stereo&&parseFn("audio","CN"),"edge"===window.webrtcDetectedBrowser&&"edge"!==(((this._peerInformations[targetMid]||{}).agent||{}).name||"unknown").name&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=rtcp-fb:.*\ x-message\ .*\r\n/gi,"")),sessionDescription.sdp},Skylink.prototype._removeSDPREMBPackets=function(targetMid,sessionDescription){return this._initOptions.disableREMB?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing REMB packets."]),sessionDescription.sdp.replace(/a=rtcp-fb:\d+ goog-remb\r\n/g,"")):sessionDescription.sdp},Skylink.prototype._getSDPSelectedCodec=function(targetMid,sessionDescription,type,beSilentOnLogs){var codecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index&&0===mediaItem.indexOf(type+" ")){var codecs=(mediaItem.split("\r\n")[0]||"").split(" ");codecs.splice(0,3);for(var i=0;i-1)){codecInfo.name=parts[0],codecInfo.clockRate=parseInt(parts[1],10)||0,codecInfo.channels=parseInt(parts[2]||"1",10)||1,codecInfo.payloadType=parseInt(codecs[i],10),codecInfo.params="";(mediaItem.match(new RegExp("a=fmtp:"+codecs[i]+".*\r\n","gi"))||[]).forEach(function(paramItem){codecInfo.params+=paramItem.replace(new RegExp("a=fmtp:"+codecs[i],"gi"),"").replace(/\ /g,"").replace(/\r\n/g,"")});break}}}}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,'Parsing session description "'+type+'" codecs ->'],codecInfo),codecInfo):codecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._initOptions.forceTURN&&this._hasMCU?(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not filtering ICE candidates as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured"]),sessionDescription.sdp):(this._initOptions.filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._initOptions.filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._initOptions.filterCandidatesType.relay&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "relay" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*relay.*\r\n/g,"")),sessionDescription.sdp)},Skylink.prototype._getCodecsSupport=function(callback){var self=this;if(self._currentCodecSupport)return void callback(null);if(self._currentCodecSupport={audio:{},video:{}},"AppleWebKit"===AdapterJS.webrtcDetectedType)return self._currentCodecSupport.audio={opus:["48000/2"]},self._currentCodecSupport.video={h264:["48000"]},callback(null);try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints="plugin"!==AdapterJS.webrtcDetectedType?{offerToReceiveAudio:!0,offerToReceiveVideo:!0}:{mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}};try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){self._currentCodecSupport=self._getSDPCodecsSupport(null,offer),callback(null)},function(error){callback(error)},offerConstraints)}}catch(error){callback(error)}},Skylink.prototype._handleSDPConnectionSettings=function(targetMid,sessionDescription,direction){var self=this;if(!self._sdpSessions[targetMid])return sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;"remote"!==direction||self.getPeerInfo(targetMid).config.enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",mediaType=(self._peerInformations[targetMid],""),bundleLineIndex=-1,bundleLineMids=[],mLineIndex=-1,settings=clone(self._sdpSettings);if("MCU"===targetMid&&(settings.connection.audio=!0,settings.connection.video=!0,settings.connection.data=!0),self._hasMCU){var peerStreamSettings=clone(self.getPeerInfo(targetMid)).settings||{};settings.direction.audio.receive="MCU"!==targetMid&&!!peerStreamSettings.audio,settings.direction.audio.send="MCU"===targetMid,settings.direction.video.receive="MCU"!==targetMid&&!!peerStreamSettings.video,settings.direction.video.send="MCU"===targetMid}if("remote"===direction){var offerCodecs=self._getSDPCommonSupports(targetMid,sessionDescription);offerCodecs.audio||(settings.connection.audio=!1),offerCodecs.video||(settings.connection.video=!1)}self._sdpSessions[targetMid][direction].mLines=[],self._sdpSessions[targetMid][direction].bundleLine="",self._sdpSessions[targetMid][direction].connection={audio:null,video:null,data:null};for(var i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");else if(mediaType&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){if(-1===["audio","video"].indexOf(mediaType)){self._sdpSessions[targetMid][direction].connection.data=sdpLines[i];continue}if("local"===direction)settings.direction[mediaType].send&&!settings.direction[mediaType].receive?sdpLines[i]=sdpLines[i].indexOf("send")>-1?"a=sendonly":"a=inactive":!settings.direction[mediaType].send&&settings.direction[mediaType].receive?sdpLines[i]=sdpLines[i].indexOf("recv")>-1?"a=recvonly":"a=inactive":settings.direction[mediaType].send||settings.direction[mediaType].receive||(sdpLines[i]="a=inactive"),self._hasMCU||"firefox"===window.webrtcDetectedBrowser||"firefox"!==peerAgent||sessionDescription.type!==self.HANDSHAKE_PROGRESS.OFFER||"a=recvonly"!==sdpLines[i]||(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Overriding any original settings to receive only to send and receive to resolve chrome BUNDLE errors."]),sdpLines[i]="a=sendrecv",settings.direction[mediaType].send=!0,settings.direction[mediaType].receive=!0);else if(sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER){var localOfferRes=self._sdpSessions[targetMid].local.connection[mediaType];"a=sendonly"===localOfferRes?sdpLines[i]=-1===["a=inactive","a=recvonly"].indexOf(sdpLines[i])?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=-1===["a=inactive","a=sendonly"].indexOf(sdpLines[i])?"a=recvonly"===sdpLines[i]?"a=inactive":"a=sendonly":sdpLines[i]:"a=inactive"===localOfferRes&&(sdpLines[i]="a=inactive")}self._sdpSessions[targetMid][direction].connection[mediaType]=sdpLines[i]}}else sdpLines.splice(i,1),i--;(sdpLines[i]||"").replace(/\n|\r|\s|\ /gi,"")||(sdpLines.splice(i,1),i--)}return bundleLineIndex>-1&&(self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE?sdpLines[bundleLineIndex]="a=group:BUNDLE "+bundleLineMids.join(" "):self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.NONE&&sdpLines.splice(bundleLineIndex,1)),"edge"!==window.webrtcDetectedBrowser&&(sdpLines[sdpLines.length-1].replace(/\n|\r|\s/gi,"")?sdpLines.push(""):sdpLines[sdpLines.length-1]=""),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Handling connection lines and direction ->"],settings),sdpLines.join("\r\n")},Skylink.prototype._getSDPFingerprint=function(targetMid,sessionDescription,beSilentOnLogs){var fingerprint={fingerprint:null,fingerprintAlgorithm:null,derBase64:null};if(!sessionDescription||!sessionDescription.sdp)return fingerprint;for(var sdpLines=sessionDescription.sdp.split("\r\n"),i=0;i"],fingerprint),fingerprint},Skylink.prototype._renderSDPOutput=function(targetMid,sessionDescription){var self=this,localStream=null,localStreamId=null;if(sessionDescription&&sessionDescription.sdp){if(!self._peerConnections[targetMid])return sessionDescription.sdp;self._peerConnections[targetMid].localStream&&(localStream=self._peerConnections[targetMid].localStream,localStreamId=self._peerConnections[targetMid].localStreamId||self._peerConnections[targetMid].localStream.id);var sdpLines=(self._initOptions.enableIceTrickle?sessionDescription.sdp:sessionDescription.sdp.replace(/a=end-of-candidates\r\n/g,"")).split("\r\n");self._peerInformations[targetMid];if(localStream)for(var mediaType="",i=0;i0?ssrcParts=sdpLines[i].split(" msid:"):sdpLines[i].indexOf(" mslabel:")>0&&(ssrcParts=sdpLines[i].split(" mslabel:")),ssrcParts){var ssrcMsidParts=(ssrcParts[1]||"").split(" ");ssrcMsidParts[0]=localStreamId,ssrcParts[1]=ssrcMsidParts.join(" "),sdpLines[i].indexOf(" msid:")>0?sdpLines[i]=ssrcParts.join(" msid:"):sdpLines[i].indexOf(" mslabel:")>0&&(sdpLines[i]=ssrcParts.join(" mslabel:"))}}if(!self._initOptions.enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var e=0;e"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),log.info([targetMid,"RTCSessionDescription",sessionDescription.type,"Formatted output ->"],sdpLines.join("\r\n")),sdpLines.join("\r\n")}},Skylink.prototype._parseSDPMediaStreamIDs=function(targetMid,sessionDescription){if(this._peerConnections[targetMid]){if(!sessionDescription||!sessionDescription.sdp)return void(this._peerConnections[targetMid].remoteStreamId=null);for(var sdpLines=sessionDescription.sdp.split("\r\n"),currentStreamId=null,i=0;i0){currentStreamId=(sdpLines[i].split(" msid:")[1]||"").split(" ")[0];break}}currentStreamId?currentStreamId!==this._peerConnections[targetMid].remoteStreamId?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"New remote stream is sent ->"],currentStreamId),this._peerConnections[targetMid].remoteStreamId=currentStreamId):log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Same remote stream is sent ->"],currentStreamId):(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"No remote stream is sent."]),this._peerConnections[targetMid].remoteStreamId=null)}},Skylink.prototype._getSDPICECandidates=function(targetMid,sessionDescription,beSilentOnLogs){var candidates={host:[],srflx:[],relay:[]};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index){var sdpMid=((mediaItem.match(/a=mid:.*\r\n/gi)||[])[0]||"").replace(/a=mid:/gi,"").replace(/\r\n/,""),sdpMLineIndex=index-1;(mediaItem.match(/a=candidate:.*\r\n/gi)||[]).forEach(function(item){var canType=(item.split(" ")[7]||"host").replace(/\r\n/g,"");candidates[canType]=candidates[canType]||[],candidates[canType].push(new RTCIceCandidate({sdpMid:sdpMid,sdpMLineIndex:sdpMLineIndex,candidate:(item.split("a=")[1]||"").replace(/\r\n/g,"")}))})}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,"Parsing session description ICE candidates ->"],candidates),candidates):candidates},Skylink.prototype._getSDPMediaSSRC=function(targetMid,sessionDescription,beSilentOnLogs){var ssrcs={audio:0,video:0};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index){var mediaType=mediaItem.split(" ")[0]||"",ssrcLine=(mediaItem.match(/a=ssrc:.*\r\n/)||[])[0];"number"==typeof ssrcs[mediaType]&&ssrcLine&&(ssrcs[mediaType]=parseInt((ssrcLine.split("a=ssrc:")[1]||"").split(" ")[0],10)||0)}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,"Parsing session description media SSRCs ->"],ssrcs),ssrcs):ssrcs},Skylink.prototype._getSDPCodecsSupport=function(targetMid,sessionDescription){var codecs={audio:{},video:{}};if(!sessionDescription||!sessionDescription.sdp)return codecs;for(var sdpLines=sessionDescription.sdp.split("\r\n"),mediaType="",i=0;i-1)continue;codecs[mediaType][codec]=codecs[mediaType][codec]||[],-1===codecs[mediaType][codec].indexOf(info)&&codecs[mediaType][codec].push(info)}}else mediaType=(sdpLines[i].split("m=")[1]||"").split(" ")[0];return log.info([targetMid||null,"RTCSessionDescription",sessionDescription.type,"Parsed codecs support ->"],codecs),codecs},Skylink.prototype._getSDPCommonSupports=function(targetMid,sessionDescription){var self=this,offer={audio:!1,video:!1};if(!targetMid||!sessionDescription||!sessionDescription.sdp){if(offer.video=!(!self._currentCodecSupport.video.h264&&!self._currentCodecSupport.video.vp8),offer.audio=!!self._currentCodecSupport.audio.opus,targetMid){var peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"";AdapterJS.webrtcDetectedBrowser===peerAgent&&(offer.video=Object.keys(self._currentCodecSupport.video).length>0,offer.audio=Object.keys(self._currentCodecSupport.audio).length>0)}return offer}var remoteCodecs=self._getSDPCodecsSupport(targetMid,sessionDescription),localCodecs=self._currentCodecSupport;for(var ac in localCodecs.audio)if(localCodecs.audio.hasOwnProperty(ac)&&localCodecs.audio[ac]&&remoteCodecs.audio[ac]){offer.audio=!0;break}for(var vc in localCodecs.video)if(localCodecs.video.hasOwnProperty(vc)&&localCodecs.video[vc]&&remoteCodecs.video[vc]){offer.video=!0;break}return offer},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this);
\ No newline at end of file
+updatedConstraints.video.mandatory.chromeMediaSourceId=response.sourceId,Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("tab")>-1&&updatedConstraints.video.mediaSource.indexOf("audio")>-1&&updatedConstraints.audio&&(updatedConstraints.audio="object"==typeof updatedConstraints.audio?updatedConstraints.audio:{},updatedConstraints.audio.mandatory=updatedConstraints.audio.mandatory||{},updatedConstraints.audio.mandatory.chromeMediaSource="desktop",updatedConstraints.audio.mandatory.chromeMediaSourceId=response.sourceId),delete updatedConstraints.video.mediaSource,baseGetUserMedia(updatedConstraints,successCb,failureCb)):(response.extensionLink&&AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_CHROME,AdapterJS.TEXT.EXTENSION.BUTTON_CHROME,function(e){window.open(response.extensionLink,"_blank"),e.target&&e.target.parentElement&&e.target.nextElementSibling&&e.target.nextElementSibling.click&&e.target.nextElementSibling.click(),AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION?AdapterJS.TEXT.EXTENSION.REQUIRE_REFRESH:AdapterJS.TEXT.REFRESH.REQUIRE_REFRESH,AdapterJS.TEXT.REFRESH.BUTTON,function(){window.open("javascript:location.reload()","_top")})}),failureCb(response.error))};if(AdapterJS.extensionInfo.chrome.iframeLink&&"opera"!==AdapterJS.webrtcDetectedBrowser)iframe.getSourceId(updatedConstraints.video.mediaSource,fetchStream);else{var extensionId=AdapterJS.extensionInfo["opera"===AdapterJS.webrtcDetectedBrowser?"opera":"chrome"].extensionId,extensionLink=AdapterJS.extensionInfo["opera"===AdapterJS.webrtcDetectedBrowser?"opera":"chrome"].extensionLink,icon=document.createElement("img");icon.src="chrome-extension://"+extensionId+"/icon.png",icon.onload=function(){chrome.runtime.sendMessage(extensionId,{type:"get-version"},function(versionRes){if(!versionRes||"object"!=typeof versionRes||"send-version"!==versionRes.type)return void fetchStream({success:!1,error:new Error("Extension is disabled")});chrome.runtime.sendMessage(extensionId,{type:"get-source",sources:updatedConstraints.video.mediaSource},function(sourceRes){fetchStream(sourceRes&&"object"==typeof sourceRes?"send-source-error"===sourceRes.type?{success:!1,error:new Error("Permission denied for screen retrieval")}:{success:!0,sourceId:sourceRes.sourceId}:{success:!1,error:new Error("Retrieval failed")})})})},icon.onerror=function(){fetchStream({success:!1,error:new Error("Extension not installed"),extensionLink:extensionLink})}}}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=window.getUserMedia=navigator.getUserMedia,navigator.mediaDevices.getUserMedia=function(constraints){return new Promise(function(resolve,reject){try{window.getUserMedia(constraints,resolve,reject)}catch(error){reject(error)}})},"chrome"===AdapterJS.webrtcDetectedBrowser){var states={loaded:!1,error:!1};if(iframe)try{(document.body||document.documentElement).removeChild(iframe)}catch(e){}if(!AdapterJS.extensionInfo.chrome.iframeLink)return;iframe.onload=function(){states.loaded=!0},iframe.onerror=function(){states.error=!0},iframe.src=AdapterJS.extensionInfo.chrome.iframeLink,iframe.style.display="none";var getSourceIdFromIFrame=function(sources,cb){window.addEventListener("message",function iframeListener(evt){window.removeEventListener("message",iframeListener),cb(evt.data?"not-installed"===evt.data.chromeExtensionStatus?{success:!1,error:new Error("Extension is not installed"),extensionLink:evt.data.data||AdapterJS.extensionInfo.chrome.extensionLink}:"installed-disabled"===evt.data.chromeExtensionStatus?{success:!1,error:new Error("Extension is disabled")}:"PermissionDeniedError"===evt.data.chromeMediaSourceId?{success:!1,error:new Error("Permission denied for screen retrieval")}:evt.data.chromeMediaSourceId&&"string"==typeof evt.data.chromeMediaSourceId?{success:!0,sourceId:evt.data.chromeMediaSourceId}:{success:!1,error:new Error("Failed retrieving selected screen")}:{success:!1,error:new Error("Failed retrieving response")})}),iframe.contentWindow.postMessage({captureSourceId:!0,sources:sources,legacy:!0,extensionId:AdapterJS.extensionInfo.chrome.extensionId,extensionLink:AdapterJS.extensionInfo.chrome.extensionLink},"*")};iframe.getSourceId=function(sources,cb){if(states.error)return void cb({success:!1,error:new Error("iframe is not loaded")});if(states.loaded)getSourceIdFromIFrame(sources,cb);else var endBlocks=0,intervalChecker=setInterval(function(){states.loaded?(clearInterval(intervalChecker),getSourceIdFromIFrame(sources,cb)):50===endBlocks?(clearInterval(intervalChecker),cb({success:!1,error:new Error("iframe failed to load")})):endBlocks++},100)},(document.body||document.documentElement).appendChild(iframe)}}else"edge"===AdapterJS.webrtcDetectedBrowser?console.warn("Edge does not support screensharing feature in getUserMedia"):"AppleWebKit"===AdapterJS.webrtcDetectedType?console.warn("Safari does not support screensharing feature in getUserMedia"):"plugin"===AdapterJS.webrtcDetectedType&&(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(checkIfConstraintsIsValid(constraints,successCb,failureCb),constraints.video&&"object"==typeof constraints.video&&constraints.video.hasOwnProperty("mediaSource")){var updatedConstraints=clone(constraints);AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){if(!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature||!AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable)return void failureCb(new Error("Your version of the WebRTC plugin does not support screensharing"));if(AdapterJS.WebRTCPlugin.plugin.screensharingKeys)if(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("screen")>-1&&updatedConstraints.video.mediaSource.indexOf("window")>-1||updatedConstraints.video.mediaSource===AdapterJS.WebRTCPlugin.plugin.screensharingKey||updatedConstraints.video.mediaSource===AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screenOrWindow)updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screenOrWindow;else if(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("screen")>-1||"screen"===updatedConstraints.video.mediaSource)updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screen;else{if(!(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("window")>-1||"window"===updatedConstraints.video.mediaSource))return void failureCb(new Error('GetUserMedia: Only "screen", "window", ["screen", "window"] are supported as mediaSource constraints'));updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.window}updatedConstraints.video.optional=updatedConstraints.video.optional||[],updatedConstraints.video.optional.push({sourceId:updatedConstraints.video.mediaSource}),baseGetUserMedia(updatedConstraints,successCb,failureCb)})}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=getUserMedia=window.getUserMedia=navigator.getUserMedia,navigator.mediaDevices&&"undefined"!=typeof Promise&&(navigator.mediaDevices.getUserMedia=requestUserMedia))}},"function"!=typeof window.require&&AdapterJS._defineMediaSourcePolyfill(),function(globals){"use strict";function Skylink(){this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._peerInformations={},this._user=null,this._userData="",this._peerPriorityWeight=0,this._autoIntroduce=!0,this._isPrivileged=!1,this._peerList=null,this._selectedRoom=null,this._roomLocked=!1,this._inRoom=!1,this._EVENTS={},this._onceEvents={},this._timestamp={socketMessage:null,shareScreen:null,refreshConnection:null,getUserMedia:null,lastRestart:null},this._socketSession={},this._socketMessageQueue=[],this._socketMessageTimeout=null,this._socketPorts={"http:":[80,3e3],"https:":[443,3443]},this._channelOpen=!1,this._signalingServer=null,this._signalingServerProtocol=window.location.protocol,this._signalingServerPort=null,this._socket=null,this._socketUseXDR=!1,this._enableIceRestart=!1,this._hasMCU=!1,this._path=null,this._readyState=null,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._streams={userMedia:null,screenshare:null},this._streamsDefaultSettings={userMedia:{audio:{stereo:!1},video:{resolution:{width:640,height:480},frameRate:50}},screenshare:{video:!0}},this._streamsMutedSettings={audioMuted:!1,videoMuted:!1},this._streamsBandwidthSettings={googleX:{},bAS:{}},this._streamsStoppedCbs={},this._streamsSession={},this._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},this._publishOnly=!1,this._parentId=null,this._recordings={},this._currentRecordingId=!1,this._recordingStartInterval=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType=this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._bandwidthAdjuster=null,this._peerConnStatus={},this._joinRoomManager={timestamp:0,socketsFn:[]},this._initOptions={}}!function(){Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,r=!{toString:null}.propertyIsEnumerable("toString"),e=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],o=e.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var c=[];for(var l in n)t.call(n,l)&&c.push(l);if(r)for(var p=0;o>p;p++)t.call(n,e[p])&&c.push(e[p]);return c}}())}(),function(){function t(t){return 10>t?"0"+t:t}Date.prototype.toISOString=function(){return this.getUTCFullYear()+"-"+t(this.getUTCMonth()+1)+"-"+t(this.getUTCDate())+"T"+t(this.getUTCHours())+":"+t(this.getUTCMinutes())+":"+t(this.getUTCSeconds())+"."+(this.getUTCMilliseconds()/1e3).toFixed(3).slice(2,5)+"Z"}}(),function(){"function"!=typeof Date.now&&(Date.now=function(){return(new Date).getTime()})}(),function(e,t){function n(e){var n=t[e];t[e]=function(e){return o(n(e))}}function a(t,n,a){return(a=this).attachEvent("on"+t,function(t){var t=t||e.event;t.preventDefault=t.preventDefault||function(){t.returnValue=!1},t.stopPropagation=t.stopPropagation||function(){t.cancelBubble=!0},n.call(a,t)})}function o(e,t){if(t=e.length)for(;t--;)e[t].addEventListener=a;else e.addEventListener=a;return e}e.addEventListener||(o([t,e]),"Element"in e?e.Element.prototype.addEventListener=a:(t.attachEvent("onreadystatechange",function(){o(t.all)}),n("getElementsByTagName"),n("getElementById"),n("createElement"),o(t.all)))}(window,document),function(){if("performance"in window==0&&(window.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in window.performance==0){var a=Date.now();performance.timing&&performance.timing.navigationStart&&(a=performance.timing.navigationStart),window.performance.now=function(){return Date.now()-a}}}(),window.BlobBuilder=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,Array.prototype.forEach||(Array.prototype.forEach=function(callback){var T,k;if(null==this)throw new TypeError("this is null or not defined");var O=Object(this),len=O.length>>>0;if("function"!=typeof callback)throw new TypeError(callback+" is not a function");for(arguments.length>1&&(T=arguments[1]),k=0;k"],error),void self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CREATE_ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))}self._dataChannels[peerId]?self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel.label===channelName&&(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING):(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING,self._dataChannels[peerId]={},log.debug([peerId,"RTCDataChannel",channelProp,"initializing main DataChannel"])),dataChannel.onerror=function(evt){var channelError=evt.error||evt;log.error([peerId,"RTCDataChannel",channelProp,"Datachannel has an exception ->"],channelError),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,channelError,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onbufferedamountlow=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel buffering data transfer low"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.BUFFERED_AMOUNT_LOW,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onmessage=function(event){self._processDataChannelData(event.data,peerId,channelName,channelType)};var onOpenHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has opened"]),dataChannel.bufferedAmountLowThreshold=bufferThreshold||0,self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.OPEN,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))};dataChannel.readyState===self.DATA_CHANNEL_STATE.OPEN?setTimeout(onOpenHandlerFn,1):(self._trigger("dataChannelState",dataChannel.readyState,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),dataChannel.onopen=onOpenHandlerFn);var onCloseHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has closed"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSED,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),self._peerConnections[peerId]&&self._peerConnections[peerId].remoteDescription&&self._peerConnections[peerId].remoteDescription.sdp&&(-1===self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")||self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application 0")>0)||channelType===self.DATA_CHANNEL_TYPE.MESSAGING&&setTimeout(function(){self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[peerId].localDescription&&self._peerConnections[peerId].localDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&(log.debug([peerId,"RTCDataChannel",channelProp,"Reviving Datachannel connection"]),self._createDataChannel(peerId,channelName,bufferThreshold,!0))},100)};if("firefox"===AdapterJS.webrtcDetectedBrowser){var hasTriggeredClose=!1,timeBlockAfterClosing=0;dataChannel.onclose=function(){hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())};var onFFClosed=setInterval(function(){dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSED||hasTriggeredClose||5===timeBlockAfterClosing?(clearInterval(onFFClosed),hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())):dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSING&&timeBlockAfterClosing++},1e3)}else dataChannel.onclose=onCloseHandlerFn;channelType===self.DATA_CHANNEL_TYPE.MESSAGING?self._dataChannels[peerId].main={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}:self._dataChannels[peerId][channelName]={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}},Skylink.prototype.refreshDatachannel=function(peerId){var self=this;if(self._dataChannels[peerId]&&self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel){var channelName=self._dataChannels[peerId].main.channelName,channelType=self._dataChannels[peerId].main.channelType,bufferThreshold=self._dataChannels[peerId].main.channel.bufferedAmountLowThreshold||0;channelType===self.DATA_CHANNEL_TYPE.MESSAGING&&setTimeout(function(){self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[peerId].localDescription&&self._peerConnections[peerId].localDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&(self._closeDataChannel(peerId,"main",!0),log.debug([peerId,"RTCDataChannel","main","Reviving Datachannel connection"]),self._createDataChannel(peerId,channelName,bufferThreshold,!0))},100)}else log.debug([peerId,"RTCDataChannel","Not a valid Datachannel connection"])},Skylink.prototype._getDataChannelBuffer=function(peerId,channelProp){if("object"==typeof peerId)return{bufferedAmountLow:"number"==typeof peerId.bufferedAmountLow?peerId.bufferedAmountLow:parseInt(peerId.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?peerId.bufferedAmountLowThreshold:parseInt(peerId.bufferedAmountLowThreshold,10)||0};if(!(this._dataChannels[peerId]&&this._dataChannels[peerId][channelProp]&&this._dataChannels[peerId][channelProp].channel))return{bufferedAmountLow:0,bufferedAmountLowThreshold:0};var channel=this._dataChannels[peerId][channelProp].channel;return{bufferedAmountLow:"number"==typeof channel.bufferedAmountLow?channel.bufferedAmountLow:parseInt(channel.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof channel.bufferedAmountLowThreshold?channel.bufferedAmountLowThreshold:parseInt(channel.bufferedAmountLowThreshold,10)||0}},Skylink.prototype._sendMessageToDataChannel=function(peerId,data,channelProp,doNotConvert){var self=this;if(channelProp&&channelProp!==peerId||(channelProp="main"),!("object"==typeof data&&data||data&&"string"==typeof data))return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping invalid data ->"],data);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Peer connection does not exists or is closed ->"],data);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Datachannel connection does not exists ->"],data);var channelName=self._dataChannels[peerId][channelProp].channelName,channelType=self._dataChannels[peerId][channelProp].channelType,readyState=self._dataChannels[peerId][channelProp].channel.readyState,messageType="object"==typeof data&&data.type===self._DC_PROTOCOL_TYPE.MESSAGE?self.DATA_CHANNEL_MESSAGE_ERROR.MESSAGE:self.DATA_CHANNEL_MESSAGE_ERROR.TRANSFER;if(readyState!==self.DATA_CHANNEL_STATE.OPEN){var notOpenError='Failed sending message as Datachannel connection state is not opened. Current readyState is "'+readyState+'"';throw log.error([peerId,"RTCDataChannel",channelProp,notOpenError+" ->"],data),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,new Error(notOpenError),channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),new Error(notOpenError)}try{doNotConvert||"object"!=typeof data?(log.debug([peerId,"RTCDataChannel",channelProp,"Sending data with size ->"],data.size||data.length||data.byteLength),self._dataChannels[peerId][channelProp].channel.send(data)):(log.debug([peerId,"RTCDataChannel",channelProp,'Sending "'+data.type+'" protocol message ->'],data),self._dataChannels[peerId][channelProp].channel.send(JSON.stringify(data)))}catch(error){throw log.error([peerId,"RTCDataChannel",channelProp,"Failed sending "+(doNotConvert||"object"!=typeof data?"data":'"'+data.type+'" protocol message')+" ->"],error),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,error,channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),error}},Skylink.prototype._closeDataChannel=function(peerId,channelProp,isCloseMainChannel){var self=this;if(!self._dataChannels[peerId])return void log.warn([peerId,"RTCDataChannel",channelProp||null,"Aborting closing Datachannels as Peer connection does not have Datachannel sessions"]);var closeFn=function(rChannelProp){var channelName=self._dataChannels[peerId][rChannelProp].channelName,channelType=self._dataChannels[peerId][rChannelProp].channelType;self._dataChannels[peerId][rChannelProp].readyState!==self.DATA_CHANNEL_STATE.CLOSED&&(log.debug([peerId,"RTCDataChannel",channelProp,"Closing Datachannel"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSING,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(peerId,rChannelProp)),self._dataChannels[peerId][rChannelProp].channel.close(),delete self._dataChannels[peerId][rChannelProp])};if(isCloseMainChannel)closeFn(channelProp);else if(channelProp&&"main"!==channelProp){if(!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Aborting closing Datachannel as it does not exists"]);closeFn(channelProp)}else{for(var channelNameProp in self._dataChannels)self._dataChannels[peerId].hasOwnProperty(channelNameProp)&&self._dataChannels[peerId][channelNameProp]&&closeFn(channelNameProp);delete self._dataChannels[peerId]}},Skylink.prototype._base64ToBlob=function(dataURL){for(var byteString=atob(dataURL),ab=new ArrayBuffer(byteString.length),ia=new Uint8Array(ab),j=0;jchunkSize){for(;blobByteSize-1>endCount;)endCount=startCount+chunkSize,chunksArray.push(blob.slice(startCount,endCount)),startCount+=chunkSize;blobByteSize-(startCount+1)>0&&chunksArray.push(blob.slice(startCount,blobByteSize-1))}else chunksArray.push(blob);return chunksArray},Skylink.prototype._chunkDataURL=function(dataURL,chunkSize){var outputStr=dataURL,dataURLArray=[],startCount=0,endCount=0,dataByteSize=dataURL.size||dataURL.length;if(dataByteSize>chunkSize){for(;dataByteSize-1>endCount;)endCount=startCount+chunkSize,dataURLArray.push(outputStr.slice(startCount,endCount)),startCount+=chunkSize;dataByteSize-(startCount+1)>0&&chunksArray.push(outputStr.slice(startCount,dataByteSize-1))}else dataURLArray.push(outputStr);return dataURLArray},Skylink.prototype.sendBlobData=function(data,timeout,targetPeerId,sendChunksAsBinary,callback){this._startDataTransfer(data,timeout,targetPeerId,sendChunksAsBinary,callback,"blob")},Skylink.prototype.sendURLData=function(data,timeout,targetPeerId,callback){this._startDataTransfer(data,timeout,targetPeerId,callback,null,"data")},Skylink.prototype.respondBlobRequest=Skylink.prototype.acceptDataTransfer=function(peerId,transferId,accept){var self=this;if("string"!=typeof transferId&&"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as data transfer ID or peer ID is not provided"]);if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as Peer does not have any Datachannel connections"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as invalid transfer ID is provided"])
+;var channelProp="main",dataChannelStateCbFn=null;self._dataChannels[peerId][transferId]&&(channelProp=transferId),self.once("dataTransferState",function(){dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),delete self._dataTransfers[transferId],self._dataChannels[peerId]&&("main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),channelProp===transferId&&self._closeDataChannel(peerId,transferId))},function(state,evtTransferId,evtPeerId){return evtTransferId===transferId&&evtPeerId===peerId&&[self.DATA_TRANSFER_STATE.ERROR,self.DATA_TRANSFER_STATE.CANCEL,self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED,self.DATA_TRANSFER_STATE.USER_REJECTED].indexOf(state)>-1}),accept?(log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]),dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){log.error([peerId,"RTCDataChannel",channelProp,'Data transfer "'+transferId+'" has been terminated due to connection.']),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD,message:new Error("Data transfer terminated as Peer Datachannel connection closed abruptly.")})},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_STATE.MESSAGING:channelName===transferId)&&[self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED,self.DATA_CHANNEL_STATE.ERROR].indexOf(state)>-1:void self.off("dataChannelState",dataChannelStateCbFn)}),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:0},channelProp),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_STARTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)):(log.warn([peerId,"RTCDataChannel",transferId,"Rejected data transfer and data transfer request has been aborted"]),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:-1},channelProp),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_REJECTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as User has rejected data transfer request."),transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD}))},Skylink.prototype.cancelBlobTransfer=Skylink.prototype.cancelDataTransfer=function(peerId,transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer ID is not provided"]);if(!peerId||"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as peer ID is not provided"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer session does not exists."]);log.debug([peerId,"RTCDataChannel",transferId,"Canceling data transfer ..."]);var emitEventFn=function(peers,transferInfoPeerId){for(var i=0;i0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},"main"),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},transferId),emitEventFn(Object.keys(self._dataTransfers[transferId].peers.main).concat(Object.keys(self._dataTransfers[transferId].peers[transferId])))}else{var channelProp="main";if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as Peer does not have any Datachannel connections"]);self._dataChannels[peerId][transferId]&&(channelProp=transferId),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},channelProp),emitEventFn([peerId],peerId)}},Skylink.prototype.sendP2PMessage=function(message,targetPeerId){var listOfPeers=Object.keys(this._dataChannels),isPrivate=!1;if(Array.isArray(targetPeerId)?(listOfPeers=targetPeerId,isPrivate=!0):targetPeerId&&"string"==typeof targetPeerId&&(listOfPeers=[targetPeerId],isPrivate=!0),!this._inRoom||!this._user||!this._user.sid)return void log.error("Unable to send message as User is not in Room. ->",message);if(!this._initOptions.enableDataChannel)return void log.error("Unable to send message as User does not have Datachannel enabled. ->",message);for(var i=0;i-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeStreamingFn=function(error){log.error(error)};if(!this._inRoom||!this._user||!this._user.sid)return emitErrorBeforeStreamingFn("Unable to start data streaming as User is not in Room.");if(!this._initOptions.enableDataChannel)return emitErrorBeforeStreamingFn("Unable to start data streaming as User does not have Datachannel enabled.");if(0===listOfPeers.length)return emitErrorBeforeStreamingFn("Unable to start data streaming as there are no Peers to start session with.");if(self._hasMCU)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature is current not supported by MCU yet.");if(!self._initOptions.enableSimultaneousTransfers)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature requires simultaneous data transfers to be enabled");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},listenToPeerFn=function(peerId,channelProp){var hasStarted=!1;sessions[peerId]=channelProp,self.once("dataStreamState",function(){},function(state,evtTransferId,evtPeerId,evtSessionInfo){if(evtTransferId===transferId&&evtPeerId===peerId){evtSessionInfo.chunk;return delete clone(evtSessionInfo).chunk,state===self.DATA_STREAM_STATE.SENDING_STARTED?void(hasStarted=!0):hasStarted&&[self.DATA_STREAM_STATE.ERROR,self.DATA_STREAM_STATE.SENDING_STOPPED].indexOf(state)>-1?(channelProp===transferId&&self._closeDataChannel(peerId,transferId),self._dataStreams[transferId]&&self._dataStreams[transferId].sessions[peerId]&&(delete self._dataStreams[transferId].sessions[peerId],0===Object.keys(self._dataStreams[transferId].sessions).length&&delete self._dataStreams[transferId]),!0):void 0}})},i=0;i-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE)};if(peersNonInterop.length>0)if(self._hasMCU)waitForChannelOpenFn("MCU",peersNonInterop);else for(var pni=0;pni0)if(self._hasMCU)startDataSessionFn("MCU","main",peersInterop);else for(var pi=0;piself._CHUNK_DATAURL_SIZE:updatedDataChunk.length>self._BINARY_FILE_SIZE)return void log.error("Failed streaming data chunk as data chunk exceeds maximum chunk limit.");var sessionInfo={chunk:updatedDataChunk,chunkSize:updatedDataChunk.size||updatedDataChunk.length||updatedDataChunk.byteLength,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){var onSendDataFn=function(buffer){self._sendMessageToDataChannel(peerId,buffer,channelProp,!0);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype.stopStreamingData=function(transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error("Failed streaming data chunk as stream session ID is not provided.");if(!(self._inRoom&&self._user&&self._user.sid))return void log.error("Failed streaming data chunk as User is not in the Room.");if(!self._dataStreams[transferId])return void log.error("Failed stopping data streaming session as it does not exists.");if(!self._dataStreams[transferId].isUpload)return void log.error("Failed stopping data streaming session as it is not sending.");if(self._hasMCU)return void log.error("Failed stopping data streaming session as MCU does not support this feature yet.");var sessionInfo={chunk:null,chunkSize:0,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:transferId,size:0,originalSize:0,dataType:"fastBinaryStop",mimeType:null,chunkType:self._dataStreams[transferId].sessionChunkType,chunkSize:0,timeout:0,isPrivate:self._dataStreams[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype._startDataTransfer=function(data,timeout,targetPeerId,sendChunksAsBinary,callback,sessionType){var self=this,transferId=(self._user?self._user.sid:"")+"_"+(new Date).getTime(),transferErrors={},transferCompleted=[],chunks=[],listOfPeers=Object.keys(self._peerConnections),sessionChunkType="string",transferInfo={name:null,size:null,chunkSize:null,chunkType:null,dataType:null,mimeType:null,direction:self.DATA_TRANSFER_TYPE.UPLOAD,timeout:60,isPrivate:!1,percentage:0};"number"==typeof timeout?transferInfo.timeout=timeout:Array.isArray(timeout)?listOfPeers=timeout:timeout&&"string"==typeof timeout?listOfPeers=[timeout]:timeout&&"boolean"==typeof timeout?sessionChunkType="binary":"function"==typeof timeout&&(callback=timeout),Array.isArray(targetPeerId)?listOfPeers=targetPeerId:targetPeerId&&"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:targetPeerId&&"boolean"==typeof targetPeerId?sessionChunkType="binary":"function"==typeof targetPeerId&&(callback=targetPeerId),sendChunksAsBinary&&"boolean"==typeof sendChunksAsBinary?sessionChunkType="binary":"function"==typeof sendChunksAsBinary&&(callback=sendChunksAsBinary),listOfPeers.indexOf("MCU")>-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeDataTransferFn=function(error){if(log.error(error),"function"==typeof callback){var transferErrors={};if(0===listOfPeers.length)transferErrors.self=new Error(error);else for(var i=0;i0){var bsChunkSize="firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_CHUNK_FILE_SIZE:self._CHUNK_FILE_SIZE,bsChunks=self._chunkBlobData(new Blob(chunks),bsChunkSize);self._dataTransfers[transferId].enforceBSInfo={chunkSize:4*Math.ceil(bsChunkSize/3),chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,size:4*Math.ceil(transferInfo.originalSize/3),chunks:bsChunks}}}for(var completeFn=function(peerId,error){transferCompleted.indexOf(peerId)>-1||(log.debug([peerId,"RTCDataChannel",transferId,"Data transfer result. Is errors present? ->"],error),transferCompleted.push(peerId),error&&(transferErrors[peerId]=new Error(error)),listOfPeers.length===transferCompleted.length&&(log.log([null,"RTCDataChannel",transferId,"Data transfer request completed"]),"function"==typeof callback&&(Object.keys(transferErrors).length>0?callback({transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),transferErrors:transferErrors,listOfPeers:listOfPeers},null):callback(null,{transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),listOfPeers:listOfPeers}))))},i=0;i0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,"main",Object.keys(self._dataTransfers[transferId].peers.main)),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,transferId,Object.keys(self._dataTransfers[transferId].peers[transferId])))},Skylink.prototype._startDataTransferToPeer=function(transferId,peerId,callback,channelProp,targetPeers){var self=this,peerConnectionStateCbFn=null,dataChannelStateCbFn=null,emitEventFn=function(cb){for(var peers=targetPeers||[peerId],i=0;i-1&&(log.warn([peerId,"RTCDataChannel",transferId,"Binary data chunks transfer is not yet supported with Peer connecting from Android, iOS and C++ SDK. Fallbacking to binary string data chunks transfer."]),size=self._dataTransfers[transferId].enforceBSInfo.size,chunkSize=self._dataTransfers[transferId].enforceBSInfo.chunkSize,chunkType="string"),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:self._dataTransfers[transferId].name,size:size,originalSize:self._dataTransfers[transferId].originalSize,dataType:self._dataTransfers[transferId].sessionType,mimeType:self._dataTransfers[transferId].mimeType,chunkType:chunkType,chunkSize:chunkSize,timeout:self._dataTransfers[transferId].timeout,isPrivate:self._dataTransfers[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp),emitEventFn(function(evtPeerId){self._trigger("incomingDataRequest",transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_UPLOAD_REQUEST,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)})};if("MCU"!==peerId){var dataTransferStateCbFn=function(state,evtTransferId,evtPeerId,transferInfo,error){peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],callback(peerId,state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?null:error.message.message||error.message.toString()),delete self._dataTransfers[transferId].sessions[peerId],self._hasMCU&&0===Object.keys(self._dataTransfers[transferId].peers.main).length&&self._dataChannels.MCU&&self._dataChannels.MCU.main?self._dataChannels.MCU.main.transferId=null:"main"===channelProp&&self._dataChannels[peerId]&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),
+0===Object.keys(self._dataTransfers[transferId].sessions).length&&delete self._dataTransfers[transferId]};self.once("dataTransferState",dataTransferStateCbFn,function(state,evtTransferId,evtPeerId){return self._dataTransfers[transferId]&&(self._hasMCU?self._dataTransfers[transferId].peers.main[peerId]||self._dataTransfers[transferId].peers[transferId][peerId]:self._dataTransfers[transferId].sessions[peerId])?evtTransferId===transferId&&evtPeerId===peerId&&[self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,self.DATA_TRANSFER_STATE.ERROR,self.DATA_TRANSFER_STATE.CANCEL,self.DATA_TRANSFER_STATE.REJECTED].indexOf(state)>-1:(dataTransferStateCbFn&&self.off("dataTransferState",dataTransferStateCbFn),peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),void(dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn)))})}if(!self._peerConnections[peerId])return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer connection does not exists.");if(!self._peerInformations[peerId])return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer connection does not exists.");if(self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer connection is not stable.");if(!self._dataTransfers[transferId])return void returnErrorBeforeTransferFn("Unable to start data transfer as data transfer session is not in order.");if(!self._dataChannels[peerId]||!self._dataChannels[peerId].main)return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel connection does not exists.");if(self._dataChannels[peerId].main.channel.readyState!==self.DATA_CHANNEL_STATE.OPEN)return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel connection is not opened.");var streamId=self._dataChannels[peerId].main.streamId;if(streamId&&"main"===channelProp&&self._dataStreams[streamId]&&("string"===self._dataStreams[streamId].sessionChunkType&&("string"===self._dataTransfers[transferId].sessionChunkType||self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1)||"binary"===self._dataStreams[streamId].sessionChunkType&&"binary"===self._dataStreams[streamId].sessionChunkType&&-1===self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)))return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel currently has an active "+self._dataStreams[streamId].sessionChunkType+" data streaming session.");var protocolVer=(self._peerInformations[peerId].agent||{}).DTProtocolVersion||"0.1.0",requireInterop=self._isLowerThanVersion(protocolVer,"0.1.2")||!self._initOptions.enableSimultaneousTransfers;return self._isLowerThanVersion(protocolVer,"0.1.2")&&"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer do not support DATA_URL type of data transfers"):"MCU"!==peerId&&self._hasMCU?(channelProp=requireInterop?"main":transferId,peerConnectionStateCbFn=function(){returnErrorBeforeTransferFn("Data transfer terminated as Peer connection is not stable.")},self.once("peerConnectionState",peerConnectionStateCbFn,function(state,evtPeerId){return self._dataTransfers[transferId]?state!==self.PEER_CONNECTION_STATE.STABLE&&evtPeerId===peerId:void self.off("peerConnectionState",peerConnectionStateCbFn)}),requireInterop):(requireInterop||"main"===channelProp)&&self._dataChannels[peerId].main.transferId?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel has a data transfer in-progress."):(self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0},dataChannelStateCbFn=function(state,evtPeerId,error){self._dataTransfers[transferId].sessions[peerId].ackN>=self._dataTransfers[transferId].chunks.length-1||returnErrorBeforeTransferFn(error?error.message||error.toString():"Data transfer terminated as Peer Datachannel connection closed abruptly.")},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void self.off("dataChannelState",dataChannelStateCbFn);if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId))return state===self.DATA_CHANNEL_STATE.OPEN&&"main"!==channelProp&&channelName===transferId?(self._dataChannels[peerId][channelProp].transferId=transferId,sendWRQFn(),!1):[self.DATA_CHANNEL_STATE.CREATE_ERROR,self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(channelProp="main",self._dataChannels[peerId].main.transferId=transferId,sendWRQFn()):(channelProp=transferId,self._createDataChannel(peerId,transferId,"data"===self._dataTransfers[transferId].sessionType?self._CHUNK_DATAURL_SIZE:"string"===self._dataTransfers[transferId].sessionChunkType?"firefox"===AdapterJS.webrtcDetectedBrowser?16384:65546:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE))))},Skylink.prototype._getTransferInfo=function(transferId,peerId,returnDataProp,hidePercentage,returnDataAtStart){if(!this._dataTransfers[transferId])return{};var transferInfo={name:this._dataTransfers[transferId].name,size:this._dataTransfers[transferId].size,dataType:this._dataTransfers[transferId].dataType||this.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:this._dataTransfers[transferId].mimeType||null,chunkSize:this._dataTransfers[transferId].chunkSize,chunkType:this._dataTransfers[transferId].chunkType,timeout:this._dataTransfers[transferId].timeout,isPrivate:this._dataTransfers[transferId].isPrivate,direction:this._dataTransfers[transferId].direction};if(this._dataTransfers[transferId].originalSize?transferInfo.size=this._dataTransfers[transferId].originalSize:this._dataTransfers[transferId].chunkType===this.DATA_TRANSFER_DATA_TYPE.BINARY_STRING&&(transferInfo.size=Math.ceil(3*transferInfo.size/4)),!hidePercentage){if(transferInfo.percentage=0,!this._dataTransfers[transferId].sessions[peerId])return returnDataProp&&(transferInfo.data=null),transferInfo;if(this._dataTransfers[transferId].direction===this.DATA_TRANSFER_TYPE.DOWNLOAD)this._dataTransfers[transferId].sessions[peerId].receivedSize===this._dataTransfers[transferId].sessions[peerId].size?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].receivedSize/this._dataTransfers[transferId].size*100).toFixed(2),10);else{var chunksLength=this._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?this._dataTransfers[transferId].enforceBSInfo.chunks.length:this._dataTransfers[transferId].chunks.length;this._dataTransfers[transferId].sessions[peerId].ackN===chunksLength?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].ackN/chunksLength*100).toFixed(2),10)}returnDataProp&&("number"!=typeof returnDataAtStart?100===transferInfo.percentage?transferInfo.data=this._getTransferData(transferId):transferInfo.data=null:(transferInfo.percentage=returnDataAtStart,0===returnDataAtStart&&(transferInfo.data=this._getTransferData(transferId))))}return transferInfo},Skylink.prototype._getTransferData=function(transferId){if(!this._dataTransfers[transferId])return null;if(this._dataTransfers[transferId].dataType===this.DATA_TRANSFER_SESSION_TYPE.BLOB){var mimeType={name:this._dataTransfers[transferId].name};return this._dataTransfers[transferId].mimeType&&(mimeType.type=this._dataTransfers[transferId].mimeType),new Blob(this._dataTransfers[transferId].chunks,mimeType)}return this._dataTransfers[transferId].chunks.join("")},Skylink.prototype._handleDataTransferTimeoutForPeer=function(transferId,peerId,setPeerTO){var self=this;if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer does not exists for Peer. Ignoring timeout."]);log.debug([peerId,"RTCDataChannel",transferId,"Clearing data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer&&clearTimeout(self._dataTransfers[transferId].sessions[peerId].timer),self._dataTransfers[transferId].sessions[peerId].timer=null,setPeerTO&&(log.debug([peerId,"RTCDataChannel",transferId,"Setting data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer=setTimeout(function(){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer already ended for Peer. Ignoring expired timeout."]);if(!self._user||!self._user.sid)return void log.debug([peerId,"RTCDataChannel",transferId,"User is not in Room. Ignoring expired timeout."]);if(!self._dataChannels[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Datachannel connection does not exists. Ignoring expired timeout."]);log.error([peerId,"RTCDataChannel",transferId,"Data transfer response has timed out."]);var emitEventFn=function(cb){if("MCU"===peerId){for(var broadcastedPeers=[self._dataTransfers[transferId].peers.main,self._dataTransfers[transferId].peers[transferId]],i=0;i"],rawData);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping data received from Peer as Datachannel connection is not present ->"],rawData);if("string"==typeof rawData)try{var protocolData=JSON.parse(rawData);if(isStreamChunk=!1,log.debug([peerId,"RTCDataChannel",channelProp,'Received protocol "'+protocolData.type+'" message ->'],protocolData),[self._DC_PROTOCOL_TYPE.ACK,self._DC_PROTOCOL_TYPE.ERROR,self._DC_PROTOCOL_TYPE.CANCEL].indexOf(protocolData.type)>-1&&!(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded protocol message as data transfer session is not present ->"],protocolData);switch(protocolData.type){case self._DC_PROTOCOL_TYPE.WRQ:if(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId])return log.warn([peerId,"RTCDataChannel",channelProp,"Rejecting bidirectional data transfer request as it is currently not supported in the SDK ->"],protocolData),void self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,ackN:-1,sender:self._user.sid},channelProp);self._WRQProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ACK:self._ACKProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ERROR:self._ERRORProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.CANCEL:self._CANCELProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.MESSAGE:self._MESSAGEProtocolHandler(peerId,protocolData,channelProp);break;default:log.warn([peerId,"RTCDataChannel",channelProp,'Discarded unknown "'+protocolData.type+'" message ->'],protocolData)}}catch(error){if(rawData.indexOf("{")>-1&&rawData.indexOf("}")>0)throw log.error([peerId,"RTCDataChannel",channelProp,"Failed parsing protocol step data error ->"],{data:rawData,error:error}),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(peerId,channelProp)),error;if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING;if(isStreamChunk||self._dataTransfers[transferId].dataType===self.DATA_TRANSFER_SESSION_TYPE.DATA_URL)log.debug([peerId,"RTCDataChannel",channelProp,"Received string data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.length||rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.STRING,rawData.length||rawData.size||0,channelProp);else{var removeSpaceData=rawData.replace(/\s|\r|\n/g,"");log.debug([peerId,"RTCDataChannel",channelProp,"Received binary string data chunk @"+self._dataTransfers[transferId].sessions[peerId].ackN+" with size ->"],removeSpaceData.length||removeSpaceData.size),self._DATAProtocolHandler(peerId,self._base64ToBlob(removeSpaceData),self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,removeSpaceData.length||removeSpaceData.size||0,channelProp)}}else{if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);if(rawData instanceof Blob)log.debug([peerId,"RTCDataChannel",channelProp,"Received blob data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.BLOB,rawData.size,channelProp);else{var byteArray=rawData,blob=null;if(rawData.constructor&&"Array"===rawData.constructor.name&&(byteArray=new Int8Array(rawData)),"IE"===AdapterJS.webrtcDetectedBrowser){if(window.BlobBuilder){var bb=new BlobBuilder;bb.append(rawData.constructor&&"ArrayBuffer"===rawData.constructor.name?byteArray:new Uint8Array(byteArray).buffer),blob=bb.getBlob()}}else blob=new Blob([byteArray]);log.debug([peerId,"RTCDataChannel",channelProp,"Received arraybuffer data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],blob.size),self._DATAProtocolHandler(peerId,blob,self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,blob.size,channelProp)}}},Skylink.prototype._WRQProtocolHandler=function(peerId,data,channelProp){var self=this,transferId="main"===channelProp?data.transferId||null:channelProp,senderPeerId=data.sender||peerId;if(["fastBinaryStart","fastBinaryStop"].indexOf(data.dataType)>-1)if("fastBinaryStart"===data.dataType){transferId||(transferId="stream_"+peerId+"_"+(new Date).getTime()),self._dataStreams[transferId]={chunkSize:0,chunkType:"string"===data.chunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:data.chunkType,isPrivate:!!data.isPrivate,isStringStream:"string"===data.chunkType,senderPeerId:senderPeerId,isUpload:!1},self._dataChannels[peerId][channelProp].streamId=transferId;self.once("dataChannelState",function(){},function(state,evtPeerId,channelName,channelType,error){if(!self._dataStreams[transferId])return!0;if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId&&channelType===self.DATA_CHANNEL_TYPE.DATA)&&[self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');return self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},updatedError),!0}}),self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STARTED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStarted",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1)}else transferId=self._dataChannels[peerId][channelProp].streamId,self._dataStreams[transferId]&&!self._dataStreams[transferId].isUpload&&(self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STOPPED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStopped",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1),self._dataChannels[peerId][channelProp].streamId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp),delete self._dataStreams[transferId]);else transferId||(transferId="transfer_"+peerId+"_"+(new Date).getTime()),self._dataTransfers[transferId]={name:data.name||transferId,size:data.size||0,chunkSize:data.chunkSize,originalSize:data.originalSize||0,timeout:data.timeout||60,isPrivate:!!data.isPrivate,senderPeerId:data.sender||peerId,dataType:self.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:data.mimeType||null,chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,direction:self.DATA_TRANSFER_TYPE.DOWNLOAD,chunks:[],sessions:{},sessionType:data.dataType||"blob",sessionChunkType:data.chunkType||"string"},"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?(self._dataTransfers[transferId].dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,self._dataTransfers[transferId].chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING):"blob"===self._dataTransfers[transferId].sessionType&&"binary"===self._dataTransfers[transferId].sessionChunkType&&(self._dataTransfers[transferId].chunkType=self._binaryChunkType),self._dataChannels[peerId][channelProp].transferId=transferId,self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0,receivedSize:0},self._trigger("incomingDataRequest",transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!1),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_REQUEST,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)},Skylink.prototype._ACKProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ACK event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};if(data.ackN>-1){if(0===data.ackN)emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_STARTED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,0),null)});else if(self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?data.ackN===self._dataTransfers[transferId].enforceBSInfo.chunks.length:data.ackN===self._dataTransfers[transferId].chunks.length)return self._dataTransfers[transferId].sessions[peerId].ackN=data.ackN,emitEventFn(function(evtPeerId){self._trigger("incomingData",self._getTransferData(transferId),transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,100),null)}),void(self._dataChannels[peerId][channelProp]&&(self._dataChannels[peerId][channelProp].transferId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp)));var uploadFn=function(chunk){self._sendMessageToDataChannel(peerId,chunk,channelProp,!0),data.ackN-1?self._blobToBase64(self._dataTransfers[transferId].enforceBSInfo.chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING?self._blobToBase64(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER?self._blobToArrayBuffer(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):uploadFn(self._dataTransfers[transferId].chunks[data.ackN])}else self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.REJECTED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as Peer has rejected data transfer request"),transferType:self.DATA_TRANSFER_TYPE.UPLOAD})},Skylink.prototype._MESSAGEProtocolHandler=function(peerId,data,channelProp){var senderPeerId=data.sender||peerId;log.log([senderPeerId,"RTCDataChannel",channelProp,"Received P2P message from peer:"],data),this._trigger("incomingMessage",{content:data.data,isPrivate:data.isPrivate,isDataChannel:!0,targetPeerId:this._user.sid,senderPeerId:senderPeerId},senderPeerId,this.getPeerInfo(senderPeerId),!1)},Skylink.prototype._ERRORProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ERROR event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,evtPeerId,self._getTransferInfo(transferId,peerID,!0,!1,!1),{message:new Error(data.content),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._CANCELProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of CANCEL event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(peerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.CANCEL,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error(data.content||"Peer has terminated data transfer."),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._DATAProtocolHandler=function(peerId,chunk,chunkType,chunkSize,channelProp){var self=this,transferId=channelProp,senderPeerId=peerId;if(self._dataChannels[peerId]&&self._dataChannels[peerId][channelProp]){var streamId=self._dataChannels[peerId][channelProp].streamId;if(streamId&&self._dataStreams[streamId]&&("string"==typeof chunk&&"string"===self._dataStreams[streamId].sessionChunkType||chunk instanceof Blob&&"binary"===self._dataStreams[streamId].sessionChunkType))return senderPeerId=self._dataStreams[streamId].senderPeerId||peerId,self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVED,streamId,senderPeerId,{chunk:chunk,chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},null),void self._trigger("incomingDataStream",chunk,transferId,senderPeerId,{chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},!1);if("main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._dataTransfers[transferId].senderPeerId&&(senderPeerId=self._dataTransfers[transferId].senderPeerId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1),self._dataTransfers[transferId].chunkType=chunkType,self._dataTransfers[transferId].sessions[peerId].receivedSize+=chunkSize,self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN]=chunk,self._dataTransfers[transferId].sessions[peerId].receivedSize>=self._dataTransfers[transferId].size)return log.log([peerId,"RTCDataChannel",channelProp,"Data transfer has been completed. Computed size ->"],self._dataTransfers[transferId].sessions[peerId].receivedSize),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN+1},channelProp),self._trigger("incomingData",self._getTransferData(transferId),transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),null),void self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null);self._dataTransfers[transferId].sessions[peerId].ackN+=1,self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN},channelProp),self._handleDataTransferTimeoutForPeer(transferId,peerId,!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOADING,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)}},Skylink.prototype._onIceCandidate=function(targetMid,candidate){var self=this,pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCIceCandidate",null,"Ignoring of ICE candidate event as Peer connection does not exists ->"],candidate);if(candidate.candidate){pc.gathering||(log.log([targetMid,"RTCIceCandidate",null,"ICE gathering has started."]),pc.gathering=!0,pc.gathered=!1,self._trigger("candidateGenerationState",self.CANDIDATE_GENERATION_STATE.GATHERING,targetMid));var candidateType=candidate.candidate.split(" ")[7];if(log.debug([targetMid,"RTCIceCandidate",candidateType,"Generated ICE candidate ->"],candidate),"endOfCandidates"===candidateType||!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].localDescription&&self._peerConnections[targetMid].localDescription.sdp&&self._peerConnections[targetMid].localDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return void log.warn([targetMid,"RTCIceCandidate",candidateType,"Dropping of sending ICE candidate end-of-candidates signal or unused ICE candidates to prevent errors ->"],candidate);if(self._initOptions.filterCandidatesType[candidateType]){if(!self._hasMCU||!self._initOptions.forceTURN)return void log.warn([targetMid,"RTCIceCandidate",candidateType,"Dropping of sending ICE candidate as it matches ICE candidate filtering flag ->"],candidate);log.warn([targetMid,"RTCIceCandidate",candidateType,"Not dropping of sending ICE candidate as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured ->"],candidate)}if(self._gatheredCandidates[targetMid]||(self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),self._gatheredCandidates[targetMid].sending[candidateType].push({sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate}),!self._initOptions.enableIceTrickle)return void log.warn([targetMid,"RTCIceCandidate",candidateType,"Dropping of sending ICE candidate as trickle ICE is disabled ->"],candidate);log.debug([targetMid,"RTCIceCandidate",candidateType,"Sending ICE candidate ->"],candidate),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.CANDIDATE,label:candidate.sdpMLineIndex,id:candidate.sdpMid,candidate:candidate.candidate,mid:self._user.sid,target:targetMid,rid:self._room.id})}else{if(log.log([targetMid,"RTCIceCandidate",null,"ICE gathering has completed."]),pc.gathered)return;if(pc.gathering=!1,pc.gathered=!0,self._trigger("candidateGenerationState",self.CANDIDATE_GENERATION_STATE.COMPLETED,targetMid),self._initOptions.enableIceTrickle)self._gatheredCandidates[targetMid]&&self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.END_OF_CANDIDATES,
+noOfExpectedCandidates:self._gatheredCandidates[targetMid].sending.srflx.length+self._gatheredCandidates[targetMid].sending.host.length+self._gatheredCandidates[targetMid].sending.relay.length,mid:self._user.sid,target:targetMid,rid:self._room.id});else{var sessionDescription=self._peerConnections[targetMid].localDescription;if(!(sessionDescription&&sessionDescription.type&&sessionDescription.sdp))return void log.warn([targetMid,"RTCSessionDescription",null,"Not sending any session description after ICE gathering completed as it is not present."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,userInfo:self._getUserInfo(targetMid),target:targetMid,rid:self._room.id})}}},Skylink.prototype._addIceCandidateToQueue=function(targetMid,canId,candidate){var candidateType=candidate.candidate.split(" ")[7];log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Buffering ICE candidate."]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.BUFFERED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[],this._peerCandidatesQueue[targetMid].push([canId,candidate])},Skylink.prototype._addIceCandidateFromQueue=function(targetMid){this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[];for(var i=0;i"],error),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},error)};if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Adding ICE candidate."]),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESSING,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[targetMid].remoteDescription&&self._peerConnections[targetMid].remoteDescription.sdp&&self._peerConnections[targetMid].remoteDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),void self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed."));try{self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)}catch(error){onErrorCbFn(error)}},Skylink.prototype._setIceServers=function(passedIceServers){var self=this,iceServerName=null,iceServerProtocol="stun",iceServerPorts={udp:[3478,19302,19303,19304],tcp:[80,443],both:[19305,19306,19307,19308]},iceServers=[{urls:[]},{urls:[]}];return passedIceServers.forEach(function(server){if(0===server.url.indexOf("stun:"))server.url.indexOf("temasys")>0?iceServerName=(server.url.split(":")[1]||"").split("?")[0]||null:iceServers[0].urls.push(server.url);else if(0===server.url.indexOf("turn:")&&server.url.indexOf("@")>0&&server.credential&&!iceServers[1].username&&!iceServers[1].credential){var parts=server.url.split(":"),urlParts=(parts[1]||"").split("@");iceServerName=(urlParts[1]||"").split("?")[0],iceServers[1].username=urlParts[0],iceServers[1].credential=server.credential,iceServerProtocol="turn"}}),self._initOptions.iceServer?iceServers=[{urls:self._initOptions.iceServer.urls,username:iceServers[1].username||null,credential:iceServers[1].credential||null}]:(iceServerName=iceServerName||"turn.temasys.io","turn"!==iceServerProtocol||self._initOptions.enableTURNServer||self._initOptions.forceTURNSSL?"edge"===AdapterJS.webrtcDetectedBrowser?(iceServerPorts.udp=[3478],iceServerPorts.tcp=[],iceServerPorts.both=[],iceServerProtocol="turn"):self._initOptions.forceTURNSSL?"firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion<53?(iceServerPorts.udp=[],iceServerPorts.tcp=[443],iceServerPorts.both=[],iceServerProtocol="turn"):(iceServerPorts.udp=[],iceServerProtocol="turns"):"firefox"===AdapterJS.webrtcDetectedBrowser&&(iceServerPorts.udp=[3478],iceServerPorts.tcp=[443,80]):iceServerProtocol="stun",self._initOptions.TURNServerTransport!==self.TURN_TRANSPORT.UDP||self._initOptions.forceTURNSSL?self._initOptions.TURNServerTransport===self.TURN_TRANSPORT.TCP?(iceServerPorts.tcp=iceServerPorts.tcp.concat(iceServerPorts.both),iceServerPorts.udp=[],iceServerPorts.both=[]):self._initOptions.TURNServerTransport===self.TURN_TRANSPORT.NONE&&(iceServerPorts.tcp=[],iceServerPorts.udp=[]):(iceServerPorts.udp=iceServerPorts.udp.concat(iceServerPorts.both),iceServerPorts.tcp=[],iceServerPorts.both=[]),"stun"===iceServerProtocol&&(iceServerPorts.tcp=[]),"stun"!==iceServerProtocol||self._initOptions.enableSTUNServer?(iceServerPorts.tcp.forEach(function(tcpPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+tcpPort+"?transport=tcp")}),iceServerPorts.udp.forEach(function(udpPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+udpPort+"?transport=udp")}),iceServerPorts.both.forEach(function(bothPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+bothPort)}),self._initOptions.usePublicSTUN||iceServers.splice(0,1)):iceServers=[]),log.log("Output iceServers configuration:",iceServers),{iceServers:iceServers}},Skylink.prototype.refreshConnection=function(targetPeerId,iceRestart,options,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),doIceRestart=!1,bwOptions={};Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:"boolean"==typeof targetPeerId?doIceRestart=targetPeerId:targetPeerId&&"object"==typeof targetPeerId?bwOptions=targetPeerId:"function"==typeof targetPeerId&&(callback=targetPeerId),"boolean"==typeof iceRestart?doIceRestart=iceRestart:iceRestart&&"object"==typeof iceRestart?bwOptions=iceRestart:"function"==typeof iceRestart&&(callback=iceRestart),options&&"object"==typeof options?bwOptions=options:"function"==typeof options&&(callback=options);var emitErrorForPeersFn=function(error){if(log.error(error),"function"==typeof callback){var listOfPeerErrors={};if(0===listOfPeers.length)listOfPeerErrors.self=new Error(error);else for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}},refreshSinglePeer=function(peerId,peerCallback){if(!self._peerConnections[peerId])return error="There is currently no existing peer connection made with the peer. Unable to restart connection",log.error([peerId,null,null,error]),void peerCallback(error);log.log([peerId,"PeerConnection",null,"Restarting peer connection"]),self._restartPeerConnection(peerId,doIceRestart,bwOptions,peerCallback)};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?refreshSinglePeer(peerId,refreshSinglePeerCallback(peerId)):(error="Peer connection with peer does not exists. Unable to restart",log.error([peerId,"PeerConnection",null,error]),refreshSinglePeerCallback(peerId)(error))}}},Skylink.prototype.getConnectionStatus=function(targetPeerId,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),listOfPeerStats={},listOfPeerErrors={};if(Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId&&targetPeerId?listOfPeers=[targetPeerId]:"function"==typeof targetPeerId&&(callback=targetPeerId,targetPeerId=void 0),0===listOfPeers.length)return listOfPeerErrors.self=new Error("There is currently no peer connections to retrieve connection status"),log.error([null,"RTCStatsReport",null,"Retrieving request failure ->"],listOfPeerErrors.self),void("function"==typeof callback&&callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null));"edge"===AdapterJS.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){-1===completedTaskCounter.indexOf(peerId)&&completedTaskCounter.push(peerId),completedTaskCounter.length===listOfPeers.length&&"function"==typeof callback&&(Object.keys(listOfPeerErrors).length>0?callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null):callback(null,{listOfPeers:listOfPeers,connectionStats:listOfPeerStats}))},statsFn=function(peerId){var retrieveFn=function(firstRetrieval,nextCb){return function(err,result){if(err)return log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],error),listOfPeerErrors[peerId]=error,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,error),checkCompletedFn(peerId),void(firstRetrieval&&delete self._peerStats[peerId]);firstRetrieval?nextCb():(listOfPeerStats[peerId]=result,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_SUCCESS,peerId,listOfPeerStats[peerId],null),checkCompletedFn(peerId))}};if(!self._peerStats[peerId])return self._peerStats[peerId]={},log.debug([peerId,"RTCStatsReport",null,"Retrieving first report to tabulate results"]),void self._retrieveStats(peerId,retrieveFn(!0,function(){self._retrieveStats(peerId,retrieveFn())}),!0);self._retrieveStats(peerId,retrieveFn())},i=0;i"],listOfPeerErrors[peerId]),self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,listOfPeerErrors[peerId]),checkCompletedFn(peerId))}},Skylink.prototype._retrieveStats=function(peerId,callback,beSilentOnLogs,isAutoBwStats){var self=this,pc=self._peerConnections[peerId],output={raw:{},connection:{},audio:{sending:{},receiving:{}},video:{sending:{},receiving:{}},selectedCandidate:{local:{},remote:{},consentResponses:{},consentRequests:{},responses:{},requests:{}},certificate:{}};if(!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));if(!pc)return callback(new Error("Peer connection is not initialised"));"edge"!==AdapterJS.webrtcDetectedBrowser&&"AppleWebKit"!==AdapterJS.webrtcDetectedType||log.warn("Current connection stats may not be complete as it is in beta"),output.connection.iceConnectionState=pc.iceConnectionState,output.connection.iceGatheringState=pc.iceGatheringState,output.connection.signalingState=pc.signalingState,output.connection.remoteDescription={type:pc.remoteDescription&&pc.remoteDescription.type||"",sdp:pc.remoteDescription&&pc.remoteDescription.sdp||""},output.connection.localDescription={type:pc.localDescription&&pc.localDescription.type||"",sdp:pc.localDescription&&pc.localDescription.sdp||""},output.connection.candidates={sending:self._getSDPICECandidates(peerId,pc.localDescription,beSilentOnLogs),receiving:self._getSDPICECandidates(peerId,pc.remoteDescription,beSilentOnLogs)},output.connection.dataChannels={},output.connection.constraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,output.connection.optional=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,output.connection.sdpConstraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null,output.audio.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),output.video.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),output.audio.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"audio",beSilentOnLogs),output.video.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"video",beSilentOnLogs),output.certificate.local=self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),output.certificate.remote=self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs);var inboundSSRCs=self._getSDPMediaSSRC(peerId,pc.remoteDescription,beSilentOnLogs);output.audio.receiving.ssrc=inboundSSRCs.audio,output.video.receiving.ssrc=inboundSSRCs.video;var outboundSSRCs=self._getSDPMediaSSRC(peerId,pc.localDescription,beSilentOnLogs);output.audio.sending.ssrc=outboundSSRCs.audio,output.video.sending.ssrc=outboundSSRCs.video,Object.keys(self._dataChannels[peerId]||{}).forEach(function(prop){var channel=self._dataChannels[peerId][prop];output.connection.dataChannels[channel.channel.label]={label:channel.channel.label,readyState:channel.channel.readyState,channelType:self.DATA_CHANNEL_TYPE["main"===prop?"MESSAGING":"DATA"],currentTransferId:channel.transferId||null,currentStreamId:channel.streamId||null}});var certificateFn=function(item,prop){if(0===prop.indexOf("RTCCertificate_"))item.fingerprint===output.certificate.local.fingerprint?(output.certificate.local.derBase64=item.base64Certificate,output.certificate.local.fingerprintAlgorithm=item.fingerprintAlgorithm):item.fingerprint===output.certificate.remote.fingerprint&&(output.certificate.remote.derBase64=item.base64Certificate,output.certificate.remote.fingerprintAlgorithm=item.fingerprintAlgorithm);else if(0===prop.indexOf("ssrc_")&&item.transportId){var pairItem=output.raw[item.transportId]||{};output.certificate.srtpCipher=pairItem.srtpCipher,output.certificate.dtlsCipher=pairItem.dtlsCipher;var localCertItem=output.raw[pairItem.localCertificateId||""]||{};output.certificate.local.fingerprint=localCertItem.googFingerprint,output.certificate.local.fingerprintAlgorithm=localCertItem.googFingerprintAlgorithm,output.certificate.local.derBase64=localCertItem.googDerBase64;var remoteCertItem=output.raw[pairItem.remoteCertificateId||""]||{};output.certificate.remote.fingerprint=remoteCertItem.googFingerprint,output.certificate.remote.fingerprintAlgorithm=remoteCertItem.googFingerprintAlgorithm,output.certificate.remote.derBase64=remoteCertItem.googDerBase64}},candidatePairFn=function(item,prop){if(0===prop.indexOf("RTCIceCandidatePair_")){if("succeeded"!==item.state||output.selectedCandidate.nominated||item.prioirty<(output.selectedCandidate.priority||0))return;for(var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],sending=pc.localDescription&&pc.localDescription.sdp&&pc.localDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],receiving=pc.remoteDescription&&pc.remoteDescription&&pc.remoteDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],computePrioirtyFn=function(controller,controlled){return Math.pow(2,32)*Math.min(controller,controlled)+2*Math.max(controller,controlled)+(controller>controlled?1:0)},computeCanTypeFn=function(type){return"relay"===type?"relayed":"host"===type?"local":"srflx"===type?"serverreflexive":type},s=0;s0?"sending":"receiving";item.codecImplementationName="unknown"===item.codecImplementationName?null:item.codecImplementationName,output[item.mediaType][direction].codec.implementation=item.codecImplementationName||null,item.googCodecName="unknown"===item.googCodecName?null:item.googCodecName,output[item.mediaType][direction].codec.name=item.googCodecName||output[item.mediaType][direction].codec.name}},audioStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPAudioStream")){if(output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.audio.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),"function"!=typeof pc.getReceivers)return}else if(0===prop.indexOf("RTCMediaStreamTrack_remote_audio_"))output.audio.receiving.audioOutputLevel=item.audioLevel;else if(0===prop.indexOf("RTCOutboundRTPAudioStream"))output.audio.sending.targetBitrate=item.targetBitrate||0,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"audio"===item.mediaType&&item.isRemote)output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"audio"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"audio"===item.mediaType)if(prop.indexOf("_recv")>0){output.audio.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.audio.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.audio.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.audio.receiving.totalBytes=bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.audio.receiving.totalPackets=packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.audio.receiving.totalPacketsLost=packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost")}else{output.audio.sending.rtt=parseInt(item.googRtt||"0",10),output.audio.sending.audioInputLevel=parseInt(item.audioInputLevel||"0",10),output.audio.sending.echoReturnLoss=parseInt(item.googEchoCancellationReturnLoss||"0",10),output.audio.sending.echoReturnLossEnhancement=parseInt(item.googEchoCancellationReturnLossEnhancement||"0",10);var bytesSent=parseInt(item.bytesSent||"0",10);output.audio.sending.totalBytes=bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.audio.sending.totalPackets=packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent")}else if(0===prop.indexOf("inbound_rtp_audio"))output.audio.receiving.jitter=item.jitter||0,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if(0===prop.indexOf("outbound_rtp_audio")){output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.audio.sending.rtt=rtcpItem.roundTripTime||0}}else{output.audio.sending.targetBitrate=item.targetBitrate,output.audio.sending.rtt=item.roundTripTime,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.audio.sending.audioInputLevel=trackItem.audioLevel,output.audio.sending.echoReturnLoss=trackItem.echoReturnLoss,output.audio.sending.echoReturnLossEnhancement=trackItem.echoReturnLossEnhancement}},videoStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPVideoStream"))output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.framesDecoded=item.framesDecoded,output.video.receiving.qpSum=item.qpSum,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),
+output.video.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.video.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if(0===prop.indexOf("RTCMediaStreamTrack_remote_video_"))output.video.receiving.frameHeight=item.frameHeight,output.video.receiving.frameWidth=item.frameWidth,output.video.receiving.framesCorrupted=item.framesCorrupted,output.video.receiving.framesPerSecond=item.framesPerSecond,output.video.receiving.framesDropped=item.framesDropped,output.video.receiving.totalFrames=item.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,item,"framesReceived");else if(0===prop.indexOf("RTCOutboundRTPVideoStream"))output.video.sending.qpSum=item.qpSum,output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"video"===item.mediaType&&item.isRemote){output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.receiving.framesCorrupted=trackItem.framesCorrupted,output.video.receiving.framesDropped=trackItem.framesDropped,output.video.receiving.framesDecoded=trackItem.framesDecoded,output.video.receiving.totalFrames=trackItem.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,trackItem,"framesReceived")}else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"video"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType)if(prop.indexOf("_recv")>0){output.video.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.video.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.video.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10),output.video.receiving.renderDelayMs=parseInt(item.googRenderDelayMs||"0",10),output.video.receiving.frameWidth=parseInt(item.googFrameWidthReceived||"0",10),output.video.receiving.frameHeight=parseInt(item.googFrameHeightReceived||"0",10),output.video.receiving.framesDecoded=parseInt(item.framesDecoded||"0",10),output.video.receiving.frameRateOutput=parseInt(item.googFrameRateOutput||"0",10),output.video.receiving.frameRateDecoded=parseInt(item.googFrameRateDecoded||"0",10),output.video.receiving.frameRateReceived=parseInt(item.googFrameRateReceived||"0",10),output.video.receiving.qpSum=parseInt(item.qpSum||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.video.receiving.totalBytes=bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.video.receiving.totalPackets=packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.video.receiving.totalPacketsLost=packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost");var nacksSent=parseInt(item.googNacksSent||"0",10);output.video.receiving.totalNacks=nacksSent,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"googNacksSent");var plisSent=parseInt(item.googPlisSent||"0",10);output.video.receiving.totalPlis=plisSent,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"googPlisSent");var firsSent=parseInt(item.googFirsSent||"0",10);output.video.receiving.totalFirs=firsSent,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"googFirsSent")}else{output.video.sending.rtt=parseInt(item.googRtt||"0",10),output.video.sending.frameWidth=parseInt(item.googFrameWidthSent||"0",10),output.video.sending.frameHeight=parseInt(item.googFrameHeightSent||"0",10),output.video.sending.framesEncoded=parseInt(item.framesEncoded||"0",10),output.video.sending.frameRateInput=parseInt(item.googFrameRateInput||"0",10),output.video.sending.frameRateEncoded=parseInt(item.googFrameRateEncoded||"0",10),output.video.sending.frameRateSent=parseInt(item.googFrameRateSent||"0",10),output.video.sending.cpuLimitedResolution="true"===item.googCpuLimitedResolution,output.video.sending.bandwidthLimitedResolution="true"===item.googBandwidthLimitedResolution;var bytesSent=parseInt(item.bytesSent||"0",10);output.video.sending.totalBytes=bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.video.sending.totalPackets=packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent");var nacksReceived=parseInt(item.googNacksReceived||"0",10);output.video.sending.totalNacks=nacksReceived,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"googNacksReceived");var plisReceived=parseInt(item.googPlisReceived||"0",10);output.video.sending.totalPlis=plisReceived,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"googPlisReceived");var firsReceived=parseInt(item.googFirsReceived||"0",10);output.video.sending.totalFirs=firsReceived,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"googFirsReceived")}else if(0===prop.indexOf("inbound_rtp_video"))output.video.receiving.jitter=item.jitter||0,output.video.receiving.framesDecoded=item.framesDecoded||0,output.video.receiving.frameRateMean=item.framerateMean||0,output.video.receiving.frameRateStdDev=item.framerateStdDev||0,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount");else if(0===prop.indexOf("outbound_rtp_video")){output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.frameRateMean=item.framerateMean||0,output.video.sending.frameRateStdDev=item.framerateStdDev||0,output.video.sending.framesDropped=item.droppedFrames||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.video.sending.rtt=rtcpItem.roundTripTime||0}}else{output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.roundTripTime=item.roundTripTime||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.sending.frameHeight=trackItem.frameHeight,output.video.sending.frameWidth=trackItem.frameWidth,output.video.sending.framesPerSecond=trackItem.framesPerSecond,output.video.sending.totalFrames=trackItem.framesSent,output.video.sending.frames=self._parseConnectionStats(prevStats,trackItem,"framesSent")}},videoE2EStatsFn=function(item,prop){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType){var captureStartNtpTimeMs=parseInt(item.googCaptureStartNtpTimeMs||"0",10),remoteStream=pc.getRemoteStreams()[0];if(!(captureStartNtpTimeMs>0&&prop.indexOf("_recv")>0&&remoteStream&&document&&"function"==typeof document.getElementsByTagName))return;try{var elements=document.getElementsByTagName("plugin"===AdapterJS.webrtcDetectedType?"object":"video");"plugin"!==AdapterJS.webrtcDetectedType&&0===elements.length&&(elements=document.getElementsByTagName("audio"));for(var e=0;e0))break;for(var ec=0;ec"],error)}}},successCbFn=function(stats){"function"==typeof stats.forEach?stats.forEach(function(item,prop){output.raw[prop]=item}):output.raw=stats;var edgeTracksKind={remote:{},local:{}};"edge"===AdapterJS.webrtcDetectedBrowser&&(pc.remoteStream&&pc.remoteStream.getTracks().forEach(function(track){edgeTracksKind.remote[track.id]=track.kind}),pc.localStream&&pc.localStream.getTracks().forEach(function(track){edgeTracksKind.local[track.id]=track.kind})),Object.keys(output.raw).forEach(function(prop){if(0!==prop.indexOf("ssrc_")||output.raw[prop].mediaType){if("edge"===AdapterJS.webrtcDetectedBrowser&&!output.raw[prop].mediaType&&["inboundrtp","outboundrtp"].indexOf(output.raw[prop].type)>-1){var trackItem=output.raw[output.raw[prop].mediaTrackId]||{};output.raw[prop].mediaType=edgeTracksKind[output.raw[prop].isRemote?"remote":"local"][trackItem.trackIdentifier]||""}}else output.raw[prop].mediaType=output.raw[prop].audioInputLevel||output.raw[prop].audioOutputLevel?"audio":"video";certificateFn(output.raw[prop],prop),candidatePairFn(output.raw[prop],prop),codecsFn(output.raw[prop],prop),audioStatsFn(output.raw[prop],prop),videoStatsFn(output.raw[prop],prop),videoE2EStatsFn(output.raw[prop],prop),isAutoBwStats&&!self._peerBandwidth[peerId][prop]?self._peerBandwidth[peerId][prop]=output.raw[prop]:isAutoBwStats||self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=output.raw[prop])}),output.audio.sending.bytes=output.audio.sending.bytes||0,output.audio.sending.packets=output.audio.sending.packets||0,output.audio.sending.totalBytes=output.audio.sending.totalBytes||0,output.audio.sending.totalPackets=output.audio.sending.totalPackets||0,output.video.sending.bytes=output.video.sending.bytes||0,output.video.sending.packets=output.video.sending.packets||0,output.video.sending.totalBytes=output.video.sending.totalBytes||0,output.video.sending.totalPackets=output.video.sending.totalPackets||0,output.audio.receiving.bytes=output.audio.receiving.bytes||0,output.audio.receiving.packets=output.audio.receiving.packets||0,output.audio.receiving.totalBytes=output.audio.receiving.totalBytes||0,output.audio.receiving.totalPackets=output.audio.receiving.totalPackets||0,output.video.receiving.bytes=output.video.receiving.bytes||0,output.video.receiving.packets=output.video.receiving.packets||0,output.video.receiving.totalBytes=output.video.receiving.totalBytes||0,output.video.receiving.totalPackets=output.video.receiving.totalPackets||0,callback(null,output)},errorCbFn=function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)};if("function"!=typeof pc.getStats)return errorCbFn(new Error("getStats() API is not available."));"plugin"===AdapterJS.webrtcDetectedType?pc.getStats(null,successCbFn,errorCbFn):pc.getStats(null).then(successCbFn).catch(errorCbFn)},Skylink.prototype._addPeer=function(targetMid,cert,peerBrowser,receiveOnly,isSS){var self=this;return self._peerConnections[targetMid]?void log.error([targetMid,null,null,"Connection to peer has already been made"]):(self._peerConnStatus[targetMid]={connected:!1,init:!1},log.log([targetMid,null,null,"Starting the connection to peer. Options provided:"],{peerBrowser:peerBrowser,receiveOnly:receiveOnly,enableDataChannel:self._initOptions.enableDataChannel}),log.info("Adding peer",isSS),self._peerConnections[targetMid]=self._createPeerConnection(targetMid,!!isSS,cert),self._peerConnections[targetMid]?(self._peerConnStatus[targetMid].init=!0,void(self._peerConnections[targetMid].hasScreen=!!isSS)):void log.error([targetMid,null,null,"Failed creating the connection to peer."]))},Skylink.prototype._restartPeerConnection=function(peerId,doIceRestart,bwOptions,callback){var self=this;if(!self._peerConnections[peerId])return void log.error([peerId,null,null,"Peer does not have an existing connection. Unable to restart"]);var pc=self._peerConnections[peerId],agent=(self.getPeerInfo(peerId)||{}).agent||{};if(self._isLowerThanVersion(agent.SMProtocolVersion||"","0.1.2")){var notSupportedError=new Error("Failed restarting with other agents connecting from other SDKs as re-negotiation is not supported by other SDKs");return log.warn([peerId,"RTCPeerConnection",null,"Ignoring restart request as agent's SDK does not support it"],notSupportedError),void("function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(notSupportedError)))}if(pc.signalingState===self.PEER_CONNECTION_STATE.STABLE&&self._peerConnections[peerId]){log.log([peerId,null,null,"Sending restart message to signaling server ->"],{iceRestart:doIceRestart,options:bwOptions}),self._peerCustomConfigs[peerId]=self._peerCustomConfigs[peerId]||{},self._peerCustomConfigs[peerId].bandwidth=self._peerCustomConfigs[peerId].bandwidth||{},self._peerCustomConfigs[peerId].googleXBandwidth=self._peerCustomConfigs[peerId].googleXBandwidth||{},bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._peerCustomConfigs[peerId].bandwidth.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._peerCustomConfigs[peerId].bandwidth.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._peerCustomConfigs[peerId].bandwidth.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._peerCustomConfigs[peerId].googleXBandwidth.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._peerCustomConfigs[peerId].googleXBandwidth.max=bwOptions.googleXBandwidth.max));var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===doIceRestart&&self._enableIceRestart&&self._peerInformations[peerId]&&self._peerInformations[peerId].config.enableIceRestart,isRestartResend:!1,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._peerEndOfCandidatesCounter[peerId]=self._peerEndOfCandidatesCounter[peerId]||{},self._peerEndOfCandidatesCounter[peerId].len=0,self._sendChannelMessage(restartMsg),self._trigger("peerRestart",peerId,self.getPeerInfo(peerId),!0,!0===doIceRestart),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart callback"]),callback(null))}else if(pc.signalingState===self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER){var hasLocalDescription=pc.localDescription&&pc.localDescription.sdp;if(hasLocalDescription)self._sendChannelMessage({type:pc.localDescription.type,sdp:pc.localDescription.sdp,mid:self._user.sid,target:peerId,rid:self._room.id,restart:!0});else{var noLocalDescriptionError="Failed re-sending localDescription as there is no localDescription set to connection. There could be a handshaking step error";log.error([peerId,"RTCPeerConnection",null,noLocalDescriptionError],{localDescription:pc.localDescription,remoteDescription:pc.remoteDescription}),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(noLocalDescriptionError)))}}else{var unableToRestartError="Failed restarting as peer connection state is "+pc.signalingState;log.warn([peerId,"RTCPeerConnection",null,unableToRestartError]),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(unableToRestartError)))}},Skylink.prototype._removePeer=function(peerId){if(!this._peerConnections[peerId]&&!this._peerInformations[peerId])return void log.debug([peerId,"RTCPeerConnection",null,"Dropping the hangup from Peer as not connected to Peer at all."]);var peerInfo=clone(this.getPeerInfo(peerId))||{userData:"",settings:{audio:!1,video:!1,data:!1},mediaStatus:{audioMuted:!0,videoMuted:!0},agent:{name:"unknown",version:0,os:"",pluginVersion:null},config:{enableDataChannel:!0,enableIceRestart:!1,enableIceTrickle:!0,priorityWeight:0,publishOnly:!1,receiveOnly:!0},parentId:null,room:clone(this._selectedRoom)};"MCU"!==peerId?this._trigger("peerLeft",peerId,peerInfo,!1):(this._hasMCU=!1,log.log([peerId,null,null,"MCU has stopped listening and left"]),this._trigger("serverPeerLeft",peerId,this.SERVER_PEER_TYPE.MCU)),this._peerConnections[peerId]&&(this._peerConnections[peerId].signalingState!==this.PEER_CONNECTION_STATE.CLOSED&&(this._peerConnections[peerId].close(),"AppleWebKit"===AdapterJS.webrtcDetectedType&&(this._peerConnections[peerId].signalingStateClosed||(this._peerConnections[peerId].signalingStateClosed=!0,this._trigger("peerConnectionState",this.PEER_CONNECTION_STATE.CLOSED,peerId)),this._peerConnections[peerId].iceConnectionStateClosed||(this._peerConnections[peerId].iceConnectionStateClosed=!0,this._trigger("iceConnectionState",this.ICE_CONNECTION_STATE.CLOSED,peerId)))),"MCU"!==peerId&&this._handleEndedStreams(peerId),delete this._peerConnections[peerId]),this._peerInformations[peerId]&&delete this._peerInformations[peerId],this._peerMessagesStamps[peerId]&&delete this._peerMessagesStamps[peerId],this._streamsSession[peerId]&&delete this._streamsSession[peerId],this._peerEndOfCandidatesCounter[peerId]&&delete this._peerEndOfCandidatesCounter[peerId],this._peerCandidatesQueue[peerId]&&delete this._peerCandidatesQueue[peerId],this._sdpSessions[peerId]&&delete this._sdpSessions[peerId],this._peerStats[peerId]&&delete this._peerStats[peerId],this._peerBandwidth[peerId]&&delete this._peerBandwidth[peerId],this._gatheredCandidates[peerId]&&delete this._gatheredCandidates[peerId],this._peerCustomConfigs[peerId]&&delete this._peerCustomConfigs[peerId],this._peerConnStatus[peerId]&&delete this._peerConnStatus[peerId],this._dataChannels[peerId]&&this._closeDataChannel(peerId),log.log([peerId,"RTCPeerConnection",null,"Successfully removed peer"])},Skylink.prototype._createPeerConnection=function(targetMid,isScreenSharing,cert){var pc,self=this;if(self._inRoom&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)){var constraints={iceServers:self._room.connection.peerConfig.iceServers,iceTransportPolicy:self._initOptions.filterCandidatesType.host&&self._initOptions.filterCandidatesType.srflx&&!self._initOptions.filterCandidatesType.relay?"relay":"all",bundlePolicy:self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.NONE?self.BUNDLE_POLICY.BALANCED:self._peerConnectionConfig.bundlePolicy,rtcpMuxPolicy:self._peerConnectionConfig.rtcpMuxPolicy,iceCandidatePoolSize:self._peerConnectionConfig.iceCandidatePoolSize},optional={optional:[{DtlsSrtpKeyAgreement:!0},{googIPv6:!0}]};cert&&(constraints.certificates=[cert]),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].constraints=constraints,self._peerConnStatus[targetMid].optional=optional);try{log.debug([targetMid,"RTCPeerConnection",null,"Creating peer connection ->"],{constraints:constraints,optional:optional}),pc=new(self._initOptions.useEdgeWebRTC&&window.msRTCPeerConnection?window.msRTCPeerConnection:RTCPeerConnection)(constraints,optional)}catch(error){return log.error([targetMid,null,null,"Failed creating peer connection:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),null}pc.setOffer="",pc.setAnswer="",pc.hasStream=!1,pc.hasScreen=!!isScreenSharing,pc.hasMainChannel=!1,pc.firefoxStreamId="",pc.processingLocalSDP=!1,pc.processingRemoteSDP=!1,pc.gathered=!1,pc.gathering=!1,pc.localStream=null,pc.localStreamId=null,pc.remoteStream=null,pc.remoteStreamId=null,pc.iceConnectionStateClosed=!1,pc.signalingStateClosed=!1,self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}},self._streamsSession[targetMid]=self._streamsSession[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._sdpSessions[targetMid]={local:{},remote:{}},self._peerBandwidth[targetMid]={};var bandwidth=null;return pc.ondatachannel=function(event){var dc=event.channel||event;if(log.debug([targetMid,"RTCDataChannel",dc.label,"Received datachannel ->"],dc),self._initOptions.enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel){self.DATA_CHANNEL_TYPE.DATA,dc.label;pc.hasMainChannel||(self.DATA_CHANNEL_TYPE.MESSAGING,"main",pc.hasMainChannel=!0),self._createDataChannel(targetMid,dc)}else log.warn([targetMid,"RTCDataChannel",dc.label,"Not adding datachannel as enable datachannel is set to false"])},pc.onaddstream=function(evt){if(self._peerConnections[targetMid]){var stream=evt.stream||evt;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received empty remote stream ->"],stream);pc.remoteStream=stream,pc.remoteStreamId=pc.remoteStreamId||stream.id||stream.label;var peerSettings=clone(self.getPeerInfo(targetMid).settings);self._streamsSession[targetMid][pc.remoteStreamId]=peerSettings,0===stream.getAudioTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].audio=!1),0===stream.getVideoTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].video=!1),pc.hasStream=!0,pc.hasScreen=peerSettings.video&&"object"==typeof peerSettings.video&&peerSettings.video.screenshare,self._onRemoteStreamAdded(targetMid,stream,!!pc.hasScreen)}},pc.onicecandidate=function(event){self._onIceCandidate(targetMid,event.candidate||event)},pc.oniceconnectionstatechange=function(evt){var iceConnectionState=pc.iceConnectionState;if(log.debug([targetMid,"RTCIceConnectionState",null,"Ice connection state changed ->"],iceConnectionState),"edge"===AdapterJS.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),"AppleWebKit"===AdapterJS.webrtcDetectedType&&iceConnectionState===self.ICE_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.iceConnectionStateClosed||self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.CLOSED,targetMid)},10);if(self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._initOptions.enableIceTrickle&&self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.TRICKLE_FAILED,targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].connected=[self.ICE_CONNECTION_STATE.COMPLETED,self.ICE_CONNECTION_STATE.CONNECTED].indexOf(iceConnectionState)>-1),!self._hasMCU&&[self.ICE_CONNECTION_STATE.CONNECTED,self.ICE_CONNECTION_STATE.COMPLETED].indexOf(iceConnectionState)>-1&&self._bandwidthAdjuster&&!bandwidth&&"edge"!==AdapterJS.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),"AppleWebKit"===AdapterJS.webrtcDetectedType&&pc.signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.signalingStateClosed||self._trigger("peerConnectionState",self.PEER_CONNECTION_STATE.CLOSED,targetMid)},10);self._trigger("peerConnectionState",pc.signalingState,targetMid)},pc.onicegatheringstatechange=function(){log.log([targetMid,"RTCIceGatheringState",null,"Ice gathering state changed ->"],pc.iceGatheringState),self._trigger("candidateGenerationState",pc.iceGatheringState,targetMid)},"firefox"===AdapterJS.webrtcDetectedBrowser&&(pc.removeStream=function(stream){for(var senders=pc.getSenders(),s=0;s"],restartMsg),self._sendChannelMessage(restartMsg)}
+;bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=bwOptions.googleXBandwidth.max));for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers},null):callback(null,{listOfPeers:listOfPeers}))};self.once("peerJoined",peerJoinedFn,function(peerId,peerInfo,isSelf){return isSelf}),self.leaveRoom(!1,function(error,success){if(error){if("function"==typeof callback){for(var i=0;i=self._peerEndOfCandidatesCounter[targetMid].expectedLen&&(!self._peerCandidatesQueue[targetMid]||0===self._peerCandidatesQueue[targetMid].length)&&!self._peerEndOfCandidatesCounter[targetMid].hasSet){log.debug([targetMid,"RTCPeerConnection",null,"Signaling of end-of-candidates remote ICE gathering."]),self._peerEndOfCandidatesCounter[targetMid].hasSet=!0;try{if("edge"===AdapterJS.webrtcDetectedBrowser){for(var mLineCounter=-1,addedMids=[],sdpLines=self._peerConnections[targetMid].remoteDescription.sdp.split("\r\n"),rejected=!1,i=0;i"],error)}}},Skylink.prototype.setUserData=function(userData){var self=this,updatedUserData="";void 0!==userData&&null!==userData&&(updatedUserData=userData),this._userData=updatedUserData,self._inRoom?(log.log("Updated userData -> ",updatedUserData),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.UPDATE_USER,mid:self._user.sid,rid:self._room.id,userData:updatedUserData,stamp:(new Date).getTime()}),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0)):log.warn("User is not in the room. Broadcast of updated information will be dropped")},Skylink.prototype.getUserData=function(peerId){if(peerId&&this._peerInformations[peerId]){var userData=this._peerInformations[peerId].userData;return null!==userData&&void 0===userData||(userData=""),userData}return this._userData},Skylink.prototype.getPeerInfo=function(peerId){var peerInfo=null;return"string"==typeof peerId&&"object"==typeof this._peerInformations[peerId]?(peerInfo=clone(this._peerInformations[peerId]),peerInfo.room=clone(this._selectedRoom),peerInfo.settings.bandwidth=peerInfo.settings.bandwidth||{},peerInfo.settings.googleXBandwidth=peerInfo.settings.googleXBandwidth||{},"boolean"==typeof peerInfo.settings.video||peerInfo.settings.video&&"object"==typeof peerInfo.settings.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"==typeof peerInfo.settings.audio||peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.audioMuted&&(peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.videoMuted&&(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.maxBandwidth&&(peerInfo.settings.bandwidth=clone(peerInfo.settings.maxBandwidth),delete peerInfo.settings.maxBandwidth),peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&peerInfo.settings.video.customSettings&&"object"==typeof peerInfo.settings.video.customSettings&&(peerInfo.settings.video.customSettings.frameRate&&(peerInfo.settings.video.frameRate=clone(peerInfo.settings.video.customSettings.frameRate)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode)),peerInfo.settings.video.customSettings.width&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.width=clone(peerInfo.settings.video.customSettings.width)),peerInfo.settings.video.customSettings.height&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.height=clone(peerInfo.settings.video.customSettings.height)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode))),peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&(peerInfo.settings.audio.stereo=!0===peerInfo.settings.audio.stereo),null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),peerInfo.parentId=peerInfo.parentId||null,"MCU"===peerId?(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1):this._hasMCU&&(peerInfo.config.receiveOnly=!1,peerInfo.config.publishOnly=!0),this._sdpSettings.direction.audio.receive||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.direction.video.receive||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.data=!!(this._dataChannels[peerId]&&this._dataChannels[peerId].main&&this._dataChannels[peerId].main.channel&&this._dataChannels[peerId].main.channel.readyState===this.DATA_CHANNEL_STATE.OPEN),peerInfo.connected=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].connected,peerInfo.init=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].init,this._sdpSessions[peerId]&&this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&"object"==typeof this._sdpSessions[peerId].remote.connection&&(this._sdpSessions[peerId].remote.connection.audio&&this._sdpSessions[peerId].remote.connection.audio.indexOf("send")>-1||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSessions[peerId].remote.connection.video&&this._sdpSessions[peerId].remote.connection.video.indexOf("send")>-1||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSessions[peerId].remote.connection.data&&this._sdpSessions[peerId].remote.connection.data.indexOf("send")>-1||(peerInfo.settings.data=!1))):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,os:window.navigator.platform,pluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:this.SMProtocolVersion,DTProtocolVersion:this.DTProtocolVersion},room:clone(this._selectedRoom),config:{enableDataChannel:this._initOptions.enableDataChannel,enableIceTrickle:this._initOptions.enableIceTrickle,enableIceRestart:this._enableIceRestart,priorityWeight:this._peerPriorityWeight,receiveOnly:!1,publishOnly:!!this._publishOnly},connected:null,init:null},null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),this._streams.screenshare?peerInfo.settings=clone(this._streams.screenshare.settings):this._streams.userMedia&&(peerInfo.settings=clone(this._streams.userMedia.settings)),peerInfo.settings.bandwidth=clone(this._streamsBandwidthSettings.bAS),peerInfo.settings.googleXBandwidth=clone(this._streamsBandwidthSettings.googleX),peerInfo.parentId=this._parentId?this._parentId:null,peerInfo.config.receiveOnly=!peerInfo.settings.video&&!peerInfo.settings.audio,peerInfo.settings.data=this._initOptions.enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._initOptions.codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._initOptions.codecParams.audio.opus.stereo),"boolean"==typeof this._initOptions.codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._initOptions.codecParams.audio.opus.usedtx),"number"==typeof this._initOptions.codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._initOptions.codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._initOptions.codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._initOptions.codecParams.audio.opus.useinbandfec))),peerInfo.settings.audio||(peerInfo.mediaStatus.audioMuted=!0),peerInfo.settings.video||(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.audio||peerInfo.settings.video||(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1),peerInfo},Skylink.prototype.getPeersInRoom=function(){for(var listOfPeersInfo={},listOfPeers=Object.keys(this._peerInformations),i=0;i-1||(customSettings.settings.audio=!1,customSettings.mediaStatus.audioMuted=!0),self._sdpSessions[usePeerId].local.connection.video&&self._sdpSessions[usePeerId].local.connection.video.indexOf("send")>-1||(customSettings.settings.video=!1,customSettings.mediaStatus.videoMuted=!0),self._sdpSessions[usePeerId].local.connection.data&&self._sdpSessions[usePeerId].local.connection.data.indexOf("send")>-1||(customSettings.settings.data=!1)),customSettings},Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo()),userCustomInfoForPeer=peerId?this._getPeerCustomSettings(peerId):null;return userCustomInfoForPeer&&"object"==typeof userCustomInfoForPeer&&(userInfo.settings=userCustomInfoForPeer.settings,userInfo.mediaStatus=userCustomInfoForPeer.mediaStatus),userInfo.settings.video&&"object"==typeof userInfo.settings.video&&(userInfo.settings.video.customSettings={},userInfo.settings.video.frameRate&&"object"==typeof userInfo.settings.video.frameRate&&(userInfo.settings.video.customSettings.frameRate=clone(userInfo.settings.video.frameRate),userInfo.settings.video.frameRate=-1),userInfo.settings.video.facingMode&&"object"==typeof userInfo.settings.video.facingMode&&(userInfo.settings.video.customSettings.facingMode=clone(userInfo.settings.video.facingMode),userInfo.settings.video.facingMode="-1"),userInfo.settings.video.resolution&&"object"==typeof userInfo.settings.video.resolution&&(userInfo.settings.video.resolution.width&&"object"==typeof userInfo.settings.video.resolution.width&&(userInfo.settings.video.customSettings.width=clone(userInfo.settings.video.width),userInfo.settings.video.resolution.width=-1),userInfo.settings.video.resolution.height&&"object"==typeof userInfo.settings.video.resolution.height&&(userInfo.settings.video.customSettings.height=clone(userInfo.settings.video.height),userInfo.settings.video.resolution.height=-1))),userInfo.settings.bandwidth&&(userInfo.settings.maxBandwidth=clone(userInfo.settings.bandwidth),delete userInfo.settings.bandwidth),this._getSDPCommonSupports(peerId).video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._getSDPCommonSupports(peerId).audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype._doOffer=function(targetMid,iceRestart){var self=this,pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of creating of offer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription","offer",'Dropping of creating of offer as signalingState is not "'+self.PEER_CONNECTION_STATE.STABLE+'" ->'],pc.signalingState);var offerConstraints={offerToReceiveAudio:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).video,offerToReceiveVideo:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).audio,iceRestart:!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,voiceActivityDetection:self._voiceActivityDetection};self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._initOptions.enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._dataChannels[targetMid]&&self._dataChannels[targetMid].main||(self._createDataChannel(targetMid),self._peerConnections[targetMid].hasMainChannel=!0)),log.debug([targetMid,null,null,"Creating offer with config:"],offerConstraints),pc.endOfCandidates=!1,self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=offerConstraints);var onSuccessCbFn=function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)};pc.createOffer(onSuccessCbFn,onErrorCbFn,"plugin"===AdapterJS.webrtcDetectedType?{mandatory:{OfferToReceiveAudio:offerConstraints.offerToReceiveAudio,OfferToReceiveVideo:offerConstraints.offerToReceiveVideo,iceRestart:offerConstraints.iceRestart,voiceActivityDetection:offerConstraints.voiceActivityDetection}}:offerConstraints)},Skylink.prototype._doAnswer=function(targetMid){var self=this;log.log([targetMid,null,null,"Creating answer with config:"],self._room.connection.sdpConstraints);var pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of creating of answer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription","answer",'Dropping of creating of answer as signalingState is not "'+self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER+'" ->'],pc.signalingState);var answerConstraints="edge"===AdapterJS.webrtcDetectedBrowser?{offerToReceiveVideo:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).video,offerToReceiveAudio:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).audio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints);var onSuccessCbFn=function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},onErrorCbFn=function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.createAnswer(onSuccessCbFn,onErrorCbFn,answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,_sessionDescription){var self=this,pc=self._peerConnections[targetMid];if(!_sessionDescription||!_sessionDescription.sdp)return void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],_sessionDescription);if(!pc)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as connection does not exists ->"],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(pc.processingLocalSDP)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as another is being processed ->"],_sessionDescription);pc.processingLocalSDP=!0;var sessionDescription={type:_sessionDescription.type,sdp:_sessionDescription.sdp};sessionDescription.sdp=self._removeSDPFirefoxH264Pref(targetMid,sessionDescription),sessionDescription.sdp=self._setSDPCodecParams(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPUnknownAptRtx(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPCodecs(targetMid,sessionDescription),sessionDescription.sdp=self._handleSDPConnectionSettings(targetMid,sessionDescription,"local"),sessionDescription.sdp=self._removeSDPREMBPackets(targetMid,sessionDescription),self._peerConnectionConfig.disableBundle&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=group:BUNDLE.*\r\n/gi,"")),log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description updated ->"],sessionDescription.sdp);var onSuccessCbFn=function(){if(log.debug([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description has been set ->"],sessionDescription),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",sessionDescription.type,targetMid),sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER?pc.setAnswer="local":pc.setOffer="local",!self._initOptions.enableIceTrickle&&!pc.gathered)return void log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description sending is halted to complete ICE gathering."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},onErrorCbFn=function(error){log.error([targetMid,"RTCSessionDescription",sessionDescription.type,"Local description failed setting ->"],error),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.setLocalDescription(new RTCSessionDescription(sessionDescription),onSuccessCbFn,onErrorCbFn)},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._initOptions.appKey?("function"==typeof showAll&&(callback=showAll,showAll=!1),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.GET_PEERS,showAll:showAll||!1}),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.ENQUIRED,self._user.sid,null),log.log("Enquired server for peers within the realm"),void("function"==typeof callback&&self.once("getPeersStateChange",function(state,privilegedPeerId,peerList){callback(null,peerList)},function(state,privilegedPeerId,peerList){return state===self.GET_PEERS_STATE.RECEIVED}))):void log.warn("App key is not defined. Please authenticate again."):void log.warn("Please upgrade your key to privileged to use this function")},Skylink.prototype.introducePeer=function(sendingPeerId,receivingPeerId){var self=this;if(!self._isPrivileged)return log.warn("Please upgrade your key to privileged to use this function"),void self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,sendingPeerId,receivingPeerId,"notPrivileged");self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.INTRODUCE,sendingPeerId:sendingPeerId,receivingPeerId:receivingPeerId}),self._trigger("introduceStateChange",self.INTRODUCE_STATE.INTRODUCING,self._user.sid,sendingPeerId,receivingPeerId,null),log.log("Introducing",sendingPeerId,"to",receivingPeerId)},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._initOptions.defaultRoom,previousRoom=self._selectedRoom,mediaOptions={},timestamp=(new Date).getTime()+Math.floor(1e4*Math.random());self._joinRoomManager.timestamp=timestamp,room&&"string"==typeof room?selectedRoom=room:room&&"object"==typeof room?mediaOptions=room:"function"==typeof room&&(callback=room),options&&"object"==typeof options?mediaOptions=options:"function"==typeof options&&(callback=options);var resolveAsErrorFn=function(error,tryRoom,readyState){log.error(error),"function"==typeof callback&&callback({room:tryRoom,errorCode:readyState||null,error:error instanceof Error?error:new Error(JSON.stringify(error))})},joinRoomFn=function(){if(self._joinRoomManager.timestamp!==timestamp)return void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom);self._initSelectedRoom(selectedRoom,function(initError,initSuccess){return initError?void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState):self._joinRoomManager.timestamp!==timestamp?void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom):void self._waitForOpenChannel(mediaOptions||{},timestamp,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);if(self._joinRoomManager.timestamp!==timestamp)return void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom);if("AppleWebKit"===AdapterJS.webrtcDetectedType){
+var checkStream=self._streams.screenshare&&self._streams.screenshare.stream?self._streams.screenshare.stream:self._streams.userMedia&&self._streams.userMedia.stream?self._streams.userMedia.stream:null;checkStream&&0!==checkStream.getTracks().length?0===checkStream.getAudioTracks().length?log.warn("Note that receiving audio streams may fail as safari 11 needs stream with audio and video tracks and not just with video tracks"):0===checkStream.getVideoTracks().length&&log.warn("Note that receiving video streams may fail as safari 11 needs stream with audio and video tracks and not just with audio tracks"):log.warn("Note that receiving audio and video streams may fail as safari 11 needs stream with audio and video tracks")}if("function"==typeof callback){var peerOnJoin=function(peerId,peerInfo,isSelf){self.off("systemAction",peerFailedJoin),self.off("channelClose",peerSocketFailedJoin),log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo})},peerFailedJoin=function(action,message){self.off("peerJoined",peerOnJoin),self.off("channelClose",peerSocketFailedJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room ->"],message),resolveAsErrorFn(new Error(message),self._selectedRoom,self._readyState)},peerSocketFailedJoin=function(){self.off("systemAction",peerFailedJoin),self.off("peerJoined",peerOnJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room due to abrupt disconnection."]),resolveAsErrorFn(new Error("Channel closed abruptly before session was established"),self._selectedRoom,self._readyState)};self.once("peerJoined",peerOnJoin,function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),self.once("systemAction",peerFailedJoin,function(action){return action===self.SYSTEM_ACTION.REJECT}),self.once("channelClose",peerSocketFailedJoin)}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.JOIN_ROOM,uid:self._user.uid,cid:self._key,rid:self._room.id,userCred:self._user.token,timeStamp:self._user.timeStamp,apiOwner:self._appKeyOwner,roomCred:self._room.token,start:self._room.startDateTime,len:self._room.duration,isPrivileged:!0===self._isPrivileged,autoIntroduce:!1!==self._autoIntroduce,key:self._initOptions.appKey})})})};if(null===room||["number","boolean"].indexOf(typeof room)>-1)return void resolveAsErrorFn("Invalid room name is provided",room);if(null===options||["number","boolean"].indexOf(typeof options)>-1)return void resolveAsErrorFn("Invalid mediaOptions is provided",selectedRoom);self._joinRoomManager.socketsFn.forEach(function(fnItem){fnItem(timestamp)}),self._joinRoomManager.socketsFn=[];var stopStream=!1===mediaOptions.audio&&!1===mediaOptions.video;self._inRoom?self.leaveRoom({userMedia:stopStream},function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()}):(stopStream&&self.stopStream(),joinRoomFn())},Skylink.prototype.leaveRoom=function(stopMediaOptions,callback){var self=this,stopUserMedia=!0,stopScreenshare=!0,previousRoom=self._selectedRoom,previousUserPeerId=self._user?self._user.sid:null,peersThatLeft=[],isNotInRoom=!self._inRoom;"boolean"==typeof stopMediaOptions?!1===stopMediaOptions&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=!1!==stopMediaOptions.userMedia,stopScreenshare=!1!==stopMediaOptions.screenshare):"function"==typeof stopMediaOptions&&(callback=stopMediaOptions);for(var infoPeerId in self._peerInformations)self._peerInformations.hasOwnProperty(infoPeerId)&&self._peerInformations[infoPeerId]&&(peersThatLeft.push(infoPeerId),self._removePeer(infoPeerId));for(var connPeerId in self._peerConnections)self._peerConnections.hasOwnProperty(connPeerId)&&self._peerConnections[connPeerId]&&-1===peersThatLeft.indexOf(connPeerId)&&(peersThatLeft.push(connPeerId),self._removePeer(connPeerId));if(self._inRoom=!1,self._closeChannel(),isNotInRoom){var notInRoomError="Unable to leave room as user is not in any room";return log.error([null,"Room",previousRoom,notInRoomError]),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}self._stopStreams({userMedia:stopUserMedia,screenshare:stopScreenshare}),self._wait(function(){log.log([null,"Room",previousRoom,"User left the room"]),self._trigger("peerLeft",previousUserPeerId,self.getPeerInfo(),!0),"function"==typeof callback&&callback(null,{peerId:previousUserPeerId,previousRoom:previousRoom})},function(){return!self._channelOpen})},Skylink.prototype.lockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!0),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!0}),this._roomLocked=!0,this._trigger("roomLock",!0,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype.unlockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!1),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!1}),this._roomLocked=!1,this._trigger("roomLock",!1,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype._waitForOpenChannel=function(mediaOptions,joinRoomTimestamp,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){var onChannelOpen=function(){self.off("socketError",onChannelError),setTimeout(function(){if(mediaOptions=mediaOptions||{},self._userData=mediaOptions.userData||self._userData||"",self._streamsBandwidthSettings={googleX:{},bAS:{}},self._publishOnly=!1,self._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},self._voiceActivityDetection="boolean"!=typeof mediaOptions.voiceActivityDetection||mediaOptions.voiceActivityDetection,self._peerConnectionConfig={bundlePolicy:self.BUNDLE_POLICY.BALANCED,rtcpMuxPolicy:self.RTCP_MUX_POLICY.REQUIRE,iceCandidatePoolSize:0,certificate:self.PEER_CERTIFICATE.AUTO,disableBundle:!1},self._bandwidthAdjuster=null,mediaOptions.bandwidth&&("number"==typeof mediaOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=mediaOptions.bandwidth.audio),"number"==typeof mediaOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=mediaOptions.bandwidth.video),"number"==typeof mediaOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=mediaOptions.bandwidth.data)),mediaOptions.googleXBandwidth&&("number"==typeof mediaOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=mediaOptions.googleXBandwidth.min),"number"==typeof mediaOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=mediaOptions.googleXBandwidth.max)),mediaOptions.sdpSettings&&(mediaOptions.sdpSettings.direction&&(mediaOptions.sdpSettings.direction.audio&&(self._sdpSettings.direction.audio.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.receive||mediaOptions.sdpSettings.direction.audio.receive,self._sdpSettings.direction.audio.send="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.send||mediaOptions.sdpSettings.direction.audio.send),mediaOptions.sdpSettings.direction.video&&(self._sdpSettings.direction.video.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.video.receive||mediaOptions.sdpSettings.direction.video.receive,self._sdpSettings.direction.video.send="boolean"!=typeof mediaOptions.sdpSettings.direction.video.send||mediaOptions.sdpSettings.direction.video.send)),mediaOptions.sdpSettings.connection&&(self._sdpSettings.connection.audio="boolean"!=typeof mediaOptions.sdpSettings.connection.audio||mediaOptions.sdpSettings.connection.audio,self._sdpSettings.connection.video="boolean"!=typeof mediaOptions.sdpSettings.connection.video||mediaOptions.sdpSettings.connection.video,self._sdpSettings.connection.data="boolean"!=typeof mediaOptions.sdpSettings.connection.data||mediaOptions.sdpSettings.connection.data)),mediaOptions.publishOnly&&(self._sdpSettings.direction.audio.send=!0,self._sdpSettings.direction.audio.receive=!1,self._sdpSettings.direction.video.send=!0,self._sdpSettings.direction.video.receive=!1,self._publishOnly=!0,"object"==typeof mediaOptions.publishOnly&&mediaOptions.publishOnly.parentId&&"string"==typeof mediaOptions.publishOnly.parentId&&(self._parentId=mediaOptions.publishOnly.parentId)),mediaOptions.parentId&&(self._parentId=mediaOptions.parentId),mediaOptions.peerConnection&&"object"==typeof mediaOptions.peerConnection){if("string"==typeof mediaOptions.peerConnection.bundlePolicy)for(var bpProp in self.BUNDLE_POLICY)self.BUNDLE_POLICY.hasOwnProperty(bpProp)&&self.BUNDLE_POLICY[bpProp]===mediaOptions.peerConnection.bundlePolicy&&(self._peerConnectionConfig.bundlePolicy=mediaOptions.peerConnection.bundlePolicy);if("string"==typeof mediaOptions.peerConnection.rtcpMuxPolicy)for(var rmpProp in self.RTCP_MUX_POLICY)self.RTCP_MUX_POLICY.hasOwnProperty(rmpProp)&&self.RTCP_MUX_POLICY[rmpProp]===mediaOptions.peerConnection.rtcpMuxPolicy&&(self._peerConnectionConfig.rtcpMuxPolicy=mediaOptions.peerConnection.rtcpMuxPolicy);if("number"==typeof mediaOptions.peerConnection.iceCandidatePoolSize&&mediaOptions.peerConnection.iceCandidatePoolSize>0&&(self._peerConnectionConfig.iceCandidatePoolSize=mediaOptions.peerConnection.iceCandidatePoolSize),"string"==typeof mediaOptions.peerConnection.certificate)for(var pcProp in self.PEER_CERTIFICATE)self.PEER_CERTIFICATE.hasOwnProperty(pcProp)&&self.PEER_CERTIFICATE[pcProp]===mediaOptions.peerConnection.certificate&&(self._peerConnectionConfig.certificate=mediaOptions.peerConnection.certificate);self._peerConnectionConfig.disableBundle=!0===mediaOptions.peerConnection.disableBundle}if(mediaOptions.autoBandwidthAdjustment&&(self._bandwidthAdjuster={interval:10,limitAtPercentage:100,useUploadBwOnly:!1},"object"==typeof mediaOptions.autoBandwidthAdjustment&&("number"==typeof mediaOptions.autoBandwidthAdjustment.interval&&mediaOptions.autoBandwidthAdjustment.interval>=10&&(self._bandwidthAdjuster.interval=mediaOptions.autoBandwidthAdjustment.interval),"number"==typeof mediaOptions.autoBandwidthAdjustment.limitAtPercentage&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage>=0&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage<=100&&(self._bandwidthAdjuster.limitAtPercentage=mediaOptions.autoBandwidthAdjustment.limitAtPercentage),"boolean"==typeof mediaOptions.autoBandwidthAdjustment.useUploadBwOnly&&(self._bandwidthAdjuster.useUploadBwOnly=mediaOptions.autoBandwidthAdjustment.useUploadBwOnly))),!0===mediaOptions.manualGetUserMedia){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){!0===mediaAccessRequiredFailure?self._onUserMediaError(new Error("Waiting for stream timeout"),!1,!1):callback(null,self._streams.userMedia.stream)},function(){return current50Block+=1,600===current50Block?(mediaAccessRequiredFailure=!0,!0):!(!self._streams.userMedia||!self._streams.userMedia.stream)||void 0},50)}if(mediaOptions.audio||mediaOptions.video)return void self.getUserMedia({useExactConstraints:!!mediaOptions.useExactConstraints,audio:mediaOptions.audio,video:mediaOptions.video},function(error,success){error?callback(error,null):callback(null,success)});callback(null,null)},1)},onChannelError=function(errorState,error){self.off("channelOpen",onChannelOpen),callback(error)};self._channelOpen?onChannelOpen():(self.once("channelOpen",onChannelOpen),self.once("socketError",onChannelError,function(errorState){return errorState===self.SOCKET_ERROR.RECONNECTION_ABORTED}),self._openChannel(joinRoomTimestamp))},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.generateUUID=function(){var d=(new Date).getTime();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"===c?r:r&&15).toString(16)})},Skylink.prototype.init=function(_options,_callback){var self=this,options={},callback=function(){};if("function"==typeof _options?callback=_options:_options&&"object"==typeof _options?(options=clone(_options),options.appKey&&"string"==typeof options.appKey||!options.apiKey||"string"!=typeof options.apiKey||(options.appKey=options.apiKey)):_options&&"string"==typeof _options&&(options.appKey=_options),"function"==typeof _callback&&(callback=_callback),options.defaultRoom=options.defaultRoom&&"string"==typeof options.defaultRoom?options.defaultRoom:options.appKey,options.roomServer=options.roomServer&&"string"==typeof options.roomServer?options.roomServer:"//api.temasys.io",options.enableIceTrickle=!1!==options.enableIceTrickle,options.enableDataChannel=!1!==options.enableDataChannel,options.enableSTUNServer=!1!==options.enableSTUNServer,options.enableTURNServer=!1!==options.enableTURNServer,options.audioFallback=!0===options.audioFallback,options.forceSSL=!1!==options.forceSSL,options.socketTimeout="number"==typeof options.socketTimeout&&options.socketTimeout>=5e3?options.socketTimeout:7e3,options.apiTimeout="number"==typeof options.apiTimeout?options.apiTimeout:4e3,options.forceTURNSSL=!0===options.forceTURNSSL,options.forceTURN=!0===options.forceTURN,options.usePublicSTUN=!0===options.usePublicSTUN,options.disableVideoFecCodecs=!0===options.disableVideoFecCodecs,options.disableComfortNoiseCodec=!0===options.disableComfortNoiseCodec,options.disableREMB=!0===options.disableREMB,options.throttleShouldThrowError=!0===options.throttleShouldThrowError,options.mcuUseRenegoRestart=!0===options.mcuUseRenegoRestart,options.useEdgeWebRTC=!0===options.useEdgeWebRTC,options.enableSimultaneousTransfers=!1!==options.enableSimultaneousTransfers,options.priorityWeightScheme=self._containsInList("PRIORITY_WEIGHT_SCHEME",options.priorityWeightScheme,"AUTO"),options.TURNServerTransport=self._containsInList("TURN_TRANSPORT",options.TURNServerTransport,"ANY"),options.credentials=options.credentials&&"object"==typeof options.credentials&&options.credentials.startDateTime&&"string"==typeof options.credentials.startDateTime&&options.credentials.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration?options.credentials:null,options.filterCandidatesType=options.filterCandidatesType&&"object"==typeof options.filterCandidatesType?options.filterCandidatesType:{},options.filterCandidatesType.host=!0===options.filterCandidatesType.host,options.filterCandidatesType.srflx=!0===options.filterCandidatesType.srflx,options.filterCandidatesType.relay=!0===options.filterCandidatesType.relay,options.throttleIntervals=options.throttleIntervals&&"object"==typeof options.throttleIntervals?options.throttleIntervals:{},options.throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:1e4,options.throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:5e3,options.throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:0,options.iceServer&&"string"==typeof options.iceServer?options.iceServer={urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0?options.iceServer={urls:options.iceServer}:options.iceServer=null,options.socketServer&&"string"==typeof options.socketServer?options.socketServer=options.socketServer:options.socketServer&&"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url?options.socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)?options.socketServer.ports:[],protocol:options.socketServer.protocol?options.socketServer.protocol:null}:options.socketServer=null,options.audioCodec&&"object"==typeof options.audioCodec&&self._containsInList("AUDIO_CODEC",options.audioCodec.codec,"-")?options.audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels?options.audioCodec.channels:null}:options.audioCodec=self._containsInList("AUDIO_CODEC",options.audioCodec,"AUTO"),options.videoCodec&&"object"==typeof options.videoCodec&&self._containsInList("VIDEO_CODEC",options.videoCodec.codec,"-")?options.videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate?options.videoCodec.samplingRate:null}:options.videoCodec=self._containsInList("VIDEO_CODEC",options.videoCodec,"AUTO"),options.codecParams=options.codecParams&&"object"==typeof options.codecParams?options.codecParams:{},options.codecParams.audio=options.codecParams.audio&&"object"==typeof options.codecParams.audio?options.codecParams.audio:{},options.codecParams.video=options.codecParams.video&&"object"==typeof options.codecParams.video?options.codecParams.video:{},options.codecParams.audio.opus=options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus?options.codecParams.audio.opus:{},options.codecParams.audio.opus.stereo="boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,options.codecParams.audio.opus["sprop-stereo"]="boolean"==typeof options.codecParams.audio.opus["sprop-stereo"]?options.codecParams.audio.opus["sprop-stereo"]:null,options.codecParams.audio.opus.usedtx="boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,options.codecParams.audio.opus.useinbandfec="boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,options.codecParams.audio.opus.maxplaybackrate="number"==typeof options.codecParams.audio.opus.maxplaybackrate&&options.codecParams.audio.opus.maxplaybackrate>=8e3&&options.codecParams.audio.opus.maxplaybackrate<=48e3?options.codecParams.audio.opus.maxplaybackrate:null,options.codecParams.audio.opus.minptime="number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null,options.codecParams.video.h264=options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264?options.codecParams.video.h264:{},options.codecParams.video.h264.profileLevelId=options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,options.codecParams.video.h264.levelAsymmetryAllowed="boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,options.codecParams.video.h264.packetizationMode="boolean"==typeof options.codecParams.video.h264.packetizationMode?!0===options.codecParams.video.h264.packetizationMode?1:0:"number"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null,options.codecParams.video.vp8=options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8?options.codecParams.video.vp8:{},options.codecParams.video.vp8.maxFs="number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,options.codecParams.video.vp8.maxFr="number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null,options.codecParams.video.vp9=options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9?options.codecParams.video.vp9:{},options.codecParams.video.vp9.maxFs="number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,options.codecParams.video.vp9.maxFr="number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null,options.forceTURN&&(options.enableTURNServer=!0,options.enableSTUNServer=!1,options.filterCandidatesType.host=!0,options.filterCandidatesType.srflx=!0,options.filterCandidatesType.relay=!1),self.once("readyStateChange",function(){},function(state,error){if(state===self.READY_STATE_CHANGE.ERROR)return log.error("Failed init() process ->",error),callback({error:error.content,errorCode:error.errorCode,status:error.status},null),!0;if(state===self.READY_STATE_CHANGE.COMPLETED){log.info("Completed init() successfully ->",options);var success=clone(self._initOptions);return success.serverUrl=self._path,success.readyState=self._readyState,success.selectedRoom=self._selectedRoom,success.TURNTransport=success.TURNServerTransport,callback(null,success),!0}}),self._initOptions=options,self._readyState=self.READY_STATE_CHANGE.INIT,self._selectedRoom=self._initOptions.defaultRoom,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),!options||!options.appKey||"string"!=typeof options.appKey)return self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{content:new Error("Please provide an app key"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH,status:-2},self._selectedRoom);self._path=self._initOptions.roomServer+"/api/"+self._initOptions.appKey+"/"+self._selectedRoom+(self._initOptions.credentials?"/"+self._initOptions.credentials.startDateTime+"/"+self._initOptions.credentials.duration+"?cred="+self._initOptions.credentials.credentials:"")+(self._initOptions.credentials?"&":"?")+"rand="+Date.now(),self._loadInfo()},Skylink.prototype._containsInList=function(listName,value,defaultProperty){var self=this;for(var property in self[listName])if(self[listName].hasOwnProperty(property)&&self[listName][property]===value)return value;return self[listName][defaultProperty]},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,retries=0;self._socketUseXDR="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest,url=self._initOptions.forceSSL?"https:"+url:url,function requestFn(){var xhr=new XMLHttpRequest,completed=!1;self._socketUseXDR&&(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest for CORS authentication."]),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}),xhr.onload=function(){if(!completed){completed=!0;var response=JSON.parse(xhr.responseText||xhr.response||"{}"),status=xhr.status||(response.success?200:400);if(response.success)return log.debug([null,"XMLHttpRequest",method,"Received sessions parameters ->"],response),void callback(response);log.error([null,"XMLHttpRequest",method,"Failed retrieving sessions parameters ->"],response),self._readyState=self.READY_STATE_CHANGE.ERROR,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:new Error(response.info||"XMLHttpRequest status not OK\nStatus was: "+status),errorCode:response.error||status},self._selectedRoom)}},xhr.onerror=function(error){completed||(completed=!0,log.error([null,"XMLHttpRequest",method,"Failed retrieving information with status ->"],xhr.status),self._readyState=self.READY_STATE_CHANGE.ERROR,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||-1,content:new Error("Network error occurred. (Status: "+xhr.status+")"),errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom))},xhr.onprogress=function(){log.debug([null,"XMLHttpRequest",method,"Retrieving information and config from webserver ->"],{url:url,params:params})};try{xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()}catch(error){return completed=!0,self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||-1,content:new Error("Failed starting XHR process."),errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom)}setTimeout(function(){completed||(completed=!0,xhr.onload=null,xhr.onerror=null,xhr.onprogress=null,retries<2?(retries++,requestFn()):(self._readyState=self.READY_STATE_CHANGE.ERROR,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||-1,content:new Error("Response timed out from API server"),errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_NO_REPONSE_ERROR},self._selectedRoom)))},self._initOptions.apiTimeout)}()},Skylink.prototype._parseInfo=function(info){if(log.log("Parsing parameter from server",info),!info.pc_constraints&&!info.offer_constraints)return void this._trigger("readyStateChange",this.READY_STATE_CHANGE.ERROR,{status:200,content:info.info,errorCode:info.error},self._selectedRoom);log.debug("Peer connection constraints:",info.pc_constraints),log.debug("Offer constraints:",info.offer_constraints),this._key=info.cid,this._appKeyOwner=info.apiOwner,this._signalingServer=info.ipSigserver,this._isPrivileged=info.isPrivileged,this._autoIntroduce=info.autoIntroduce,this._user={uid:info.username,token:info.userCred,timeStamp:info.timeStamp,streams:[],info:{}},this._room={id:info.room_key,token:info.roomCred,startDateTime:info.start,duration:info.len,connection:{peerConstraints:JSON.parse(info.pc_constraints),peerConfig:null,offerConstraints:JSON.parse(info.offer_constraints),sdpConstraints:{mandatory:{OfferToReceiveAudio:!0,OfferToReceiveVideo:!0}},mediaConstraints:JSON.parse(info.media_constraints)}},this._socketPorts={"http:":Array.isArray(info.httpPortList)&&info.httpPortList.length>0?info.httpPortList:[80,3e3],"https:":Array.isArray(info.httpsPortList)&&info.httpsPortList.length>0?info.httpsPortList:[443,3443]},this._readyState=this.READY_STATE_CHANGE.COMPLETED,this._trigger("readyStateChange",this.READY_STATE_CHANGE.COMPLETED,null,this._selectedRoom),log.info("Parsed parameters from webserver. Ready for web-realtime communication")},Skylink.prototype._loadInfo=function(){var self=this;if("function"!=typeof(globals.AdapterJS||window.AdapterJS||{}).webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used"),errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return globals.io||window.io?window.XMLHttpRequest?self._path?void AdapterJS.webRTCReady(function(){if(self._enableIceRestart="firefox"!==AdapterJS.webrtcDetectedBrowser||AdapterJS.webrtcDetectedVersion>=48,self._binaryChunkType="firefox"===AdapterJS.webrtcDetectedBrowser?self.DATA_TRANSFER_DATA_TYPE.BLOB:self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&"plugin"===AdapterJS.webrtcDetectedType?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("plugin"===AdapterJS.webrtcDetectedType&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error(error.message||error.toString()),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):0===Object.keys(self._currentCodecSupport.audio).length&&0===Object.keys(self._currentCodecSupport.video).length?(log.error("No audio/video codecs available to start connection."),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("No audio/video codecs available to start connection"),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=self.READY_STATE_CHANGE.LOADING,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(response){self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("No API Path is found"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH},self._selectedRoom)):(log.error("XMLHttpRequest not supported. Please upgrade your browser"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("XMLHttpRequest not available"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_XMLHTTPREQUEST_SUPPORT},self._selectedRoom)):(log.error("Socket.io not loaded. Please load socket.io"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("Socket.io not found"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_SOCKET_IO},self._selectedRoom))},Skylink.prototype._initSelectedRoom=function(room,callback){var self=this;if("function"==typeof room||void 0===room)return log.error("Invalid room provided. Room:",room),void callback(new Error("Invalid room provided"),null);var defaultRoom=self._initOptions.defaultRoom,options=clone(self._initOptions);options.iceServer=options.iceServer?options.iceServer.urls:null,options.defaultRoom!==room&&(options.defaultRoom=room),self.init(options,function(error,success){self._initOptions.defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})};var _LOG_KEY="SkylinkJS",_LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!1,_printTimestamp=!1,_storedLogs=[],_getStoredLogsFn=function(logLevel){if(void 0===logLevel)return _storedLogs;for(var returnLogs=[],i=0;i<_storedLogs.length;i++)_storedLogs[i][1]===_LOG_LEVELS[logLevel]&&returnLogs.push(_storedLogs[i]);return returnLogs},_clearAllStoredLogsFn=function(){_storedLogs=[]},_printAllStoredLogsFn=function(){for(var i=0;i<_storedLogs.length;i++){var timestamp=_storedLogs[i][0],log="undefined"!==console[_storedLogs[i][1]]?_storedLogs[i][1]:"log",message=_storedLogs[i][2],debugObject=_storedLogs[i][3];void 0!==debugObject?console[log](message,debugObject,timestamp):console[log](message,timestamp)}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="",datetime=new Date;if("object"==typeof message){if(outputLog+=message[0]?" ["+message[0]+"] -":" -",outputLog+=message[1]?" <<"+message[1]+">>":"",message[2])if(outputLog+=" ","object"==typeof message[2])for(var i=0;i=logLevel)if(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace){void 0===console.trace&&logLevel[3];void 0!==debugObject?(console[_LOG_LEVELS[logLevel]](outputLog,debugObject),void 0!==console.trace&&console.trace("")):(console[_LOG_LEVELS[logLevel]](outputLog),void 0!==console.trace&&console.trace(""))}else void 0!==debugObject?console[_LOG_LEVELS[logLevel]](outputLog,debugObject):console[_LOG_LEVELS[logLevel]](outputLog)},log={debug:function(message,object){_logFn(4,message,object)},log:function(message,object){_logFn(3,message,object)},info:function(message,object){_logFn(2,message,object)},warn:function(message,object){
+_logFn(1,message,object)},error:function(message,object){_logFn(0,message,object)}};Skylink.prototype.setLogLevel=function(logLevel){for(var level in this.LOG_LEVEL)if(this.LOG_LEVEL[level]===logLevel)return _logLevel=logLevel,void log.log([null,"Log",level,"Log level exists. Level is set"]);log.error([null,"Log",level,"Log level does not exist. Level is not set"])},Skylink.prototype.setDebugMode=function(isDebugMode){isDebugMode&&"object"==typeof isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0===isDebugMode.trace,_enableDebugStack=!0===isDebugMode.storeLogs,_printTimestamp=!0===isDebugMode.printTimestamp):!0===isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0,_printTimestamp=!1):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1,_printTimestamp=!1)};Skylink.prototype.on=function(eventName,callback){"function"==typeof callback?(this._EVENTS[eventName]=this._EVENTS[eventName]||[],this._EVENTS[eventName].push(callback),log.log([null,"Event",eventName,"Event is subscribed"])):log.error([null,"Event",eventName,"Provided parameter is not a function"])},Skylink.prototype.once=function(eventName,callback,condition,fireAlways){"boolean"==typeof condition&&(fireAlways=condition,condition=null),fireAlways=void 0!==fireAlways&&fireAlways,condition="function"!=typeof condition?function(){return!0}:condition,"function"==typeof callback?(this._onceEvents[eventName]=this._onceEvents[eventName]||[],this._onceEvents[eventName].push([callback,condition,fireAlways]),log.log([null,"Event",eventName,"Event is subscribed on condition"])):log.error([null,"Event",eventName,"Provided callback is not a function"])},Skylink.prototype.off=function(eventName,callback){if(eventName&&"string"==typeof eventName){if(void 0===callback)return this._EVENTS[eventName]=[],this._onceEvents[eventName]=[],void log.log([null,"Event",eventName,"All events are unsubscribed"]);for(var arr=this._EVENTS[eventName]||[],once=this._onceEvents[eventName]||[],i=0;i"],message);self._user.sid&&!self._peerMessagesStamps[self._user.sid]&&(self._peerMessagesStamps[self._user.sid]={userData:0,audioMuted:0,videoMuted:0});var checkStampFn=function(statusMessage){return statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].userData:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].videoMuted:statusMessage.type!==self._SIG_MESSAGE_TYPE.MUTE_AUDIO||!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].audioMuted},setStampFn=function(statusMessage){statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?self._peerMessagesStamps[self._user.sid].userData=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?self._peerMessagesStamps[self._user.sid].videoMuted=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&(self._peerMessagesStamps[self._user.sid].audioMuted=statusMessage.stamp)},setQueueFn=function(){log.debug([null,"Socket",null,"Starting queue timeout"]),self._socketMessageTimeout=setTimeout(function(){if((new Date).getTime()-self._timestamp.socketMessage<=interval)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},interval-((new Date).getTime()-self._timestamp.socketMessage))},triggerEventFn=function(eventMessage){eventMessage.type===self._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE&&self._trigger("incomingMessage",{content:eventMessage.data,isPrivate:!1,targetPeerId:null,listOfPeers:Object.keys(self._peerInformations),isDataChannel:!1,senderPeerId:self._user.sid},self._user.sid,self.getPeerInfo(),!0)},sendGroupMessageFn=function(groupMessageList){if(self._socketMessageTimeout=null,!(self._channelOpen&&self._user&&self._user.sid&&self._socket))return void log.warn([message.target||"Server","Socket",null,"Dropping of group messages as Socket connection is not opened or is at incorrect step ->"],groupMessageList);for(var strGroupMessageList=[],stamps={userData:0,audioMuted:0,videoMuted:0},k=0;kself._peerMessagesStamps[self._user.sid].userData&&groupMessageList[k].stamp>stamps.userData?stamps.userData=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].audioMuted&&groupMessageList[k].stamp>stamps.audioMuted?stamps.audioMuted=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].videoMuted&&groupMessageList[k].stamp>stamps.videoMuted&&(stamps.videoMuted=groupMessageList[k].stamp));for(var i=0;i"],clone(groupMessageList[i])),groupMessageList.splice(i,1),i--):strGroupMessageList.push(JSON.stringify(groupMessageList[i]));if(strGroupMessageList.length>0){var groupMessage={type:self._SIG_MESSAGE_TYPE.GROUP,lists:strGroupMessageList,mid:self._user.sid,rid:self._room.id};log.log([message.target||"Server","Socket",groupMessage.type,"Sending queued grouped message (max: 16 per group) ->"],clone(groupMessage)),self._socket.send(JSON.stringify(groupMessage)),self._timestamp.socketMessage=(new Date).getTime();for(var j=0;j0&&(self._socketMessageQueue.length-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=interval)log.debug([message.target||"Server","Socket",message.type,"Queueing socket message to prevent message drop ->"],clone(message)),self._socketMessageQueue.push(message),self._socketMessageTimeout||setQueueFn();else{if(!checkStampFn(message))return void log.warn([message.target||"Server","Socket",message.type,"Dropping of outdated status message ->"],clone(message));self._socketMessageTimeout&&clearTimeout(self._socketMessageTimeout),log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),setStampFn(message),triggerEventFn(message),self._timestamp.socketMessage=(new Date).getTime()}else log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),message.type===self._SIG_MESSAGE_TYPE.BYE&&self._inRoom&&self._user&&self._user.sid&&message.mid===self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo()))},Skylink.prototype._createSocket=function(type,joinRoomTimestamp){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._initOptions.socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._initOptions.socketServer&&"object"==typeof self._initOptions.socketServer&&Array.isArray(self._initOptions.socketServer.ports)&&self._initOptions.socketServer.ports.length>0?self._initOptions.socketServer.ports:self._socketPorts[self._signalingServerProtocol],fallbackType=null;null===self._signalingServerPort?(self._signalingServerPort=ports[0],fallbackType=self.SOCKET_FALLBACK.NON_FALLBACK):ports.indexOf(self._signalingServerPort)===ports.length-1||"string"==typeof self._initOptions.socketServer?"WebSocket"===type?(type="Polling",self._signalingServerPort=ports[0]):self._socketSession.finalAttempts++:self._signalingServerPort=ports[ports.indexOf(self._signalingServerPort)+1],"Polling"===type&&(options.reconnectionDelayMax=1e3,options.reconnectionAttempts=4,options.transports=["xhr-polling","jsonp-polling","polling"]);var url=self._signalingServerProtocol+"//"+self._signalingServer+":"+self._signalingServerPort+"?rand="+Date.now(),retries=0;self._initOptions.socketServer&&(url="string"==typeof self._initOptions.socketServer?self._initOptions.socketServer:(self._initOptions.socketServer.protocol?self._initOptions.socketServer.protocol:self._signalingServerProtocol)+"//"+self._initOptions.socketServer.url+":"+self._signalingServerPort),self._socketSession.transportType=type,self._socketSession.socketOptions=options,self._socketSession.socketServer=url,null===fallbackType&&(fallbackType="http:"===self._signalingServerProtocol?"Polling"===type?self.SOCKET_FALLBACK.LONG_POLLING:self.SOCKET_FALLBACK.FALLBACK_PORT:"Polling"===type?self.SOCKET_FALLBACK.LONG_POLLING_SSL:self.SOCKET_FALLBACK.FALLBACK_SSL_PORT,self._socketSession.attempts++,self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ATTEMPT,null,fallbackType,clone(self._socketSession)),self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))),self._socket&&self._closeChannel(),self._channelOpen=!1,log.log("Opening channel with signaling server url:",clone(self._socketSession));var socket=null;try{socket=io.connect(url,options)}catch(error){return log.error("Failed creating socket connection object ->",error),fallbackType===self.SOCKET_FALLBACK.NON_FALLBACK?self._trigger("socketError",self.SOCKET_ERROR.CONNECTION_FAILED,error,fallbackType,clone(self._socketSession)):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_FAILED,error,fallbackType,clone(self._socketSession)),void self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ABORTED,new Error("Reconnection aborted as there no more available ports, transports and final attempts left."),fallbackType,clone(self._socketSession))}socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),socket.on("reconnect_failed",function(){fallbackType===self.SOCKET_FALLBACK.NON_FALLBACK?self._trigger("socketError",self.SOCKET_ERROR.CONNECTION_FAILED,new Error('Failed connection with transport "'+type+'" and port '+self._signalingServerPort+"."),fallbackType,clone(self._socketSession)):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_FAILED,new Error('Failed reconnection with transport "'+type+'" and port '+self._signalingServerPort+"."),fallbackType,clone(self._socketSession)),self._socketSession.finalAttempts<2?self._createSocket(type,joinRoomTimestamp):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ABORTED,new Error("Reconnection aborted as there no more available ports, transports and final attempts left."),fallbackType,clone(self._socketSession))}),socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),socket.on("error",function(error){if(error&&error.message.indexOf("xhr poll error")>-1)return log.error([null,"Socket",null,"XHR poll connection unstable. Disconnecting.. ->"],error),void self._closeChannel();log.error([null,"Socket",null,"Exception occurred ->"],error),self._trigger("channelError",error,clone(self._socketSession))}),socket.on("disconnect",function(){self._channelOpen&&(self._channelOpen=!1,self._trigger("channelClose",clone(self._socketSession)),log.log([null,"Socket",null,"Channel closed"]),self._inRoom&&self._user&&self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo())))}),socket.on("message",function(messageStr){var message=JSON.parse(messageStr);if(log.log([null,"Socket",null,"Received message ->"],message),message.type===self._SIG_MESSAGE_TYPE.GROUP){log.debug("Bundle of "+message.lists.length+" messages");for(var i=0;i",message);for(var i=0;i-1:state===self.RECORDING_STATE.STOP})}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.STOP_RECORDING,rid:self._room.id,target:"MCU"}),log.debug(["MCU","Recording",null,"Stopping recording"])},Skylink.prototype.getRecordings=function(){return clone(this._recordings)},Skylink.prototype._processSigMessage=function(message,session){var origin=message.mid;if(origin&&origin!==this._user.sid||(origin="Server"),log.debug([origin,"Socket",message.type,"Received from peer ->"],clone(message)),message.mid===this._user.sid&&message.type!==this._SIG_MESSAGE_TYPE.REDIRECT&&message.type!==this._SIG_MESSAGE_TYPE.IN_ROOM)return void log.debug([origin,"Socket",message.type,"Ignoring message ->"],clone(message));switch(message.type){case this._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE:this._publicMessageHandler(message);break;case this._SIG_MESSAGE_TYPE.PRIVATE_MESSAGE:this._privateMessageHandler(message);break;case this._SIG_MESSAGE_TYPE.IN_ROOM:this._inRoomHandler(message);break;case this._SIG_MESSAGE_TYPE.ENTER:this._enterHandler(message);break;case this._SIG_MESSAGE_TYPE.WELCOME:this._welcomeHandler(message);break;case this._SIG_MESSAGE_TYPE.RESTART:this._restartHandler(message);break;case this._SIG_MESSAGE_TYPE.OFFER:this._offerHandler(message);break;case this._SIG_MESSAGE_TYPE.ANSWER:this._answerHandler(message);break;case this._SIG_MESSAGE_TYPE.CANDIDATE:this._candidateHandler(message);break;case this._SIG_MESSAGE_TYPE.BYE:this._byeHandler(message);break;case this._SIG_MESSAGE_TYPE.REDIRECT:this._redirectHandler(message);break;case this._SIG_MESSAGE_TYPE.UPDATE_USER:this._updateUserEventHandler(message);break;case this._SIG_MESSAGE_TYPE.MUTE_VIDEO:this._muteVideoEventHandler(message);break;case this._SIG_MESSAGE_TYPE.MUTE_AUDIO:this._muteAudioEventHandler(message);break;case this._SIG_MESSAGE_TYPE.STREAM:this._streamEventHandler(message);break;case this._SIG_MESSAGE_TYPE.ROOM_LOCK:this._roomLockEventHandler(message);break;case this._SIG_MESSAGE_TYPE.PEER_LIST:this._peerListEventHandler(message);break;case this._SIG_MESSAGE_TYPE.INTRODUCE_ERROR:this._introduceErrorEventHandler(message);break;case this._SIG_MESSAGE_TYPE.APPROACH:this._approachEventHandler(message);break;case this._SIG_MESSAGE_TYPE.RECORDING:this._recordingEventHandler(message);break;case this._SIG_MESSAGE_TYPE.END_OF_CANDIDATES:this._endOfCandidatesHandler(message);break;default:log.error([message.mid,"Socket",message.type,"Unsupported message ->"],clone(message))}},Skylink.prototype._peerListEventHandler=function(message){var self=this;self._peerList=message.result,log.log(["Server",null,message.type,"Received list of peers"],self._peerList),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.RECEIVED,self._user.sid,self._peerList)},Skylink.prototype._endOfCandidatesHandler=function(message){var self=this,targetMid=message.mid;self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&(self._peerEndOfCandidatesCounter[targetMid].expectedLen=message.noOfExpectedCandidates||0,self._signalingEndOfCandidates(targetMid))},Skylink.prototype._introduceErrorEventHandler=function(message){var self=this;log.log(["Server",null,message.type,"Introduce failed. Reason: "+message.reason]),self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,message.sendingPeerId,message.receivingPeerId,message.reason)},Skylink.prototype._approachEventHandler=function(message){var self=this;log.log(["Server",null,message.type,"Approaching peer"],message.target),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._redirectHandler=function(message){if(log.log(["Server",null,message.type,"System action warning:"],{message:message.info,reason:message.reason,action:message.action}),message.action===this.SYSTEM_ACTION.REJECT)for(var key in this._peerConnections)this._peerConnections.hasOwnProperty(key)&&this._removePeer(key);"toClose"===message.reason&&(message.reason="toclose"),this._trigger("systemAction",message.action,message.info,message.reason)},Skylink.prototype._updateUserEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer updated userData:"],message.userData),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].userData=message.stamp}this._peerInformations[targetMid].userData=message.userData||{},this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._roomLockEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,message.type,"Room lock status:"],message.lock),this._trigger("roomLock",message.lock,targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._muteAudioEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's audio muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].audioMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.audioMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,message.type,"Peer does not have any user information"])},Skylink.prototype._muteVideoEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's video muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].videoMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.videoMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._streamEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Peer's stream status:"],message.status),this._peerInformations[targetMid]&&message.streamId?(this._streamsSession[targetMid]=this._streamsSession[targetMid]||{},"ended"===message.status&&(message.settings&&"object"==typeof message.settings&&void 0===this._streamsSession[targetMid][message.streamId]&&(this._streamsSession[targetMid][message.streamId]={audio:message.settings.audio,video:message.settings.video}),this._handleEndedStreams(targetMid,message.streamId))):log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._byeHandler=function(message){var targetMid=message.mid;(this._user||{}).sid!==targetMid?(log.log([targetMid,null,message.type,"Peer has left the room"]),this._removePeer(targetMid)):log.log([targetMid,null,message.type,"Self has left the room"])},Skylink.prototype._privateMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received private message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!0,targetPeerId:message.target,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._publicMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received public message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!1,targetPeerId:null,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._recordingEventHandler=function(message){var self=this;if(log.debug(["MCU","Recording",null,"Received recording message ->"],message),"on"===message.action)self._recordings[message.recordingId]||(log.debug(["MCU","Recording",message.recordingId,"Started recording"]),self._currentRecordingId=message.recordingId,self._recordings[message.recordingId]={active:!0,state:self.RECORDING_STATE.START,startedDateTime:(new Date).toISOString(),endedDateTime:null,mixingDateTime:null,links:null,error:null},self._recordingStartInterval=setTimeout(function(){log.log(["MCU","Recording",message.recordingId,"4 seconds has been recorded. Recording can be stopped now"]),self._recordingStartInterval=null},4e3),self._trigger("recordingState",self.RECORDING_STATE.START,message.recordingId,null,null));else if("off"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,'Received request of "off" but the session is empty']);self._currentRecordingId=null,self._recordingStartInterval&&(clearTimeout(self._recordingStartInterval),log.warn(["MCU","Recording",message.recordingId,"Recording stopped abruptly before 4 seconds"]),self._recordingStartInterval=null),log.debug(["MCU","Recording",message.recordingId,"Stopped recording"]),self._recordings[message.recordingId].active=!1,self._recordings[message.recordingId].state=self.RECORDING_STATE.STOP,
+self._recordings[message.recordingId].endedDateTime=(new Date).toISOString(),self._trigger("recordingState",self.RECORDING_STATE.STOP,message.recordingId,null,null)}else if("url"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,"Received URL but the session is empty"]);var links={};if(Array.isArray(message.urls))for(var i=0;i"],recordingError);log.error(["MCU","Recording",message.recordingId,"Recording failure ->"],recordingError),self._recordings[message.recordingId].state=self.RECORDING_STATE.ERROR,self._recordings[message.recordingId].error=recordingError,self._recordings[message.recordingId].active&&(log.debug(["MCU","Recording",message.recordingId,"Stopped recording abruptly"]),self._recordings[message.recordingId].active=!1),self._trigger("recordingState",self.RECORDING_STATE.ERROR,message.recordingId,null,recordingError)}},Skylink.prototype._inRoomHandler=function(message){var self=this;log.log(["Server",null,message.type,"User is now in the room and functionalities are now available. Config received:"],message.pc_config),self._room.connection.peerConfig=self._setIceServers((message.pc_config||{}).iceServers||[]),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._initOptions.priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._initOptions.priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.ENFORCE_OFFERER?2e15:-2e15),self._trigger("peerJoined",self._user.sid,self.getPeerInfo(),!0),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var streamId=null;self._streams.screenshare&&self._streams.screenshare.stream?(streamId=self._streams.screenshare.stream.id||self._streams.screenshare.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.screenshare.stream,!0,self.getPeerInfo(),!0,streamId)):self._streams.userMedia&&self._streams.userMedia.stream&&(streamId=self._streams.userMedia.stream.id||self._streams.userMedia.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.userMedia.stream,!0,self.getPeerInfo(),!1,streamId));var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._enterHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "enter" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid)}self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0};var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),receiveOnly:self.getPeerInfo().config.receiveOnly,os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg),isNewPeer&&self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._restartHandler=function(message){var self=this,targetMid=message.mid,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "restart" received ->'],message),!self._peerInformations[targetMid])return void log.error([targetMid,"RTCPeerConnection",null,"Peer does not have an existing session. Ignoring restart process."]);if("MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId or publishOnly case ->'],message);if(self._hasMCU&&!self._initOptions.mcuUseRenegoRestart)return log.warn([targetMid,"RTCPeerConnection",null,"Dropping restart request as MCU does not support re-negotiation. Restart workaround is to re-join Room for Peer."]),void self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!1);if(self._peerInformations[targetMid]=userInfo,self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid].len=0,self._peerPriorityWeight>message.weight){if(log.debug([targetMid,"RTCPeerConnection",null,"Re-negotiating new offer/answer."]),self._peerMessagesStamps[targetMid].hasRestart)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "restart" received.']);self._peerMessagesStamps[targetMid].hasRestart=!0,self._doOffer(targetMid,!0===message.doIceRestart,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start re-negotiation."]);var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===message.doIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,isRestartResend:!0,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._sendChannelMessage(restartMsg)}self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!0===message.doIceRestart)},Skylink.prototype._welcomeHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "welcome" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)}if(self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0,hasWelcome:!1},self._hasMCU||self._peerPriorityWeight>message.weight){if(self._peerMessagesStamps[targetMid].hasWelcome)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "welcome" received.']);log.debug([targetMid,"RTCPeerConnection",null,"Starting negotiation"]),self._peerMessagesStamps[targetMid].hasWelcome=!0,self._doOffer(targetMid,!1,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start negotiation."]);var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg)}};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._offerHandler=function(message){var self=this,targetMid=message.mid,pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for offer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}log.log([targetMid,null,message.type,"Received offer from peer. Session description:"],clone(message));var offer={type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],offer),offer.sdp=self._removeSDPFilteredCandidates(targetMid,offer),offer.sdp=self._setSDPCodec(targetMid,offer),offer.sdp=self._setSDPBitrate(targetMid,offer),offer.sdp=self._setSDPCodecParams(targetMid,offer),offer.sdp=self._removeSDPCodecs(targetMid,offer),offer.sdp=self._removeSDPREMBPackets(targetMid,offer),offer.sdp=self._handleSDPConnectionSettings(targetMid,offer,"remote"),offer.sdp=self._removeSDPUnknownAptRtx(targetMid,offer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "stable" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.resend});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,offer);var onSuccessCbFn=function(){log.debug([targetMid,"RTCSessionDescription",message.type,"Remote description set"]),pc.setOffer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.OFFER,targetMid),self._addIceCandidateFromQueue(targetMid),self._doAnswer(targetMid)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,offer:offer})};pc.setRemoteDescription(new RTCSessionDescription(offer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._candidateHandler=function(message){var targetMid=message.mid;if(!message.candidate&&!message.id)return void log.warn([targetMid,"RTCIceCandidate",null,"Received invalid ICE candidate message ->"],message);var canId="can-"+(new Date).getTime(),candidateType=message.candidate.split(" ")[7]||"",candidate=new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate,sdpMid:message.id});if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Received ICE candidate ->"],candidate),this._peerEndOfCandidatesCounter[targetMid]=this._peerEndOfCandidatesCounter[targetMid]||{},this._peerEndOfCandidatesCounter[targetMid].len=this._peerEndOfCandidatesCounter[targetMid].len||0,this._peerEndOfCandidatesCounter[targetMid].hasSet=!1,this._peerEndOfCandidatesCounter[targetMid].len++,this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.RECEIVED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!this._peerConnections[targetMid]||this._peerConnections[targetMid].signalingState===this.PEER_CONNECTION_STATE.CLOSED)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed.")),void this._signalingEndOfCandidates(targetMid);if(this._initOptions.filterCandidatesType[candidateType]){if(!this._hasMCU||!this._initOptions.forceTURN)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping received ICE candidate as it matches ICE candidate filtering flag ->"],candidate),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Dropping of processing ICE candidate as it matches ICE candidate filtering flag.")),void this._signalingEndOfCandidates(targetMid);log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Not dropping received ICE candidate as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured ->"],candidate)}this._peerConnections[targetMid].remoteDescription&&this._peerConnections[targetMid].remoteDescription.sdp&&this._peerConnections[targetMid].localDescription&&this._peerConnections[targetMid].localDescription.sdp?this._addIceCandidate(targetMid,canId,candidate):this._addIceCandidateToQueue(targetMid,canId,candidate),this._signalingEndOfCandidates(targetMid),this._gatheredCandidates[targetMid]||(this._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),this._gatheredCandidates[targetMid].receiving[candidateType].push({sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate})},Skylink.prototype._answerHandler=function(message){var self=this,targetMid=message.mid;log.log([targetMid,null,message.type,"Received answer from peer. Session description:"],clone(message));var pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for answer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}var answer={type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],answer),answer.sdp=self._removeSDPFilteredCandidates(targetMid,answer),answer.sdp=self._setSDPCodec(targetMid,answer),answer.sdp=self._setSDPBitrate(targetMid,answer),answer.sdp=self._setSDPCodecParams(targetMid,answer),answer.sdp=self._removeSDPCodecs(targetMid,answer),answer.sdp=self._removeSDPREMBPackets(targetMid,answer),answer.sdp=self._handleSDPConnectionSettings(targetMid,answer,"remote"),answer.sdp=self._removeSDPUnknownAptRtx(targetMid,answer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "have-local-offer" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.restart});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,answer);var onSuccessCbFn=function(){log.debug([targetMid,null,message.type,"Remote description set"]),pc.setAnswer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ANSWER,targetMid),self._addIceCandidateFromQueue(targetMid),self._peerMessagesStamps[targetMid]&&(self._peerMessagesStamps[targetMid].hasRestart=!1),self._dataChannels[targetMid]&&(-1===pc.remoteDescription.sdp.indexOf("m=application")||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,answer:answer})};pc.setRemoteDescription(new RTCSessionDescription(answer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=(agentVer||"").split("."),partsB=(requiredVer||"").split("."),i=0;i0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for sendStream() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream)):"function"==typeof callback&&callback(null,stream)};if(!("object"==typeof options&&null!==options||AdapterJS&&AdapterJS.WebRTCPlugin&&AdapterJS.WebRTCPlugin.plugin&&["function","object"].indexOf(typeof options)>-1)){var invalidOptionsError="Provided stream settings is invalid";return log.error(invalidOptionsError,options),void("function"==typeof callback&&callback(new Error(invalidOptionsError),null))}if(self._inRoom||log.warn("There are no peers to send stream to as not in room!"),"edge"===AdapterJS.webrtcDetectedBrowser){var edgeNotSupportError="Edge browser currently does not support renegotiation.";return log.error(edgeNotSupportError,options),void("function"==typeof callback&&callback(new Error(edgeNotSupportError),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0&&(useMediaSource=enableAudioArr)}else enableAudio&&"object"==typeof enableAudio?enableAudio.sourceId&&enableAudio.mediaSource||(enableAudioSettings={usedtx:"boolean"==typeof enableAudio.usedtx?enableAudio.usedtx:null,useinbandfec:"boolean"==typeof enableAudio.useinbandfec?enableAudio.useinbandfec:null,stereo:!0===enableAudio.stereo,echoCancellation:!1!==enableAudio.echoCancellation,deviceId:enableAudio.deviceId}):!0===enableAudio?enableAudioSettings=!0===enableAudio&&{usedtx:null,useinbandfec:null,stereo:!1,echoCancellation:!0,deviceId:null}:"function"==typeof enableAudio&&(callback=enableAudio,enableAudio=!1);if(mediaSource&&"string"==typeof mediaSource||mediaSource&&"object"==typeof mediaSource&&mediaSource.sourceId&&mediaSource.mediaSource)checkIfSourceExistsFn("object"==typeof mediaSource?mediaSource.mediaSource:mediaSource)&&(useMediaSource=["object"==typeof mediaSource?mediaSource.mediaSource:mediaSource]),useMediaSourceId="object"==typeof mediaSource?mediaSource.sourceId:null;else if(Array.isArray(mediaSource)){for(var mediaSourceArr=[],i=0;i0&&(useMediaSource=mediaSourceArr)}else"function"==typeof mediaSource&&(callback=mediaSource);useMediaSource.indexOf("audio")>-1&&-1===useMediaSource.indexOf("tab")&&(useMediaSource.splice(useMediaSource.indexOf("audio"),1),0===useMediaSource.length&&(useMediaSource=[self.MEDIA_SOURCE.SCREEN])),self._throttle(function(runFn){if(runFn){var settings={settings:{audio:enableAudioSettings,video:{screenshare:!0,exactConstraints:!1}},getUserMediaSettings:{audio:!1,video:{mediaSource:useMediaSource}}};"plugin"===AdapterJS.webrtcDetectedType&&useMediaSourceId&&(settings.getUserMediaSettings.video.optional=[{screenId:useMediaSourceId}]);var mediaAccessSuccessFn=function(stream){self.off("mediaAccessError",mediaAccessErrorFn),self._inRoom?(self._trigger("incomingStream",self._user.sid,stream,!0,self.getPeerInfo(),!0,stream.id||stream.label),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0),Object.keys(self._peerConnections).length>0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for shareScreen() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream)):"function"==typeof callback&&callback(null,stream)},mediaAccessErrorFn=function(error){self.off("mediaAccessSuccess",mediaAccessSuccessFn),"function"==typeof callback&&callback(error,null)};self.once("mediaAccessSuccess",mediaAccessSuccessFn,function(stream,isScreensharing){return isScreensharing}),self.once("mediaAccessError",mediaAccessErrorFn,function(error,isScreensharing){return isScreensharing});var getUserMediaAudioSettings=!!enableAudioSettings&&{echoCancellation:enableAudioSettings.echoCancellation};try{var hasDefaultAudioTrack=!1;enableAudioSettings&&("firefox"===AdapterJS.webrtcDetectedBrowser?(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio=getUserMediaAudioSettings):useMediaSource.indexOf("audio")>-1&&useMediaSource.indexOf("tab")>-1&&(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio={}));var onSuccessCbFn=function(stream){if(hasDefaultAudioTrack||!enableAudioSettings)return void self._onStreamAccessSuccess(stream,settings,!0,!1);settings.getUserMediaSettings.audio=getUserMediaAudioSettings;var onAudioSuccessCbFn=function(audioStream){try{audioStream.addTrack(stream.getVideoTracks()[0]),self.once("mediaAccessSuccess",function(){self._streams.screenshare.streamClone=stream},function(stream,isScreensharing){return isScreensharing}),self._onStreamAccessSuccess(audioStream,settings,!0,!1)}catch(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)}},onAudioErrorCbFn=function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)};navigator.getUserMedia({audio:getUserMediaAudioSettings},onAudioSuccessCbFn,onAudioErrorCbFn)},onErrorCbFn=function(error){self._onStreamAccessError(error,settings,!0,!1)};if("function"!=typeof(AdapterJS||{}).webRTCReady)return onErrorCbFn(new Error("Failed to call getUserMedia() as AdapterJS is not yet loaded!"));AdapterJS.webRTCReady(function(){navigator.getUserMedia(settings.getUserMediaSettings,onSuccessCbFn,onErrorCbFn)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._initOptions.throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._initOptions.throttleIntervals.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._initOptions.throttleIntervals.shareScreen)},Skylink.prototype.stopScreen=function(){this._streams.screenshare&&(this._stopStreams({screenshare:!0}),this._inRoom&&(this._streams.userMedia&&this._streams.userMedia.stream&&(this._trigger("incomingStream",this._user.sid,this._streams.userMedia.stream,!0,this.getPeerInfo(),!1,this._streams.userMedia.stream.id||this._streams.userMedia.stream.label),this._trigger("peerUpdated",this._user.sid,this.getPeerInfo(),!0)),this._refreshPeerConnection(Object.keys(this._peerConnections),{},!1)))},Skylink.prototype.getStreamSources=function(callback){var outputSources={audio:{input:[],output:[]},video:{input:[]}};if("function"!=typeof callback)return log.error("Please provide the callback.");var sourcesListFn=function(sources){sources.forEach(function(sourceItem){var item={deviceId:sourceItem.deviceId||sourceItem.sourceId||"default",label:sourceItem.label,groupId:sourceItem.groupId||null};item.label=item.label||"Source for "+item.deviceId,["audio","audioinput"].indexOf(sourceItem.kind)>-1?outputSources.audio.input.push(item):["video","videoinput"].indexOf(sourceItem.kind)>-1?outputSources.video.input.push(item):"audiooutput"===sourceItem.kind&&outputSources.audio.output.push(item)}),callback(outputSources)};navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.enumerateDevices?navigator.mediaDevices.enumerateDevices().then(sourcesListFn):window.MediaStreamTrack&&"function"==typeof MediaStreamTrack.getSources?MediaStreamTrack.getSources(sourcesListFn):sourcesListFn("function"==typeof navigator.getUserMedia?[{deviceId:"default",kind:"audioinput",label:"Default Audio Track"},{deviceId:"default",kind:"videoinput",label:"Default Video Track"}]:[])},Skylink.prototype.getScreenSources=function(callback){var outputSources={mediaSource:[],mediaSourceInput:[]};return"function"!=typeof callback?log.error("Please provide the callback."):navigator.userAgent.toLowerCase().indexOf("android")>-1?("chrome"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=59&&(outputSources.mediaSource=["screen"]),void callback(outputSources)):"plugin"===AdapterJS.webrtcDetectedType?void AdapterJS.webRTCReady(function(){if(AdapterJS.WebRTCPlugin.plugin&&AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable&&AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature&&(outputSources.mediaSource=["window","screen"],"function"==typeof AdapterJS.WebRTCPlugin.plugin.getScreensharingSources))return void AdapterJS.WebRTCPlugin.plugin.getScreensharingSources(function(sources){sources.forEach(sources,function(sourceItem){var item={sourceId:sourceItem.id||sourceItem.sourceId||"default",label:sourceItem.label,mediaSource:sourceItem.kind||"screen"};item.label=item.label||"Source for "+item.sourceId,outputSources.mediaSourceInput.push(item)}),callback(outputSources)});callback(outputSources)}):(("chrome"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=34||"firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=38||"opera"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=21)&&("opera"!==AdapterJS.webrtcDetectedBrowser||AdapterJS.extensionInfo&&AdapterJS.extensionInfo.opera&&AdapterJS.extensionInfo.opera.extensionId||log.warn("Please ensure that your application allows Opera screensharing!"),outputSources.mediaSource=["window","screen"],"chrome"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=52||"opera"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=39?outputSources.mediaSource.push("tab","audio"):"firefox"===AdapterJS.webrtcDetectedBrowser&&outputSources.mediaSource.push("browser","camera","application")),void callback(outputSources))},Skylink.prototype._muteStreams=function(){var self=this,hasVideo=!1,hasAudio=!1,muteFn=function(stream){for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",self._streamsMutedSettings),{hasVideo:hasVideo,hasAudio:hasAudio}},Skylink.prototype._stopStreams=function(options){var self=this,stopFn=function(stream){var streamId=stream.id||stream.label;log.debug([null,"MediaStream",streamId,"Stopping Stream ->"],stream);try{for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",options)},Skylink.prototype._parseStreamSettings=function(options){var settings={settings:{audio:!1,video:!1},mutedSettings:{shouldAudioMuted:!1,shouldVideoMuted:!1},getUserMediaSettings:{audio:!1,video:!1}};return options.audio&&(settings.settings.audio={stereo:!1,exactConstraints:!!options.useExactConstraints,echoCancellation:!0},settings.getUserMediaSettings.audio={echoCancellation:!0},"object"==typeof options.audio&&("boolean"==typeof options.audio.stereo&&(settings.settings.audio.stereo=options.audio.stereo),"boolean"==typeof options.audio.useinbandfec&&(settings.settings.audio.useinbandfec=options.audio.useinbandfec),"boolean"==typeof options.audio.usedtx&&(settings.settings.audio.usedtx=options.audio.usedtx),"number"==typeof options.audio.maxplaybackrate&&options.audio.maxplaybackrate>=8e3&&options.audio.maxplaybackrate<=48e3&&(settings.settings.audio.maxplaybackrate=options.audio.maxplaybackrate),"boolean"==typeof options.audio.mute&&(settings.mutedSettings.shouldAudioMuted=options.audio.mute),"edge"!==AdapterJS.webrtcDetectedBrowser&&("boolean"==typeof options.audio.echoCancellation&&(settings.settings.audio.echoCancellation=options.audio.echoCancellation,settings.getUserMediaSettings.audio.echoCancellation=options.audio.echoCancellation),Array.isArray(options.audio.optional)&&(settings.settings.audio.optional=clone(options.audio.optional),settings.getUserMediaSettings.audio.optional=clone(options.audio.optional)),options.audio.deviceId&&"string"==typeof options.audio.deviceId&&"firefox"!==AdapterJS.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,settings.getUserMediaSettings.audio.deviceId=options.useExactConstraints?{exact:options.audio.deviceId}:{ideal:options.audio.deviceId}))),"edge"===AdapterJS.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio=!0)),options.video&&(settings.settings.video={resolution:clone(this.VIDEO_RESOLUTION.VGA),screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video={},"object"==typeof options.video?("boolean"==typeof options.video.mute&&(settings.mutedSettings.shouldVideoMuted=options.video.mute),Array.isArray(options.video.optional)&&(settings.settings.video.optional=clone(options.video.optional),settings.getUserMediaSettings.video.optional=clone(options.video.optional)),options.video.deviceId&&"string"==typeof options.video.deviceId&&"firefox"!==AdapterJS.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,settings.getUserMediaSettings.video.deviceId=options.useExactConstraints?{exact:options.video.deviceId}:{ideal:options.video.deviceId}),options.video.resolution&&"object"==typeof options.video.resolution&&((options.video.resolution.width&&"object"==typeof options.video.resolution.width||"number"==typeof options.video.resolution.width)&&(settings.settings.video.resolution.width=options.video.resolution.width),(options.video.resolution.height&&"object"==typeof options.video.resolution.height||"number"==typeof options.video.resolution.height)&&(settings.settings.video.resolution.height=options.video.resolution.height)),settings.getUserMediaSettings.video.width="object"==typeof settings.settings.video.resolution.width?settings.settings.video.resolution.width:options.useExactConstraints?{exact:settings.settings.video.resolution.width}:{max:settings.settings.video.resolution.width},settings.getUserMediaSettings.video.height="object"==typeof settings.settings.video.resolution.height?settings.settings.video.resolution.height:options.useExactConstraints?{exact:settings.settings.video.resolution.height}:{max:settings.settings.video.resolution.height},(options.video.frameRate&&"object"==typeof options.video.frameRate||"number"==typeof options.video.frameRate&&"plugin"!==AdapterJS.webrtcDetectedType)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}),options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&"plugin"===AdapterJS.webrtcDetectedType&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):settings.getUserMediaSettings.video={width:options.useExactConstraints?{exact:settings.settings.video.resolution.width}:{max:settings.settings.video.resolution.width},height:options.useExactConstraints?{exact:settings.settings.video.resolution.height}:{max:settings.settings.video.resolution.height}},"edge"===AdapterJS.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,streamHasEnded=!1;if(log.log([null,"MediaStream",streamId,"Has access to stream ->"],stream),!isScreenSharing&&self._streams.userMedia?self._stopStreams({userMedia:!0,screenshare:!1}):isScreenSharing&&self._streams.screenshare&&self._stopStreams({userMedia:!1,screenshare:!0}),self._streamsStoppedCbs[streamId]=function(){log.log([null,"MediaStream",streamId,"Stream has ended"]),streamHasEnded=!0,self._trigger("mediaAccessStopped",!!isScreenSharing,!!isAudioFallback,streamId),self._inRoom&&(log.debug([null,"MediaStream",streamId,"Sending Stream ended status to Peers"]),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.STREAM,mid:self._user.sid,rid:self._room.id,cid:self._key,streamId:streamId,settings:settings.settings,status:"ended"}),self._trigger("streamEnded",self._user.sid,self.getPeerInfo(),!0,!!isScreenSharing,streamId),isScreenSharing&&self._streams.screenshare&&self._streams.screenshare.stream&&(self._streams.screenshare.stream.id||self._streams.screenshare.stream.label)===streamId?self._streams.screenshare=null:!isScreenSharing&&self._streams.userMedia&&self._streams.userMedia.stream&&(self._streams.userMedia.stream.id||self._streams.userMedia.stream.label)===streamId&&(self._streams.userMedia=null))},["chrome","opera"].indexOf(AdapterJS.webrtcDetectedBrowser)>-1?(stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},isScreenSharing&&stream.getVideoTracks().length>0&&(stream.getVideoTracks()[0].onended=function(){setTimeout(function(){!streamHasEnded&&self._inRoom&&self.stopScreen()},350)})):"firefox"===AdapterJS.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._initOptions.audioFallback){log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0);var onAudioSuccessCbFn=function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},onAudioErrorCbFn=function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)};return void navigator.getUserMedia({audio:!0},onAudioSuccessCbFn,onAudioErrorCbFn)}log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this,streamId=self._peerConnections[targetMid]&&self._peerConnections[targetMid].remoteStreamId||stream.id||stream.label;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",streamId,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",streamId,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",streamId,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,streamId),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId];if(pc){var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)&&self._getSDPCommonSupports(peerId,pc.remoteDescription).video,offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPCommonSupports(peerId,pc.remoteDescription).audio;if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){if(!updatedStream||(!pc.localStreamId||updatedStream.id!==pc.localStreamId)){if("edge"!==AdapterJS.webrtcDetectedBrowser||self._initOptions.useEdgeWebRTC&&window.msRTCPeerConnection?pc.getLocalStreams().forEach(function(stream){pc.removeStream(stream)}):pc.getSenders().forEach(function(sender){pc.removeTrack(sender)}),!offerToReceiveAudio&&!offerToReceiveVideo)return;updatedStream&&("edge"!==AdapterJS.webrtcDetectedBrowser||self._initOptions.useEdgeWebRTC&&window.msRTCPeerConnection?pc.addStream(updatedStream):updatedStream.getTracks().forEach(function(track){"audio"===track.kind&&!offerToReceiveAudio||"video"===track.kind&&!offerToReceiveVideo||pc.addTrack(track,updatedStream)}),pc.localStreamId=updatedStream.id||updatedStream.label,pc.localStream=updatedStream)}};self._streams.screenshare&&self._streams.screenshare.stream?(log.debug([peerId,"MediaStream",null,"Sending screen"],self._streams.screenshare.stream),updateStreamFn(self._streams.screenshare.stream)):self._streams.userMedia&&self._streams.userMedia.stream?(log.debug([peerId,"MediaStream",null,"Sending stream"],self._streams.userMedia.stream),updateStreamFn(self._streams.userMedia.stream)):(log.warn([peerId,"MediaStream",null,"No media to send. Will be only receiving"]),updateStreamFn(null))}else log.warn([peerId,"MediaStream",null,"Not adding any stream as signalingState is closed"])}else log.warn([peerId,"MediaStream",self._mediaStream,"Not adding stream as peerconnection object does not exists"])}catch(error){(error.message||"").indexOf("already added")>-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){if(self._streamsSession[peerId][streamId]){var peerInfo=clone(self.getPeerInfo(peerId));peerInfo.settings.audio=clone(self._streamsSession[peerId][streamId].audio),peerInfo.settings.video=clone(self._streamsSession[peerId][streamId].video);var hasScreenshare=peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&!!peerInfo.settings.video.screenshare;self._streamsSession[peerId][streamId]=!1,self._trigger("streamEnded",peerId,peerInfo,!1,hasScreenshare,streamId)}};if(checkStreamId)renderEndedFn(checkStreamId);else if(self._peerConnections[peerId])for(var streamId in self._streamsSession[peerId])self._streamsSession[peerId].hasOwnProperty(streamId)&&self._streamsSession[peerId][streamId]&&renderEndedFn(streamId)},Skylink.prototype._setSDPCodecParams=function(targetMid,sessionDescription){var self=this,parseFn=function(type,codecName,samplingRate,settings){var mLine=sessionDescription.sdp.match(new RegExp("m="+type+" .*\r\n","gi"));if(Array.isArray(mLine)&&mLine.length>0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}
+return"number"==typeof bw&&bw>0?-1===cLineIndex?void log.error([targetMid,"RTCSessionDesription",sessionDescription.type,'Failed setting "'+type+'" bandwidth as c-line is missing.']):(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Limiting maximum sending "'+type+'" bandwidth ->'],bw),void sdpLines.splice(cLineIndex+1,0,"firefox"===window.webrtcDetectedBrowser?"b=TIAS:"+(1e3*bw*(window.webrtcDetectedVersion>52&&window.webrtcDetectedVersion<55?1e3:1)).toFixed(0):"b=AS:"+bw)):void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not limiting "'+type+'" bandwidth'])},bASAudioBw=this._streamsBandwidthSettings.bAS.audio,bASVideoBw=this._streamsBandwidthSettings.bAS.video,bASDataBw=this._streamsBandwidthSettings.bAS.data,googleXMinBw=this._streamsBandwidthSettings.googleX.min,googleXMaxBw=this._streamsBandwidthSettings.googleX.max;if(this._peerCustomConfigs[targetMid]&&(this._peerCustomConfigs[targetMid].bandwidth&&"object"==typeof this._peerCustomConfigs[targetMid].bandwidth&&("number"==typeof this._peerCustomConfigs[targetMid].bandwidth.audio&&(bASAudioBw=this._peerCustomConfigs[targetMid].bandwidth.audio),"number"==typeof this._peerCustomConfigs[targetMid].bandwidth.video&&(bASVideoBw=this._peerCustomConfigs[targetMid].bandwidth.video),"number"==typeof this._peerCustomConfigs[targetMid].bandwidth.data&&(bASDataBw=this._peerCustomConfigs[targetMid].bandwidth.data)),this._peerCustomConfigs[targetMid].googleXBandwidth&&"object"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth&&("number"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth.min&&(googleXMinBw=this._peerCustomConfigs[targetMid].googleXBandwidth.min),"number"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth.max&&(googleXMaxBw=this._peerCustomConfigs[targetMid].googleXBandwidth.max))),parseFn("audio",bASAudioBw),parseFn("video",bASVideoBw),parseFn("data",bASDataBw),"number"==typeof googleXMinBw||"number"==typeof googleXMaxBw){for(var codec=null,codecRtpMapLineIndex=-1,codecFmtpLineIndex=-1,j=0;j-1){var xGoogleParams="";"number"==typeof googleXMinBw&&(xGoogleParams+="x-google-min-bitrate="+googleXMinBw+";"),"number"==typeof googleXMaxBw&&(xGoogleParams+="x-google-max-bitrate="+googleXMaxBw+";"),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Limiting x-google-bitrate ->"],xGoogleParams),codecFmtpLineIndex>-1?sdpLines[codecFmtpLineIndex]+=(sdpLines[codecFmtpLineIndex].split(" ")[1]?";":"")+xGoogleParams:sdpLines.splice(codecRtpMapLineIndex+1,0,"a=fmtp:"+codec+" "+xGoogleParams)}}return sdpLines.join("\r\n")},Skylink.prototype._setSDPCodec=function(targetMid,sessionDescription,overrideSettings){var self=this,parseFn=function(type,codecSettings){var codec="object"==typeof codecSettings?codecSettings.codec:codecSettings,samplingRate="object"==typeof codecSettings?codecSettings.samplingRate:null,channels="object"==typeof codecSettings?codecSettings.channels:null;if(codec===self["audio"===type?"AUDIO_CODEC":"VIDEO_CODEC"].AUTO)return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not preferring any codec for "'+type+'" streaming. Using browser selection.']);var mLine=sessionDescription.sdp.match(new RegExp("m="+type+" .*\r\n","gi"));if(!(Array.isArray(mLine)&&mLine.length>0))return void log.error([targetMid,"RTCSessionDesription",sessionDescription.type,'Not preferring any codec for "'+type+'" streaming as m= line is not found.']);var setLineFn=function(codecsList,isSROk,isChnlsOk){if(Array.isArray(codecsList)&&codecsList.length>0){isSROk||(samplingRate=null),isChnlsOk||(channels=null),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Preferring "'+codec+'" (samplingRate: '+(samplingRate||"n/a")+", channels: "+(channels||"n/a")+') for "'+type+'" streaming.']);var line=mLine[0],lineParts=line.replace("\r\n","").split(" ");line=lineParts[0]+" "+lineParts[1]+" "+lineParts[2]+" ",lineParts.splice(0,3);for(var i=0;i0?(lineParts.splice(j,1),j--):sessionDescription.sdp.match(new RegExp("a=rtpmap:"+lineParts[j]+" "+codec+"/.*\r\n","gi"))&&(line+=lineParts[j]+" ",lineParts.splice(j,1),j--);return line+=lineParts.join(" ")+"\r\n",sessionDescription.sdp=sessionDescription.sdp.replace(mLine[0],line),!0}};if(samplingRate){if("audio"===type&&channels&&setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/"+samplingRate+(1===channels?"[/1]*":"/"+channels)+"\r\n","gi")),!0,!0))return;if(setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/"+samplingRate+"[/]*.*\r\n","gi")),!0))return}"audio"===type&&channels&&setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/.*/"+channels+"\r\n","gi")),!1,!0)||setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/.*\r\n","gi")))};return parseFn("audio",overrideSettings?overrideSettings.audio:self._initOptions.audioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._initOptions.videoCodec),sessionDescription.sdp},Skylink.prototype._removeSDPFirefoxH264Pref=function(targetMid,sessionDescription){return log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing Firefox experimental H264 flag to ensure interopability reliability"]),sessionDescription.sdp.replace(/a=fmtp:0 profile-level-id=0x42e00c;packetization-mode=1\r\n/g,"")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var mediaLines=(sessionDescription.sdp.split("\r\n"),sessionDescription.sdp.split("m=")),formatRtx=function(str){return(str.match(/a=rtpmap:.*\ rtx\/.*\r\n/gi)||[]).forEach(function(line){var payload=(line.split("a=rtpmap:")[1]||"").split(" ")[0]||"",fmtpLine=(str.match(new RegExp("a=fmtp:"+payload+" .*\r\n","gi"))||[])[0];if(!fmtpLine)return void(str=str.replace(new RegExp(line,"g"),""));var codecPayload=(fmtpLine.split(" apt=")[1]||"").replace(/\r\n/gi,"");str.match(new RegExp("a=rtpmap:"+codecPayload+" .*\r\n","gi"))||(str=str.replace(new RegExp(line,"g"),""),str=str.replace(new RegExp(fmtpLine,"g"),""))}),str},formatFmtpRtcpFb=function(str){return(str.match(/a=(fmtp|rtcp-fb):.*\ rtx\/.*\r\n/gi)||[]).forEach(function(line){var payload=(line.split("a="+(line.indexOf("rtcp")>0?"rtcp-fb":"fmtp"))[1]||"").split(" ")[0]||"";str.match(new RegExp("a=rtpmap:"+payload+" .*\r\n","gi"))||(str=str.replace(new RegExp(line,"g"),""))}),str},m=0;m0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._initOptions.disableVideoFecCodecs&&(this._hasMCU?log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "ulpfec" or "red" codecs as connected to MCU to prevent connectivity issues.']):(parseFn("video","red"),parseFn("video","ulpfec"))),this._initOptions.disableComfortNoiseCodec&&audioSettings&&"object"==typeof audioSettings&&audioSettings.stereo&&parseFn("audio","CN"),"edge"===window.webrtcDetectedBrowser&&"edge"!==(((this._peerInformations[targetMid]||{}).agent||{}).name||"unknown").name&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=rtcp-fb:.*\ x-message\ .*\r\n/gi,"")),sessionDescription.sdp},Skylink.prototype._removeSDPREMBPackets=function(targetMid,sessionDescription){return this._initOptions.disableREMB?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing REMB packets."]),sessionDescription.sdp.replace(/a=rtcp-fb:\d+ goog-remb\r\n/g,"")):sessionDescription.sdp},Skylink.prototype._getSDPSelectedCodec=function(targetMid,sessionDescription,type,beSilentOnLogs){var codecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index&&0===mediaItem.indexOf(type+" ")){var codecs=(mediaItem.split("\r\n")[0]||"").split(" ");codecs.splice(0,3);for(var i=0;i-1)){codecInfo.name=parts[0],codecInfo.clockRate=parseInt(parts[1],10)||0,codecInfo.channels=parseInt(parts[2]||"1",10)||1,codecInfo.payloadType=parseInt(codecs[i],10),codecInfo.params="";(mediaItem.match(new RegExp("a=fmtp:"+codecs[i]+".*\r\n","gi"))||[]).forEach(function(paramItem){codecInfo.params+=paramItem.replace(new RegExp("a=fmtp:"+codecs[i],"gi"),"").replace(/\ /g,"").replace(/\r\n/g,"")});break}}}}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,'Parsing session description "'+type+'" codecs ->'],codecInfo),codecInfo):codecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._initOptions.forceTURN&&this._hasMCU?(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not filtering ICE candidates as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured"]),sessionDescription.sdp):(this._initOptions.filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._initOptions.filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._initOptions.filterCandidatesType.relay&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "relay" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*relay.*\r\n/g,"")),sessionDescription.sdp)},Skylink.prototype._getCodecsSupport=function(callback){var self=this;if(self._currentCodecSupport)return void callback(null);if(self._currentCodecSupport={audio:{},video:{}},"AppleWebKit"===AdapterJS.webrtcDetectedType)return self._currentCodecSupport.audio={opus:["48000/2"]},self._currentCodecSupport.video={h264:["48000"]},callback(null);try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints="plugin"!==AdapterJS.webrtcDetectedType?{offerToReceiveAudio:!0,offerToReceiveVideo:!0}:{mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}};try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){self._currentCodecSupport=self._getSDPCodecsSupport(null,offer),callback(null)},function(error){callback(error)},offerConstraints)}}catch(error){callback(error)}},Skylink.prototype._handleSDPConnectionSettings=function(targetMid,sessionDescription,direction){var self=this;if(!self._sdpSessions[targetMid])return sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;"remote"!==direction||self.getPeerInfo(targetMid).config.enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",mediaType=(self._peerInformations[targetMid],""),bundleLineIndex=-1,bundleLineMids=[],mLineIndex=-1,settings=clone(self._sdpSettings);if("MCU"===targetMid&&(settings.connection.audio=!0,settings.connection.video=!0,settings.connection.data=!0),self._hasMCU){var peerStreamSettings=clone(self.getPeerInfo(targetMid)).settings||{};settings.direction.audio.receive="MCU"!==targetMid&&!!peerStreamSettings.audio,settings.direction.audio.send="MCU"===targetMid,settings.direction.video.receive="MCU"!==targetMid&&!!peerStreamSettings.video,settings.direction.video.send="MCU"===targetMid}if("remote"===direction){var offerCodecs=self._getSDPCommonSupports(targetMid,sessionDescription);offerCodecs.audio||(settings.connection.audio=!1),offerCodecs.video||(settings.connection.video=!1)}self._sdpSessions[targetMid][direction].mLines=[],self._sdpSessions[targetMid][direction].bundleLine="",self._sdpSessions[targetMid][direction].connection={audio:null,video:null,data:null};for(var i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");else if(mediaType&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){if(-1===["audio","video"].indexOf(mediaType)){self._sdpSessions[targetMid][direction].connection.data=sdpLines[i];continue}if("local"===direction)settings.direction[mediaType].send&&!settings.direction[mediaType].receive?sdpLines[i]=sdpLines[i].indexOf("send")>-1?"a=sendonly":"a=inactive":!settings.direction[mediaType].send&&settings.direction[mediaType].receive?sdpLines[i]=sdpLines[i].indexOf("recv")>-1?"a=recvonly":"a=inactive":settings.direction[mediaType].send||settings.direction[mediaType].receive||(sdpLines[i]="a=inactive"),self._hasMCU||"firefox"===window.webrtcDetectedBrowser||"firefox"!==peerAgent||sessionDescription.type!==self.HANDSHAKE_PROGRESS.OFFER||"a=recvonly"!==sdpLines[i]||(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Overriding any original settings to receive only to send and receive to resolve chrome BUNDLE errors."]),sdpLines[i]="a=sendrecv",settings.direction[mediaType].send=!0,settings.direction[mediaType].receive=!0);else if(sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER){var localOfferRes=self._sdpSessions[targetMid].local.connection[mediaType];"a=sendonly"===localOfferRes?sdpLines[i]=-1===["a=inactive","a=recvonly"].indexOf(sdpLines[i])?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=-1===["a=inactive","a=sendonly"].indexOf(sdpLines[i])?"a=recvonly"===sdpLines[i]?"a=inactive":"a=sendonly":sdpLines[i]:"a=inactive"===localOfferRes&&(sdpLines[i]="a=inactive")}self._sdpSessions[targetMid][direction].connection[mediaType]=sdpLines[i]}}else sdpLines.splice(i,1),i--;(sdpLines[i]||"").replace(/\n|\r|\s|\ /gi,"")||(sdpLines.splice(i,1),i--)}return bundleLineIndex>-1&&(self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE?sdpLines[bundleLineIndex]="a=group:BUNDLE "+bundleLineMids.join(" "):self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.NONE&&sdpLines.splice(bundleLineIndex,1)),"edge"!==window.webrtcDetectedBrowser&&(sdpLines[sdpLines.length-1].replace(/\n|\r|\s/gi,"")?sdpLines.push(""):sdpLines[sdpLines.length-1]=""),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Handling connection lines and direction ->"],settings),sdpLines.join("\r\n")},Skylink.prototype._getSDPFingerprint=function(targetMid,sessionDescription,beSilentOnLogs){var fingerprint={fingerprint:null,fingerprintAlgorithm:null,derBase64:null};if(!sessionDescription||!sessionDescription.sdp)return fingerprint;for(var sdpLines=sessionDescription.sdp.split("\r\n"),i=0;i"],fingerprint),fingerprint},Skylink.prototype._renderSDPOutput=function(targetMid,sessionDescription){var self=this,localStream=null,localStreamId=null;if(sessionDescription&&sessionDescription.sdp){if(!self._peerConnections[targetMid])return sessionDescription.sdp;self._peerConnections[targetMid].localStream&&(localStream=self._peerConnections[targetMid].localStream,localStreamId=self._peerConnections[targetMid].localStreamId||self._peerConnections[targetMid].localStream.id);var sdpLines=(self._initOptions.enableIceTrickle?sessionDescription.sdp:sessionDescription.sdp.replace(/a=end-of-candidates\r\n/g,"")).split("\r\n");self._peerInformations[targetMid];if(localStream)for(var mediaType="",i=0;i0?ssrcParts=sdpLines[i].split(" msid:"):sdpLines[i].indexOf(" mslabel:")>0&&(ssrcParts=sdpLines[i].split(" mslabel:")),ssrcParts){var ssrcMsidParts=(ssrcParts[1]||"").split(" ");ssrcMsidParts[0]=localStreamId,ssrcParts[1]=ssrcMsidParts.join(" "),sdpLines[i].indexOf(" msid:")>0?sdpLines[i]=ssrcParts.join(" msid:"):sdpLines[i].indexOf(" mslabel:")>0&&(sdpLines[i]=ssrcParts.join(" mslabel:"))}}if(!self._initOptions.enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var e=0;e"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),log.info([targetMid,"RTCSessionDescription",sessionDescription.type,"Formatted output ->"],sdpLines.join("\r\n")),sdpLines.join("\r\n")}},Skylink.prototype._parseSDPMediaStreamIDs=function(targetMid,sessionDescription){if(this._peerConnections[targetMid]){if(!sessionDescription||!sessionDescription.sdp)return void(this._peerConnections[targetMid].remoteStreamId=null);for(var sdpLines=sessionDescription.sdp.split("\r\n"),currentStreamId=null,i=0;i0){currentStreamId=(sdpLines[i].split(" msid:")[1]||"").split(" ")[0];break}}currentStreamId?currentStreamId!==this._peerConnections[targetMid].remoteStreamId?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"New remote stream is sent ->"],currentStreamId),this._peerConnections[targetMid].remoteStreamId=currentStreamId):log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Same remote stream is sent ->"],currentStreamId):(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"No remote stream is sent."]),this._peerConnections[targetMid].remoteStreamId=null)}},Skylink.prototype._getSDPICECandidates=function(targetMid,sessionDescription,beSilentOnLogs){var candidates={host:[],srflx:[],relay:[]};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index){var sdpMid=((mediaItem.match(/a=mid:.*\r\n/gi)||[])[0]||"").replace(/a=mid:/gi,"").replace(/\r\n/,""),sdpMLineIndex=index-1;(mediaItem.match(/a=candidate:.*\r\n/gi)||[]).forEach(function(item){var canType=(item.split(" ")[7]||"host").replace(/\r\n/g,"");candidates[canType]=candidates[canType]||[],candidates[canType].push(new RTCIceCandidate({sdpMid:sdpMid,sdpMLineIndex:sdpMLineIndex,candidate:(item.split("a=")[1]||"").replace(/\r\n/g,"")}))})}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,"Parsing session description ICE candidates ->"],candidates),candidates):candidates},Skylink.prototype._getSDPMediaSSRC=function(targetMid,sessionDescription,beSilentOnLogs){var ssrcs={audio:0,video:0};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index){var mediaType=mediaItem.split(" ")[0]||"",ssrcLine=(mediaItem.match(/a=ssrc:.*\r\n/)||[])[0];"number"==typeof ssrcs[mediaType]&&ssrcLine&&(ssrcs[mediaType]=parseInt((ssrcLine.split("a=ssrc:")[1]||"").split(" ")[0],10)||0)}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,"Parsing session description media SSRCs ->"],ssrcs),ssrcs):ssrcs},Skylink.prototype._getSDPCodecsSupport=function(targetMid,sessionDescription){var codecs={audio:{},video:{}};if(!sessionDescription||!sessionDescription.sdp)return codecs;for(var sdpLines=sessionDescription.sdp.split("\r\n"),mediaType="",i=0;i-1)continue;codecs[mediaType][codec]=codecs[mediaType][codec]||[],-1===codecs[mediaType][codec].indexOf(info)&&codecs[mediaType][codec].push(info)}}else mediaType=(sdpLines[i].split("m=")[1]||"").split(" ")[0];return log.info([targetMid||null,"RTCSessionDescription",sessionDescription.type,"Parsed codecs support ->"],codecs),codecs},Skylink.prototype._getSDPCommonSupports=function(targetMid,sessionDescription){var self=this,offer={audio:!1,video:!1};if(!targetMid||!sessionDescription||!sessionDescription.sdp){if(offer.video=!(!self._currentCodecSupport.video.h264&&!self._currentCodecSupport.video.vp8),offer.audio=!!self._currentCodecSupport.audio.opus,targetMid){var peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"";AdapterJS.webrtcDetectedBrowser===peerAgent&&(offer.video=Object.keys(self._currentCodecSupport.video).length>0,offer.audio=Object.keys(self._currentCodecSupport.audio).length>0)}return offer}var remoteCodecs=self._getSDPCodecsSupport(targetMid,sessionDescription),localCodecs=self._currentCodecSupport;for(var ac in localCodecs.audio)if(localCodecs.audio.hasOwnProperty(ac)&&localCodecs.audio[ac]&&remoteCodecs.audio[ac]){offer.audio=!0;break}for(var vc in localCodecs.video)if(localCodecs.video.hasOwnProperty(vc)&&localCodecs.video[vc]&&remoteCodecs.video[vc]){offer.video=!0;break}return offer},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this);
\ No newline at end of file
diff --git a/publish/skylink.debug.js b/publish/skylink.debug.js
index 75aad2d88..7a701c82a 100644
--- a/publish/skylink.debug.js
+++ b/publish/skylink.debug.js
@@ -1,4 +1,4 @@
-/*! skylinkjs - v0.6.29 - Tue Feb 06 2018 18:44:39 GMT+0800 (+08) */
+/*! skylinkjs - v0.6.30 - Wed Feb 21 2018 17:48:18 GMT+0800 (+08) */
(function(globals) {
@@ -1602,7 +1602,7 @@ Skylink.prototype.SYSTEM_ACTION_REASON = {
* @for Skylink
* @since 0.1.0
*/
-Skylink.prototype.VERSION = '0.6.29';
+Skylink.prototype.VERSION = '0.6.30';
/**
* The list of init() method ready states.
@@ -2471,6 +2471,54 @@ Skylink.prototype._createDataChannel = function(peerId, dataChannel, bufferThres
}
};
+/**
+ * Function that refreshes the main messaging Datachannel.
+ * @method refreshDatachannel
+ * @param {String} [peerId] The target Peer ID to retrieve connection stats from.
+ * @example
+ * // Example 1: Retrieve offerer and refresh datachannel:
+ * skylink.on("dataChannelState", function (state, peerId, error, channelName, channelType) {
+ * if (channelType === skylink.DATA_CHANNEL_TYPE.MESSAGING &&
+ * state === skylink.DATA_CHANNEL_STATE.CLOSED) {
+ * var userWeight = skylink.getPeerInfo().config.priorityWeight;
+ * var peerWeight = skylink.getPeerInfo(peerId).config.priorityWeight;
+ * // Determine who is offerer because as per SM protocol, higher weight is offerer
+ * if (userWeight > peerWeight) {
+ * skylink.refreshDatachannel(peerId);
+ * }
+ * }
+ * });
+ * @for Skylink
+ * @since 0.6.30
+ */
+
+Skylink.prototype.refreshDatachannel = function (peerId) {
+
+ var self = this;
+ if(self._dataChannels[peerId] && self._dataChannels[peerId]["main"] && self._dataChannels[peerId].main.channel) {
+ var channelName = self._dataChannels[peerId].main.channelName;
+ var channelType = self._dataChannels[peerId].main.channelType;
+ var channelProp = 'main';
+ var bufferThreshold= self._dataChannels[peerId].main.channel.bufferedAmountLowThreshold || 0;
+
+ if (channelType === self.DATA_CHANNEL_TYPE.MESSAGING) {
+ setTimeout(function () {
+ if (self._peerConnections[peerId] &&
+ self._peerConnections[peerId].signalingState !== self.PEER_CONNECTION_STATE.CLOSED &&
+ (self._peerConnections[peerId].localDescription &&
+ self._peerConnections[peerId].localDescription.type === self.HANDSHAKE_PROGRESS.OFFER)) {
+ self._closeDataChannel(peerId, 'main', true);
+ log.debug([peerId, 'RTCDataChannel', channelProp, 'Reviving Datachannel connection']);
+ self._createDataChannel(peerId, channelName, bufferThreshold, true);
+ }
+ }, 100);
+ }
+ }
+ else {
+ log.debug([peerId, 'RTCDataChannel', 'Not a valid Datachannel connection']);
+ }
+};
+
/**
* Function that returns the Datachannel buffer threshold and amount.
* @method _getDataChannelBuffer
@@ -2587,7 +2635,7 @@ Skylink.prototype._sendMessageToDataChannel = function(peerId, data, channelProp
* @for Skylink
* @since 0.1.0
*/
-Skylink.prototype._closeDataChannel = function(peerId, channelProp) {
+Skylink.prototype._closeDataChannel = function(peerId, channelProp, isCloseMainChannel) {
var self = this;
if (!self._dataChannels[peerId]) {
@@ -2612,7 +2660,11 @@ Skylink.prototype._closeDataChannel = function(peerId, channelProp) {
}
};
- if (!channelProp || channelProp === 'main') {
+ if(isCloseMainChannel)
+ {
+ closeFn(channelProp);
+ }
+ else if (!channelProp || channelProp === 'main') {
for (var channelNameProp in self._dataChannels) {
if (self._dataChannels[peerId].hasOwnProperty(channelNameProp)) {
if (self._dataChannels[peerId][channelNameProp]) {
@@ -2620,6 +2672,9 @@ Skylink.prototype._closeDataChannel = function(peerId, channelProp) {
}
}
}
+
+ delete self._dataChannels[peerId];
+
} else {
if (!self._dataChannels[peerId][channelProp]) {
log.warn([peerId, 'RTCDataChannel', channelProp, 'Aborting closing Datachannel as it does not exists']);
@@ -7826,8 +7881,11 @@ Skylink.prototype._signalingEndOfCandidates = function(targetMid) {
return;
}
+ if (
+ // If peer connection exists first and state is not closed.
+ self._peerConnections[targetMid] && self._peerConnections[targetMid].signalingState !== self.PEER_CONNECTION_STATE.CLOSED &&
// If remote description is set
- if (self._peerConnections[targetMid].remoteDescription && self._peerConnections[targetMid].remoteDescription.sdp &&
+ self._peerConnections[targetMid].remoteDescription && self._peerConnections[targetMid].remoteDescription.sdp &&
// If end-of-candidates signal is received
typeof self._peerEndOfCandidatesCounter[targetMid].expectedLen === 'number' &&
// If all ICE candidates are received
@@ -8796,6 +8854,10 @@ Skylink.prototype._setLocalAndSendMessage = function(targetMid, _sessionDescript
sessionDescription.sdp = self._handleSDPConnectionSettings(targetMid, sessionDescription, 'local');
sessionDescription.sdp = self._removeSDPREMBPackets(targetMid, sessionDescription);
+ if (self._peerConnectionConfig.disableBundle) {
+ sessionDescription.sdp = sessionDescription.sdp.replace(/a=group:BUNDLE.*\r\n/gi, '');
+ }
+
log.log([targetMid, 'RTCSessionDescription', sessionDescription.type,
'Local session description updated ->'], sessionDescription.sdp);
@@ -9329,7 +9391,8 @@ Skylink.prototype._waitForOpenChannel = function(mediaOptions, joinRoomTimestamp
bundlePolicy: self.BUNDLE_POLICY.BALANCED,
rtcpMuxPolicy: self.RTCP_MUX_POLICY.REQUIRE,
iceCandidatePoolSize: 0,
- certificate: self.PEER_CERTIFICATE.AUTO
+ certificate: self.PEER_CERTIFICATE.AUTO,
+ disableBundle: false
};
self._bandwidthAdjuster = null;
@@ -9429,6 +9492,7 @@ Skylink.prototype._waitForOpenChannel = function(mediaOptions, joinRoomTimestamp
}
}
}
+ self._peerConnectionConfig.disableBundle = mediaOptions.peerConnection.disableBundle === true;
}
if (mediaOptions.autoBandwidthAdjustment) {
diff --git a/publish/skylink.min.js b/publish/skylink.min.js
index ac4f1bbde..db22bcead 100644
--- a/publish/skylink.min.js
+++ b/publish/skylink.min.js
@@ -1,12 +1,12 @@
-/*! skylinkjs - v0.6.29 - 2018-02-06 */
-!function(globals){"use strict";function Skylink(){this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._peerInformations={},this._user=null,this._userData="",this._peerPriorityWeight=0,this._autoIntroduce=!0,this._isPrivileged=!1,this._peerList=null,this._selectedRoom=null,this._roomLocked=!1,this._inRoom=!1,this._EVENTS={},this._onceEvents={},this._timestamp={socketMessage:null,shareScreen:null,refreshConnection:null,getUserMedia:null,lastRestart:null},this._socketSession={},this._socketMessageQueue=[],this._socketMessageTimeout=null,this._socketPorts={"http:":[80,3e3],"https:":[443,3443]},this._channelOpen=!1,this._signalingServer=null,this._signalingServerProtocol=window.location.protocol,this._signalingServerPort=null,this._socket=null,this._socketUseXDR=!1,this._enableIceRestart=!1,this._hasMCU=!1,this._path=null,this._readyState=null,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._streams={userMedia:null,screenshare:null},this._streamsDefaultSettings={userMedia:{audio:{stereo:!1},video:{resolution:{width:640,height:480},frameRate:50}},screenshare:{video:!0}},this._streamsMutedSettings={audioMuted:!1,videoMuted:!1},this._streamsBandwidthSettings={googleX:{},bAS:{}},this._streamsStoppedCbs={},this._streamsSession={},this._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},this._publishOnly=!1,this._parentId=null,this._recordings={},this._currentRecordingId=!1,this._recordingStartInterval=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType=this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._bandwidthAdjuster=null,this._peerConnStatus={},this._joinRoomManager={timestamp:0,socketsFn:[]},this._initOptions={}}!function(){Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,r=!{toString:null}.propertyIsEnumerable("toString"),e=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],o=e.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var c=[];for(var l in n)t.call(n,l)&&c.push(l);if(r)for(var p=0;o>p;p++)t.call(n,e[p])&&c.push(e[p]);return c}}())}(),function(){function t(t){return 10>t?"0"+t:t}Date.prototype.toISOString=function(){return this.getUTCFullYear()+"-"+t(this.getUTCMonth()+1)+"-"+t(this.getUTCDate())+"T"+t(this.getUTCHours())+":"+t(this.getUTCMinutes())+":"+t(this.getUTCSeconds())+"."+(this.getUTCMilliseconds()/1e3).toFixed(3).slice(2,5)+"Z"}}(),function(){"function"!=typeof Date.now&&(Date.now=function(){return(new Date).getTime()})}(),function(e,t){function n(e){var n=t[e];t[e]=function(e){return o(n(e))}}function a(t,n,a){return(a=this).attachEvent("on"+t,function(t){var t=t||e.event;t.preventDefault=t.preventDefault||function(){t.returnValue=!1},t.stopPropagation=t.stopPropagation||function(){t.cancelBubble=!0},n.call(a,t)})}function o(e,t){if(t=e.length)for(;t--;)e[t].addEventListener=a;else e.addEventListener=a;return e}e.addEventListener||(o([t,e]),"Element"in e?e.Element.prototype.addEventListener=a:(t.attachEvent("onreadystatechange",function(){o(t.all)}),n("getElementsByTagName"),n("getElementById"),n("createElement"),o(t.all)))}(window,document),function(){if("performance"in window==0&&(window.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in window.performance==0){var a=Date.now();performance.timing&&performance.timing.navigationStart&&(a=performance.timing.navigationStart),window.performance.now=function(){return Date.now()-a}}}(),window.BlobBuilder=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,Array.prototype.forEach||(Array.prototype.forEach=function(callback){var T,k;if(null==this)throw new TypeError("this is null or not defined");var O=Object(this),len=O.length>>>0;if("function"!=typeof callback)throw new TypeError(callback+" is not a function");for(arguments.length>1&&(T=arguments[1]),k=0;k"],error),void self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CREATE_ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))}self._dataChannels[peerId]?self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel.label===channelName&&(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING):(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING,self._dataChannels[peerId]={},log.debug([peerId,"RTCDataChannel",channelProp,"initializing main DataChannel"])),dataChannel.onerror=function(evt){var channelError=evt.error||evt;log.error([peerId,"RTCDataChannel",channelProp,"Datachannel has an exception ->"],channelError),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,channelError,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onbufferedamountlow=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel buffering data transfer low"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.BUFFERED_AMOUNT_LOW,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onmessage=function(event){self._processDataChannelData(event.data,peerId,channelName,channelType)};var onOpenHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has opened"]),dataChannel.bufferedAmountLowThreshold=bufferThreshold||0,self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.OPEN,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))};dataChannel.readyState===self.DATA_CHANNEL_STATE.OPEN?setTimeout(onOpenHandlerFn,1):(self._trigger("dataChannelState",dataChannel.readyState,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),dataChannel.onopen=onOpenHandlerFn);var onCloseHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has closed"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSED,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),self._peerConnections[peerId]&&self._peerConnections[peerId].remoteDescription&&self._peerConnections[peerId].remoteDescription.sdp&&(-1===self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")||self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application 0")>0)||channelType===self.DATA_CHANNEL_TYPE.MESSAGING&&setTimeout(function(){self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[peerId].localDescription&&self._peerConnections[peerId].localDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&(log.debug([peerId,"RTCDataChannel",channelProp,"Reviving Datachannel connection"]),self._createDataChannel(peerId,channelName,bufferThreshold,!0))},100)};if("firefox"===AdapterJS.webrtcDetectedBrowser){var hasTriggeredClose=!1,timeBlockAfterClosing=0;dataChannel.onclose=function(){hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())};var onFFClosed=setInterval(function(){dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSED||hasTriggeredClose||5===timeBlockAfterClosing?(clearInterval(onFFClosed),hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())):dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSING&&timeBlockAfterClosing++},1e3)}else dataChannel.onclose=onCloseHandlerFn;channelType===self.DATA_CHANNEL_TYPE.MESSAGING?self._dataChannels[peerId].main={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}:self._dataChannels[peerId][channelName]={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}},Skylink.prototype._getDataChannelBuffer=function(peerId,channelProp){if("object"==typeof peerId)return{bufferedAmountLow:"number"==typeof peerId.bufferedAmountLow?peerId.bufferedAmountLow:parseInt(peerId.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?peerId.bufferedAmountLowThreshold:parseInt(peerId.bufferedAmountLowThreshold,10)||0};if(!(this._dataChannels[peerId]&&this._dataChannels[peerId][channelProp]&&this._dataChannels[peerId][channelProp].channel))return{bufferedAmountLow:0,bufferedAmountLowThreshold:0};var channel=this._dataChannels[peerId][channelProp].channel;return{bufferedAmountLow:"number"==typeof channel.bufferedAmountLow?channel.bufferedAmountLow:parseInt(channel.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof channel.bufferedAmountLowThreshold?channel.bufferedAmountLowThreshold:parseInt(channel.bufferedAmountLowThreshold,10)||0}},Skylink.prototype._sendMessageToDataChannel=function(peerId,data,channelProp,doNotConvert){var self=this;if(channelProp&&channelProp!==peerId||(channelProp="main"),!("object"==typeof data&&data||data&&"string"==typeof data))return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping invalid data ->"],data);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Peer connection does not exists or is closed ->"],data);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Datachannel connection does not exists ->"],data);var channelName=self._dataChannels[peerId][channelProp].channelName,channelType=self._dataChannels[peerId][channelProp].channelType,readyState=self._dataChannels[peerId][channelProp].channel.readyState,messageType="object"==typeof data&&data.type===self._DC_PROTOCOL_TYPE.MESSAGE?self.DATA_CHANNEL_MESSAGE_ERROR.MESSAGE:self.DATA_CHANNEL_MESSAGE_ERROR.TRANSFER;if(readyState!==self.DATA_CHANNEL_STATE.OPEN){var notOpenError='Failed sending message as Datachannel connection state is not opened. Current readyState is "'+readyState+'"';throw log.error([peerId,"RTCDataChannel",channelProp,notOpenError+" ->"],data),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,new Error(notOpenError),channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),new Error(notOpenError)}try{doNotConvert||"object"!=typeof data?(log.debug([peerId,"RTCDataChannel",channelProp,"Sending data with size ->"],data.size||data.length||data.byteLength),self._dataChannels[peerId][channelProp].channel.send(data)):(log.debug([peerId,"RTCDataChannel",channelProp,'Sending "'+data.type+'" protocol message ->'],data),self._dataChannels[peerId][channelProp].channel.send(JSON.stringify(data)))}catch(error){throw log.error([peerId,"RTCDataChannel",channelProp,"Failed sending "+(doNotConvert||"object"!=typeof data?"data":'"'+data.type+'" protocol message')+" ->"],error),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,error,channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),error}},Skylink.prototype._closeDataChannel=function(peerId,channelProp){var self=this;if(!self._dataChannels[peerId])return void log.warn([peerId,"RTCDataChannel",channelProp||null,"Aborting closing Datachannels as Peer connection does not have Datachannel sessions"]);var closeFn=function(rChannelProp){var channelName=self._dataChannels[peerId][rChannelProp].channelName,channelType=self._dataChannels[peerId][rChannelProp].channelType;self._dataChannels[peerId][rChannelProp].readyState!==self.DATA_CHANNEL_STATE.CLOSED&&(log.debug([peerId,"RTCDataChannel",channelProp,"Closing Datachannel"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSING,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(peerId,rChannelProp)),self._dataChannels[peerId][rChannelProp].channel.close(),delete self._dataChannels[peerId][rChannelProp])};if(channelProp&&"main"!==channelProp){if(!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Aborting closing Datachannel as it does not exists"]);closeFn(channelProp)}else for(var channelNameProp in self._dataChannels)self._dataChannels[peerId].hasOwnProperty(channelNameProp)&&self._dataChannels[peerId][channelNameProp]&&closeFn(channelNameProp)},Skylink.prototype._base64ToBlob=function(dataURL){for(var byteString=atob(dataURL),ab=new ArrayBuffer(byteString.length),ia=new Uint8Array(ab),j=0;jchunkSize){for(;blobByteSize-1>endCount;)endCount=startCount+chunkSize,chunksArray.push(blob.slice(startCount,endCount)),startCount+=chunkSize;blobByteSize-(startCount+1)>0&&chunksArray.push(blob.slice(startCount,blobByteSize-1))}else chunksArray.push(blob);return chunksArray},Skylink.prototype._chunkDataURL=function(dataURL,chunkSize){var outputStr=dataURL,dataURLArray=[],startCount=0,endCount=0,dataByteSize=dataURL.size||dataURL.length;if(dataByteSize>chunkSize){for(;dataByteSize-1>endCount;)endCount=startCount+chunkSize,dataURLArray.push(outputStr.slice(startCount,endCount)),startCount+=chunkSize;dataByteSize-(startCount+1)>0&&chunksArray.push(outputStr.slice(startCount,dataByteSize-1))}else dataURLArray.push(outputStr);return dataURLArray},Skylink.prototype.sendBlobData=function(data,timeout,targetPeerId,sendChunksAsBinary,callback){this._startDataTransfer(data,timeout,targetPeerId,sendChunksAsBinary,callback,"blob")},Skylink.prototype.sendURLData=function(data,timeout,targetPeerId,callback){this._startDataTransfer(data,timeout,targetPeerId,callback,null,"data")},Skylink.prototype.respondBlobRequest=Skylink.prototype.acceptDataTransfer=function(peerId,transferId,accept){var self=this;if("string"!=typeof transferId&&"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as data transfer ID or peer ID is not provided"]);if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as Peer does not have any Datachannel connections"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as invalid transfer ID is provided"]);var channelProp="main",dataChannelStateCbFn=null;self._dataChannels[peerId][transferId]&&(channelProp=transferId),self.once("dataTransferState",function(){dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),delete self._dataTransfers[transferId],self._dataChannels[peerId]&&("main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),channelProp===transferId&&self._closeDataChannel(peerId,transferId))},function(state,evtTransferId,evtPeerId){return evtTransferId===transferId&&evtPeerId===peerId&&[self.DATA_TRANSFER_STATE.ERROR,self.DATA_TRANSFER_STATE.CANCEL,self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED,self.DATA_TRANSFER_STATE.USER_REJECTED].indexOf(state)>-1}),accept?(log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]),dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){log.error([peerId,"RTCDataChannel",channelProp,'Data transfer "'+transferId+'" has been terminated due to connection.']),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD,message:new Error("Data transfer terminated as Peer Datachannel connection closed abruptly.")})},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_STATE.MESSAGING:channelName===transferId)&&[self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED,self.DATA_CHANNEL_STATE.ERROR].indexOf(state)>-1:void self.off("dataChannelState",dataChannelStateCbFn)}),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:0},channelProp),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_STARTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)):(log.warn([peerId,"RTCDataChannel",transferId,"Rejected data transfer and data transfer request has been aborted"]),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:-1},channelProp),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_REJECTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as User has rejected data transfer request."),transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD}))},Skylink.prototype.cancelBlobTransfer=Skylink.prototype.cancelDataTransfer=function(peerId,transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer ID is not provided"]);if(!peerId||"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as peer ID is not provided"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer session does not exists."]);log.debug([peerId,"RTCDataChannel",transferId,"Canceling data transfer ..."]);var emitEventFn=function(peers,transferInfoPeerId){for(var i=0;i0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},"main"),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},transferId),emitEventFn(Object.keys(self._dataTransfers[transferId].peers.main).concat(Object.keys(self._dataTransfers[transferId].peers[transferId])))}else{var channelProp="main";if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as Peer does not have any Datachannel connections"]);self._dataChannels[peerId][transferId]&&(channelProp=transferId),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},channelProp),emitEventFn([peerId],peerId)}},Skylink.prototype.sendP2PMessage=function(message,targetPeerId){var listOfPeers=Object.keys(this._dataChannels),isPrivate=!1;if(Array.isArray(targetPeerId)?(listOfPeers=targetPeerId,isPrivate=!0):targetPeerId&&"string"==typeof targetPeerId&&(listOfPeers=[targetPeerId],isPrivate=!0),!this._inRoom||!this._user||!this._user.sid)return void log.error("Unable to send message as User is not in Room. ->",message);if(!this._initOptions.enableDataChannel)return void log.error("Unable to send message as User does not have Datachannel enabled. ->",message);for(var i=0;i-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeStreamingFn=function(error){log.error(error)};if(!this._inRoom||!this._user||!this._user.sid)return emitErrorBeforeStreamingFn("Unable to start data streaming as User is not in Room.");if(!this._initOptions.enableDataChannel)return emitErrorBeforeStreamingFn("Unable to start data streaming as User does not have Datachannel enabled.");if(0===listOfPeers.length)return emitErrorBeforeStreamingFn("Unable to start data streaming as there are no Peers to start session with.")
-;if(self._hasMCU)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature is current not supported by MCU yet.");if(!self._initOptions.enableSimultaneousTransfers)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature requires simultaneous data transfers to be enabled");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},listenToPeerFn=function(peerId,channelProp){var hasStarted=!1;sessions[peerId]=channelProp,self.once("dataStreamState",function(){},function(state,evtTransferId,evtPeerId,evtSessionInfo){if(evtTransferId===transferId&&evtPeerId===peerId){evtSessionInfo.chunk;return delete clone(evtSessionInfo).chunk,state===self.DATA_STREAM_STATE.SENDING_STARTED?void(hasStarted=!0):hasStarted&&[self.DATA_STREAM_STATE.ERROR,self.DATA_STREAM_STATE.SENDING_STOPPED].indexOf(state)>-1?(channelProp===transferId&&self._closeDataChannel(peerId,transferId),self._dataStreams[transferId]&&self._dataStreams[transferId].sessions[peerId]&&(delete self._dataStreams[transferId].sessions[peerId],0===Object.keys(self._dataStreams[transferId].sessions).length&&delete self._dataStreams[transferId]),!0):void 0}})},i=0;i-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE)};if(peersNonInterop.length>0)if(self._hasMCU)waitForChannelOpenFn("MCU",peersNonInterop);else for(var pni=0;pni0)if(self._hasMCU)startDataSessionFn("MCU","main",peersInterop);else for(var pi=0;piself._CHUNK_DATAURL_SIZE:updatedDataChunk.length>self._BINARY_FILE_SIZE)return void log.error("Failed streaming data chunk as data chunk exceeds maximum chunk limit.");var sessionInfo={chunk:updatedDataChunk,chunkSize:updatedDataChunk.size||updatedDataChunk.length||updatedDataChunk.byteLength,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){var onSendDataFn=function(buffer){self._sendMessageToDataChannel(peerId,buffer,channelProp,!0);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype.stopStreamingData=function(transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error("Failed streaming data chunk as stream session ID is not provided.");if(!(self._inRoom&&self._user&&self._user.sid))return void log.error("Failed streaming data chunk as User is not in the Room.");if(!self._dataStreams[transferId])return void log.error("Failed stopping data streaming session as it does not exists.");if(!self._dataStreams[transferId].isUpload)return void log.error("Failed stopping data streaming session as it is not sending.");if(self._hasMCU)return void log.error("Failed stopping data streaming session as MCU does not support this feature yet.");var sessionInfo={chunk:null,chunkSize:0,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:transferId,size:0,originalSize:0,dataType:"fastBinaryStop",mimeType:null,chunkType:self._dataStreams[transferId].sessionChunkType,chunkSize:0,timeout:0,isPrivate:self._dataStreams[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype._startDataTransfer=function(data,timeout,targetPeerId,sendChunksAsBinary,callback,sessionType){var self=this,transferId=(self._user?self._user.sid:"")+"_"+(new Date).getTime(),transferErrors={},transferCompleted=[],chunks=[],listOfPeers=Object.keys(self._peerConnections),sessionChunkType="string",transferInfo={name:null,size:null,chunkSize:null,chunkType:null,dataType:null,mimeType:null,direction:self.DATA_TRANSFER_TYPE.UPLOAD,timeout:60,isPrivate:!1,percentage:0};"number"==typeof timeout?transferInfo.timeout=timeout:Array.isArray(timeout)?listOfPeers=timeout:timeout&&"string"==typeof timeout?listOfPeers=[timeout]:timeout&&"boolean"==typeof timeout?sessionChunkType="binary":"function"==typeof timeout&&(callback=timeout),Array.isArray(targetPeerId)?listOfPeers=targetPeerId:targetPeerId&&"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:targetPeerId&&"boolean"==typeof targetPeerId?sessionChunkType="binary":"function"==typeof targetPeerId&&(callback=targetPeerId),sendChunksAsBinary&&"boolean"==typeof sendChunksAsBinary?sessionChunkType="binary":"function"==typeof sendChunksAsBinary&&(callback=sendChunksAsBinary),listOfPeers.indexOf("MCU")>-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeDataTransferFn=function(error){if(log.error(error),"function"==typeof callback){var transferErrors={};if(0===listOfPeers.length)transferErrors.self=new Error(error);else for(var i=0;i0){var bsChunkSize="firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_CHUNK_FILE_SIZE:self._CHUNK_FILE_SIZE,bsChunks=self._chunkBlobData(new Blob(chunks),bsChunkSize);self._dataTransfers[transferId].enforceBSInfo={chunkSize:4*Math.ceil(bsChunkSize/3),chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,size:4*Math.ceil(transferInfo.originalSize/3),chunks:bsChunks}}}for(var completeFn=function(peerId,error){transferCompleted.indexOf(peerId)>-1||(log.debug([peerId,"RTCDataChannel",transferId,"Data transfer result. Is errors present? ->"],error),transferCompleted.push(peerId),error&&(transferErrors[peerId]=new Error(error)),listOfPeers.length===transferCompleted.length&&(log.log([null,"RTCDataChannel",transferId,"Data transfer request completed"]),"function"==typeof callback&&(Object.keys(transferErrors).length>0?callback({transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),transferErrors:transferErrors,listOfPeers:listOfPeers},null):callback(null,{transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),listOfPeers:listOfPeers}))))},i=0;i0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,"main",Object.keys(self._dataTransfers[transferId].peers.main)),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,transferId,Object.keys(self._dataTransfers[transferId].peers[transferId])))},Skylink.prototype._startDataTransferToPeer=function(transferId,peerId,callback,channelProp,targetPeers){var self=this,peerConnectionStateCbFn=null,dataChannelStateCbFn=null,emitEventFn=function(cb){for(var peers=targetPeers||[peerId],i=0;i-1&&(log.warn([peerId,"RTCDataChannel",transferId,"Binary data chunks transfer is not yet supported with Peer connecting from Android, iOS and C++ SDK. Fallbacking to binary string data chunks transfer."]),size=self._dataTransfers[transferId].enforceBSInfo.size,chunkSize=self._dataTransfers[transferId].enforceBSInfo.chunkSize,chunkType="string"),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:self._dataTransfers[transferId].name,size:size,originalSize:self._dataTransfers[transferId].originalSize,dataType:self._dataTransfers[transferId].sessionType,mimeType:self._dataTransfers[transferId].mimeType,chunkType:chunkType,chunkSize:chunkSize,timeout:self._dataTransfers[transferId].timeout,isPrivate:self._dataTransfers[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp),emitEventFn(function(evtPeerId){self._trigger("incomingDataRequest",transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_UPLOAD_REQUEST,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)})};if("MCU"!==peerId){var dataTransferStateCbFn=function(state,evtTransferId,evtPeerId,transferInfo,error){peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],callback(peerId,state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?null:error.message.message||error.message.toString()),delete self._dataTransfers[transferId].sessions[peerId],self._hasMCU&&0===Object.keys(self._dataTransfers[transferId].peers.main).length&&self._dataChannels.MCU&&self._dataChannels.MCU.main?self._dataChannels.MCU.main.transferId=null:"main"===channelProp&&self._dataChannels[peerId]&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),0===Object.keys(self._dataTransfers[transferId].sessions).length&&delete self._dataTransfers[transferId]};self.once("dataTransferState",dataTransferStateCbFn,function(state,evtTransferId,evtPeerId){return self._dataTransfers[transferId]&&(self._hasMCU?self._dataTransfers[transferId].peers.main[peerId]||self._dataTransfers[transferId].peers[transferId][peerId]:self._dataTransfers[transferId].sessions[peerId])?evtTransferId===transferId&&evtPeerId===peerId&&[self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,self.DATA_TRANSFER_STATE.ERROR,self.DATA_TRANSFER_STATE.CANCEL,self.DATA_TRANSFER_STATE.REJECTED].indexOf(state)>-1:(dataTransferStateCbFn&&self.off("dataTransferState",dataTransferStateCbFn),peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),void(dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn)))})}if(!self._peerConnections[peerId])return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer connection does not exists.");if(!self._peerInformations[peerId])return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer connection does not exists.");if(self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer connection is not stable.");if(!self._dataTransfers[transferId])return void returnErrorBeforeTransferFn("Unable to start data transfer as data transfer session is not in order.");if(!self._dataChannels[peerId]||!self._dataChannels[peerId].main)return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel connection does not exists.");if(self._dataChannels[peerId].main.channel.readyState!==self.DATA_CHANNEL_STATE.OPEN)return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel connection is not opened.");var streamId=self._dataChannels[peerId].main.streamId;if(streamId&&"main"===channelProp&&self._dataStreams[streamId]&&("string"===self._dataStreams[streamId].sessionChunkType&&("string"===self._dataTransfers[transferId].sessionChunkType||self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1)||"binary"===self._dataStreams[streamId].sessionChunkType&&"binary"===self._dataStreams[streamId].sessionChunkType&&-1===self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)))return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel currently has an active "+self._dataStreams[streamId].sessionChunkType+" data streaming session.");var protocolVer=(self._peerInformations[peerId].agent||{}).DTProtocolVersion||"0.1.0",requireInterop=self._isLowerThanVersion(protocolVer,"0.1.2")||!self._initOptions.enableSimultaneousTransfers;return self._isLowerThanVersion(protocolVer,"0.1.2")&&"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer do not support DATA_URL type of data transfers"):"MCU"!==peerId&&self._hasMCU?(channelProp=requireInterop?"main":transferId,peerConnectionStateCbFn=function(){returnErrorBeforeTransferFn("Data transfer terminated as Peer connection is not stable.")},self.once("peerConnectionState",peerConnectionStateCbFn,function(state,evtPeerId){return self._dataTransfers[transferId]?state!==self.PEER_CONNECTION_STATE.STABLE&&evtPeerId===peerId:void self.off("peerConnectionState",peerConnectionStateCbFn)}),requireInterop):(requireInterop||"main"===channelProp)&&self._dataChannels[peerId].main.transferId?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel has a data transfer in-progress."):(self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0},dataChannelStateCbFn=function(state,evtPeerId,error){self._dataTransfers[transferId].sessions[peerId].ackN>=self._dataTransfers[transferId].chunks.length-1||returnErrorBeforeTransferFn(error?error.message||error.toString():"Data transfer terminated as Peer Datachannel connection closed abruptly.")},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void self.off("dataChannelState",dataChannelStateCbFn);if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId))return state===self.DATA_CHANNEL_STATE.OPEN&&"main"!==channelProp&&channelName===transferId?(self._dataChannels[peerId][channelProp].transferId=transferId,sendWRQFn(),!1):[self.DATA_CHANNEL_STATE.CREATE_ERROR,self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(channelProp="main",self._dataChannels[peerId].main.transferId=transferId,sendWRQFn()):(channelProp=transferId,self._createDataChannel(peerId,transferId,"data"===self._dataTransfers[transferId].sessionType?self._CHUNK_DATAURL_SIZE:"string"===self._dataTransfers[transferId].sessionChunkType?"firefox"===AdapterJS.webrtcDetectedBrowser?16384:65546:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE))))},Skylink.prototype._getTransferInfo=function(transferId,peerId,returnDataProp,hidePercentage,returnDataAtStart){if(!this._dataTransfers[transferId])return{};var transferInfo={name:this._dataTransfers[transferId].name,size:this._dataTransfers[transferId].size,dataType:this._dataTransfers[transferId].dataType||this.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:this._dataTransfers[transferId].mimeType||null,chunkSize:this._dataTransfers[transferId].chunkSize,chunkType:this._dataTransfers[transferId].chunkType,timeout:this._dataTransfers[transferId].timeout,isPrivate:this._dataTransfers[transferId].isPrivate,direction:this._dataTransfers[transferId].direction};if(this._dataTransfers[transferId].originalSize?transferInfo.size=this._dataTransfers[transferId].originalSize:this._dataTransfers[transferId].chunkType===this.DATA_TRANSFER_DATA_TYPE.BINARY_STRING&&(transferInfo.size=Math.ceil(3*transferInfo.size/4)),!hidePercentage){if(transferInfo.percentage=0,!this._dataTransfers[transferId].sessions[peerId])return returnDataProp&&(transferInfo.data=null),transferInfo;if(this._dataTransfers[transferId].direction===this.DATA_TRANSFER_TYPE.DOWNLOAD)this._dataTransfers[transferId].sessions[peerId].receivedSize===this._dataTransfers[transferId].sessions[peerId].size?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].receivedSize/this._dataTransfers[transferId].size*100).toFixed(2),10);else{var chunksLength=this._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?this._dataTransfers[transferId].enforceBSInfo.chunks.length:this._dataTransfers[transferId].chunks.length;this._dataTransfers[transferId].sessions[peerId].ackN===chunksLength?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].ackN/chunksLength*100).toFixed(2),10)}returnDataProp&&("number"!=typeof returnDataAtStart?100===transferInfo.percentage?transferInfo.data=this._getTransferData(transferId):transferInfo.data=null:(transferInfo.percentage=returnDataAtStart,0===returnDataAtStart&&(transferInfo.data=this._getTransferData(transferId))))}return transferInfo},Skylink.prototype._getTransferData=function(transferId){if(!this._dataTransfers[transferId])return null;if(this._dataTransfers[transferId].dataType===this.DATA_TRANSFER_SESSION_TYPE.BLOB){var mimeType={name:this._dataTransfers[transferId].name};return this._dataTransfers[transferId].mimeType&&(mimeType.type=this._dataTransfers[transferId].mimeType),new Blob(this._dataTransfers[transferId].chunks,mimeType)}return this._dataTransfers[transferId].chunks.join("")},Skylink.prototype._handleDataTransferTimeoutForPeer=function(transferId,peerId,setPeerTO){var self=this;if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer does not exists for Peer. Ignoring timeout."]);log.debug([peerId,"RTCDataChannel",transferId,"Clearing data transfer timer for Peer."]),
-self._dataTransfers[transferId].sessions[peerId].timer&&clearTimeout(self._dataTransfers[transferId].sessions[peerId].timer),self._dataTransfers[transferId].sessions[peerId].timer=null,setPeerTO&&(log.debug([peerId,"RTCDataChannel",transferId,"Setting data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer=setTimeout(function(){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer already ended for Peer. Ignoring expired timeout."]);if(!self._user||!self._user.sid)return void log.debug([peerId,"RTCDataChannel",transferId,"User is not in Room. Ignoring expired timeout."]);if(!self._dataChannels[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Datachannel connection does not exists. Ignoring expired timeout."]);log.error([peerId,"RTCDataChannel",transferId,"Data transfer response has timed out."]);var emitEventFn=function(cb){if("MCU"===peerId){for(var broadcastedPeers=[self._dataTransfers[transferId].peers.main,self._dataTransfers[transferId].peers[transferId]],i=0;i"],rawData);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping data received from Peer as Datachannel connection is not present ->"],rawData);if("string"==typeof rawData)try{var protocolData=JSON.parse(rawData);if(isStreamChunk=!1,log.debug([peerId,"RTCDataChannel",channelProp,'Received protocol "'+protocolData.type+'" message ->'],protocolData),[self._DC_PROTOCOL_TYPE.ACK,self._DC_PROTOCOL_TYPE.ERROR,self._DC_PROTOCOL_TYPE.CANCEL].indexOf(protocolData.type)>-1&&!(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded protocol message as data transfer session is not present ->"],protocolData);switch(protocolData.type){case self._DC_PROTOCOL_TYPE.WRQ:if(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId])return log.warn([peerId,"RTCDataChannel",channelProp,"Rejecting bidirectional data transfer request as it is currently not supported in the SDK ->"],protocolData),void self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,ackN:-1,sender:self._user.sid},channelProp);self._WRQProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ACK:self._ACKProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ERROR:self._ERRORProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.CANCEL:self._CANCELProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.MESSAGE:self._MESSAGEProtocolHandler(peerId,protocolData,channelProp);break;default:log.warn([peerId,"RTCDataChannel",channelProp,'Discarded unknown "'+protocolData.type+'" message ->'],protocolData)}}catch(error){if(rawData.indexOf("{")>-1&&rawData.indexOf("}")>0)throw log.error([peerId,"RTCDataChannel",channelProp,"Failed parsing protocol step data error ->"],{data:rawData,error:error}),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(peerId,channelProp)),error;if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING;if(isStreamChunk||self._dataTransfers[transferId].dataType===self.DATA_TRANSFER_SESSION_TYPE.DATA_URL)log.debug([peerId,"RTCDataChannel",channelProp,"Received string data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.length||rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.STRING,rawData.length||rawData.size||0,channelProp);else{var removeSpaceData=rawData.replace(/\s|\r|\n/g,"");log.debug([peerId,"RTCDataChannel",channelProp,"Received binary string data chunk @"+self._dataTransfers[transferId].sessions[peerId].ackN+" with size ->"],removeSpaceData.length||removeSpaceData.size),self._DATAProtocolHandler(peerId,self._base64ToBlob(removeSpaceData),self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,removeSpaceData.length||removeSpaceData.size||0,channelProp)}}else{if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);if(rawData instanceof Blob)log.debug([peerId,"RTCDataChannel",channelProp,"Received blob data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.BLOB,rawData.size,channelProp);else{var byteArray=rawData,blob=null;if(rawData.constructor&&"Array"===rawData.constructor.name&&(byteArray=new Int8Array(rawData)),"IE"===AdapterJS.webrtcDetectedBrowser){if(window.BlobBuilder){var bb=new BlobBuilder;bb.append(rawData.constructor&&"ArrayBuffer"===rawData.constructor.name?byteArray:new Uint8Array(byteArray).buffer),blob=bb.getBlob()}}else blob=new Blob([byteArray]);log.debug([peerId,"RTCDataChannel",channelProp,"Received arraybuffer data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],blob.size),self._DATAProtocolHandler(peerId,blob,self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,blob.size,channelProp)}}},Skylink.prototype._WRQProtocolHandler=function(peerId,data,channelProp){var self=this,transferId="main"===channelProp?data.transferId||null:channelProp,senderPeerId=data.sender||peerId;if(["fastBinaryStart","fastBinaryStop"].indexOf(data.dataType)>-1)if("fastBinaryStart"===data.dataType){transferId||(transferId="stream_"+peerId+"_"+(new Date).getTime()),self._dataStreams[transferId]={chunkSize:0,chunkType:"string"===data.chunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:data.chunkType,isPrivate:!!data.isPrivate,isStringStream:"string"===data.chunkType,senderPeerId:senderPeerId,isUpload:!1},self._dataChannels[peerId][channelProp].streamId=transferId;self.once("dataChannelState",function(){},function(state,evtPeerId,channelName,channelType,error){if(!self._dataStreams[transferId])return!0;if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId&&channelType===self.DATA_CHANNEL_TYPE.DATA)&&[self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');return self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},updatedError),!0}}),self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STARTED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStarted",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1)}else transferId=self._dataChannels[peerId][channelProp].streamId,self._dataStreams[transferId]&&!self._dataStreams[transferId].isUpload&&(self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STOPPED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStopped",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1),self._dataChannels[peerId][channelProp].streamId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp),delete self._dataStreams[transferId]);else transferId||(transferId="transfer_"+peerId+"_"+(new Date).getTime()),self._dataTransfers[transferId]={name:data.name||transferId,size:data.size||0,chunkSize:data.chunkSize,originalSize:data.originalSize||0,timeout:data.timeout||60,isPrivate:!!data.isPrivate,senderPeerId:data.sender||peerId,dataType:self.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:data.mimeType||null,chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,direction:self.DATA_TRANSFER_TYPE.DOWNLOAD,chunks:[],sessions:{},sessionType:data.dataType||"blob",sessionChunkType:data.chunkType||"string"},"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?(self._dataTransfers[transferId].dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,self._dataTransfers[transferId].chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING):"blob"===self._dataTransfers[transferId].sessionType&&"binary"===self._dataTransfers[transferId].sessionChunkType&&(self._dataTransfers[transferId].chunkType=self._binaryChunkType),self._dataChannels[peerId][channelProp].transferId=transferId,self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0,receivedSize:0},self._trigger("incomingDataRequest",transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!1),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_REQUEST,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)},Skylink.prototype._ACKProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ACK event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};if(data.ackN>-1){if(0===data.ackN)emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_STARTED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,0),null)});else if(self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?data.ackN===self._dataTransfers[transferId].enforceBSInfo.chunks.length:data.ackN===self._dataTransfers[transferId].chunks.length)return self._dataTransfers[transferId].sessions[peerId].ackN=data.ackN,emitEventFn(function(evtPeerId){self._trigger("incomingData",self._getTransferData(transferId),transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,100),null)}),void(self._dataChannels[peerId][channelProp]&&(self._dataChannels[peerId][channelProp].transferId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp)));var uploadFn=function(chunk){self._sendMessageToDataChannel(peerId,chunk,channelProp,!0),data.ackN-1?self._blobToBase64(self._dataTransfers[transferId].enforceBSInfo.chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING?self._blobToBase64(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER?self._blobToArrayBuffer(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):uploadFn(self._dataTransfers[transferId].chunks[data.ackN])}else self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.REJECTED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as Peer has rejected data transfer request"),transferType:self.DATA_TRANSFER_TYPE.UPLOAD})},Skylink.prototype._MESSAGEProtocolHandler=function(peerId,data,channelProp){var senderPeerId=data.sender||peerId;log.log([senderPeerId,"RTCDataChannel",channelProp,"Received P2P message from peer:"],data),this._trigger("incomingMessage",{content:data.data,isPrivate:data.isPrivate,isDataChannel:!0,targetPeerId:this._user.sid,senderPeerId:senderPeerId},senderPeerId,this.getPeerInfo(senderPeerId),!1)},Skylink.prototype._ERRORProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ERROR event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,evtPeerId,self._getTransferInfo(transferId,peerID,!0,!1,!1),{message:new Error(data.content),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._CANCELProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of CANCEL event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(peerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.CANCEL,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error(data.content||"Peer has terminated data transfer."),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._DATAProtocolHandler=function(peerId,chunk,chunkType,chunkSize,channelProp){var self=this,transferId=channelProp,senderPeerId=peerId;if(self._dataChannels[peerId]&&self._dataChannels[peerId][channelProp]){var streamId=self._dataChannels[peerId][channelProp].streamId;if(streamId&&self._dataStreams[streamId]&&("string"==typeof chunk&&"string"===self._dataStreams[streamId].sessionChunkType||chunk instanceof Blob&&"binary"===self._dataStreams[streamId].sessionChunkType))return senderPeerId=self._dataStreams[streamId].senderPeerId||peerId,self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVED,streamId,senderPeerId,{chunk:chunk,chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},null),void self._trigger("incomingDataStream",chunk,transferId,senderPeerId,{chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},!1);if("main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._dataTransfers[transferId].senderPeerId&&(senderPeerId=self._dataTransfers[transferId].senderPeerId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1),self._dataTransfers[transferId].chunkType=chunkType,self._dataTransfers[transferId].sessions[peerId].receivedSize+=chunkSize,self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN]=chunk,self._dataTransfers[transferId].sessions[peerId].receivedSize>=self._dataTransfers[transferId].size)return log.log([peerId,"RTCDataChannel",channelProp,"Data transfer has been completed. Computed size ->"],self._dataTransfers[transferId].sessions[peerId].receivedSize),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN+1},channelProp),self._trigger("incomingData",self._getTransferData(transferId),transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),null),void self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null);self._dataTransfers[transferId].sessions[peerId].ackN+=1,self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN},channelProp),self._handleDataTransferTimeoutForPeer(transferId,peerId,!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOADING,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)}},Skylink.prototype._onIceCandidate=function(targetMid,candidate){var self=this,pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCIceCandidate",null,"Ignoring of ICE candidate event as Peer connection does not exists ->"],candidate);if(candidate.candidate){pc.gathering||(log.log([targetMid,"RTCIceCandidate",null,"ICE gathering has started."]),pc.gathering=!0,pc.gathered=!1,self._trigger("candidateGenerationState",self.CANDIDATE_GENERATION_STATE.GATHERING,targetMid));var candidateType=candidate.candidate.split(" ")[7];if(log.debug([targetMid,"RTCIceCandidate",candidateType,"Generated ICE candidate ->"],candidate),"endOfCandidates"===candidateType||!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].localDescription&&self._peerConnections[targetMid].localDescription.sdp&&self._peerConnections[targetMid].localDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return void log.warn([targetMid,"RTCIceCandidate",candidateType,"Dropping of sending ICE candidate end-of-candidates signal or unused ICE candidates to prevent errors ->"],candidate);if(self._initOptions.filterCandidatesType[candidateType]){if(!self._hasMCU||!self._initOptions.forceTURN)return void log.warn([targetMid,"RTCIceCandidate",candidateType,"Dropping of sending ICE candidate as it matches ICE candidate filtering flag ->"],candidate);log.warn([targetMid,"RTCIceCandidate",candidateType,"Not dropping of sending ICE candidate as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured ->"],candidate)}if(self._gatheredCandidates[targetMid]||(self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),self._gatheredCandidates[targetMid].sending[candidateType].push({sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate}),!self._initOptions.enableIceTrickle)return void log.warn([targetMid,"RTCIceCandidate",candidateType,"Dropping of sending ICE candidate as trickle ICE is disabled ->"],candidate);log.debug([targetMid,"RTCIceCandidate",candidateType,"Sending ICE candidate ->"],candidate),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.CANDIDATE,label:candidate.sdpMLineIndex,id:candidate.sdpMid,candidate:candidate.candidate,mid:self._user.sid,target:targetMid,rid:self._room.id})}else{if(log.log([targetMid,"RTCIceCandidate",null,"ICE gathering has completed."]),pc.gathered)return;if(pc.gathering=!1,pc.gathered=!0,self._trigger("candidateGenerationState",self.CANDIDATE_GENERATION_STATE.COMPLETED,targetMid),self._initOptions.enableIceTrickle)self._gatheredCandidates[targetMid]&&self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.END_OF_CANDIDATES,noOfExpectedCandidates:self._gatheredCandidates[targetMid].sending.srflx.length+self._gatheredCandidates[targetMid].sending.host.length+self._gatheredCandidates[targetMid].sending.relay.length,mid:self._user.sid,target:targetMid,rid:self._room.id});else{var sessionDescription=self._peerConnections[targetMid].localDescription;if(!(sessionDescription&&sessionDescription.type&&sessionDescription.sdp))return void log.warn([targetMid,"RTCSessionDescription",null,"Not sending any session description after ICE gathering completed as it is not present."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,userInfo:self._getUserInfo(targetMid),target:targetMid,rid:self._room.id})}}},Skylink.prototype._addIceCandidateToQueue=function(targetMid,canId,candidate){var candidateType=candidate.candidate.split(" ")[7];log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Buffering ICE candidate."]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.BUFFERED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[],this._peerCandidatesQueue[targetMid].push([canId,candidate])},Skylink.prototype._addIceCandidateFromQueue=function(targetMid){this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[];for(var i=0;i"],error),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},error)};if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Adding ICE candidate."]),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESSING,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[targetMid].remoteDescription&&self._peerConnections[targetMid].remoteDescription.sdp&&self._peerConnections[targetMid].remoteDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),void self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed."));try{self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)}catch(error){onErrorCbFn(error)}},Skylink.prototype._setIceServers=function(passedIceServers){var self=this,iceServerName=null,iceServerProtocol="stun",iceServerPorts={udp:[3478,19302,19303,19304],tcp:[80,443],both:[19305,19306,19307,19308]},iceServers=[{urls:[]},{urls:[]}];return passedIceServers.forEach(function(server){if(0===server.url.indexOf("stun:"))server.url.indexOf("temasys")>0?iceServerName=(server.url.split(":")[1]||"").split("?")[0]||null:iceServers[0].urls.push(server.url);else if(0===server.url.indexOf("turn:")&&server.url.indexOf("@")>0&&server.credential&&!iceServers[1].username&&!iceServers[1].credential){var parts=server.url.split(":"),urlParts=(parts[1]||"").split("@");iceServerName=(urlParts[1]||"").split("?")[0],iceServers[1].username=urlParts[0],iceServers[1].credential=server.credential,iceServerProtocol="turn"}}),self._initOptions.iceServer?iceServers=[{urls:self._initOptions.iceServer.urls,username:iceServers[1].username||null,credential:iceServers[1].credential||null}]:(iceServerName=iceServerName||"turn.temasys.io","turn"!==iceServerProtocol||self._initOptions.enableTURNServer||self._initOptions.forceTURNSSL?"edge"===AdapterJS.webrtcDetectedBrowser?(iceServerPorts.udp=[3478],iceServerPorts.tcp=[],iceServerPorts.both=[],iceServerProtocol="turn"):self._initOptions.forceTURNSSL?"firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion<53?(iceServerPorts.udp=[],iceServerPorts.tcp=[443],iceServerPorts.both=[],iceServerProtocol="turn"):(iceServerPorts.udp=[],iceServerProtocol="turns"):"firefox"===AdapterJS.webrtcDetectedBrowser&&(iceServerPorts.udp=[3478],iceServerPorts.tcp=[443,80]):iceServerProtocol="stun",self._initOptions.TURNServerTransport!==self.TURN_TRANSPORT.UDP||self._initOptions.forceTURNSSL?self._initOptions.TURNServerTransport===self.TURN_TRANSPORT.TCP?(iceServerPorts.tcp=iceServerPorts.tcp.concat(iceServerPorts.both),iceServerPorts.udp=[],iceServerPorts.both=[]):self._initOptions.TURNServerTransport===self.TURN_TRANSPORT.NONE&&(iceServerPorts.tcp=[],iceServerPorts.udp=[]):(iceServerPorts.udp=iceServerPorts.udp.concat(iceServerPorts.both),iceServerPorts.tcp=[],iceServerPorts.both=[]),"stun"===iceServerProtocol&&(iceServerPorts.tcp=[]),"stun"!==iceServerProtocol||self._initOptions.enableSTUNServer?(iceServerPorts.tcp.forEach(function(tcpPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+tcpPort+"?transport=tcp")}),iceServerPorts.udp.forEach(function(udpPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+udpPort+"?transport=udp")}),iceServerPorts.both.forEach(function(bothPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+bothPort)}),self._initOptions.usePublicSTUN||iceServers.splice(0,1)):iceServers=[]),log.log("Output iceServers configuration:",iceServers),{iceServers:iceServers}},Skylink.prototype.refreshConnection=function(targetPeerId,iceRestart,options,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),doIceRestart=!1,bwOptions={};Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:"boolean"==typeof targetPeerId?doIceRestart=targetPeerId:targetPeerId&&"object"==typeof targetPeerId?bwOptions=targetPeerId:"function"==typeof targetPeerId&&(callback=targetPeerId),"boolean"==typeof iceRestart?doIceRestart=iceRestart:iceRestart&&"object"==typeof iceRestart?bwOptions=iceRestart:"function"==typeof iceRestart&&(callback=iceRestart),options&&"object"==typeof options?bwOptions=options:"function"==typeof options&&(callback=options);var emitErrorForPeersFn=function(error){if(log.error(error),"function"==typeof callback){var listOfPeerErrors={};if(0===listOfPeers.length)listOfPeerErrors.self=new Error(error);else for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}},refreshSinglePeer=function(peerId,peerCallback){if(!self._peerConnections[peerId])return error="There is currently no existing peer connection made with the peer. Unable to restart connection",log.error([peerId,null,null,error]),void peerCallback(error);log.log([peerId,"PeerConnection",null,"Restarting peer connection"]),self._restartPeerConnection(peerId,doIceRestart,bwOptions,peerCallback)};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?refreshSinglePeer(peerId,refreshSinglePeerCallback(peerId)):(error="Peer connection with peer does not exists. Unable to restart",log.error([peerId,"PeerConnection",null,error]),refreshSinglePeerCallback(peerId)(error))}}},Skylink.prototype.getConnectionStatus=function(targetPeerId,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),listOfPeerStats={},listOfPeerErrors={};if(Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId&&targetPeerId?listOfPeers=[targetPeerId]:"function"==typeof targetPeerId&&(callback=targetPeerId,targetPeerId=void 0),0===listOfPeers.length)return listOfPeerErrors.self=new Error("There is currently no peer connections to retrieve connection status"),log.error([null,"RTCStatsReport",null,"Retrieving request failure ->"],listOfPeerErrors.self),void("function"==typeof callback&&callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null));"edge"===AdapterJS.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){-1===completedTaskCounter.indexOf(peerId)&&completedTaskCounter.push(peerId),completedTaskCounter.length===listOfPeers.length&&"function"==typeof callback&&(Object.keys(listOfPeerErrors).length>0?callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null):callback(null,{listOfPeers:listOfPeers,connectionStats:listOfPeerStats}))},statsFn=function(peerId){var retrieveFn=function(firstRetrieval,nextCb){return function(err,result){if(err)return log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],error),listOfPeerErrors[peerId]=error,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,error),checkCompletedFn(peerId),void(firstRetrieval&&delete self._peerStats[peerId]);firstRetrieval?nextCb():(listOfPeerStats[peerId]=result,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_SUCCESS,peerId,listOfPeerStats[peerId],null),checkCompletedFn(peerId))}};if(!self._peerStats[peerId])return self._peerStats[peerId]={},log.debug([peerId,"RTCStatsReport",null,"Retrieving first report to tabulate results"]),void self._retrieveStats(peerId,retrieveFn(!0,function(){self._retrieveStats(peerId,retrieveFn())}),!0);self._retrieveStats(peerId,retrieveFn())},i=0;i"],listOfPeerErrors[peerId]),self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,listOfPeerErrors[peerId]),checkCompletedFn(peerId))}},Skylink.prototype._retrieveStats=function(peerId,callback,beSilentOnLogs,isAutoBwStats){var self=this,pc=self._peerConnections[peerId],output={raw:{},connection:{},audio:{sending:{},receiving:{}},video:{sending:{},receiving:{}},selectedCandidate:{local:{},remote:{},consentResponses:{},consentRequests:{},responses:{},requests:{}},certificate:{}};if(!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));if(!pc)return callback(new Error("Peer connection is not initialised"));"edge"!==AdapterJS.webrtcDetectedBrowser&&"AppleWebKit"!==AdapterJS.webrtcDetectedType||log.warn("Current connection stats may not be complete as it is in beta"),output.connection.iceConnectionState=pc.iceConnectionState,output.connection.iceGatheringState=pc.iceGatheringState,output.connection.signalingState=pc.signalingState,output.connection.remoteDescription={type:pc.remoteDescription&&pc.remoteDescription.type||"",sdp:pc.remoteDescription&&pc.remoteDescription.sdp||""},output.connection.localDescription={type:pc.localDescription&&pc.localDescription.type||"",sdp:pc.localDescription&&pc.localDescription.sdp||""},output.connection.candidates={sending:self._getSDPICECandidates(peerId,pc.localDescription,beSilentOnLogs),receiving:self._getSDPICECandidates(peerId,pc.remoteDescription,beSilentOnLogs)},output.connection.dataChannels={},output.connection.constraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,output.connection.optional=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,output.connection.sdpConstraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null,output.audio.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),output.video.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),output.audio.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"audio",beSilentOnLogs),output.video.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"video",beSilentOnLogs),output.certificate.local=self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),output.certificate.remote=self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs);var inboundSSRCs=self._getSDPMediaSSRC(peerId,pc.remoteDescription,beSilentOnLogs);output.audio.receiving.ssrc=inboundSSRCs.audio,output.video.receiving.ssrc=inboundSSRCs.video;var outboundSSRCs=self._getSDPMediaSSRC(peerId,pc.localDescription,beSilentOnLogs);output.audio.sending.ssrc=outboundSSRCs.audio,output.video.sending.ssrc=outboundSSRCs.video,Object.keys(self._dataChannels[peerId]||{}).forEach(function(prop){var channel=self._dataChannels[peerId][prop];output.connection.dataChannels[channel.channel.label]={label:channel.channel.label,readyState:channel.channel.readyState,channelType:self.DATA_CHANNEL_TYPE["main"===prop?"MESSAGING":"DATA"],currentTransferId:channel.transferId||null,currentStreamId:channel.streamId||null}});var certificateFn=function(item,prop){if(0===prop.indexOf("RTCCertificate_"))item.fingerprint===output.certificate.local.fingerprint?(output.certificate.local.derBase64=item.base64Certificate,output.certificate.local.fingerprintAlgorithm=item.fingerprintAlgorithm):item.fingerprint===output.certificate.remote.fingerprint&&(output.certificate.remote.derBase64=item.base64Certificate,output.certificate.remote.fingerprintAlgorithm=item.fingerprintAlgorithm);else if(0===prop.indexOf("ssrc_")&&item.transportId){var pairItem=output.raw[item.transportId]||{};output.certificate.srtpCipher=pairItem.srtpCipher,output.certificate.dtlsCipher=pairItem.dtlsCipher;var localCertItem=output.raw[pairItem.localCertificateId||""]||{};output.certificate.local.fingerprint=localCertItem.googFingerprint,output.certificate.local.fingerprintAlgorithm=localCertItem.googFingerprintAlgorithm,output.certificate.local.derBase64=localCertItem.googDerBase64;var remoteCertItem=output.raw[pairItem.remoteCertificateId||""]||{};output.certificate.remote.fingerprint=remoteCertItem.googFingerprint,output.certificate.remote.fingerprintAlgorithm=remoteCertItem.googFingerprintAlgorithm,output.certificate.remote.derBase64=remoteCertItem.googDerBase64}},candidatePairFn=function(item,prop){if(0===prop.indexOf("RTCIceCandidatePair_")){if("succeeded"!==item.state||output.selectedCandidate.nominated||item.prioirty<(output.selectedCandidate.priority||0))return;for(var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],sending=pc.localDescription&&pc.localDescription.sdp&&pc.localDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],receiving=pc.remoteDescription&&pc.remoteDescription&&pc.remoteDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],computePrioirtyFn=function(controller,controlled){return Math.pow(2,32)*Math.min(controller,controlled)+2*Math.max(controller,controlled)+(controller>controlled?1:0)},computeCanTypeFn=function(type){return"relay"===type?"relayed":"host"===type?"local":"srflx"===type?"serverreflexive":type},s=0;s0?"sending":"receiving";item.codecImplementationName="unknown"===item.codecImplementationName?null:item.codecImplementationName,output[item.mediaType][direction].codec.implementation=item.codecImplementationName||null,item.googCodecName="unknown"===item.googCodecName?null:item.googCodecName,output[item.mediaType][direction].codec.name=item.googCodecName||output[item.mediaType][direction].codec.name}},audioStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPAudioStream")){if(output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.audio.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),"function"!=typeof pc.getReceivers)return}else if(0===prop.indexOf("RTCMediaStreamTrack_remote_audio_"))output.audio.receiving.audioOutputLevel=item.audioLevel;else if(0===prop.indexOf("RTCOutboundRTPAudioStream"))output.audio.sending.targetBitrate=item.targetBitrate||0,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"audio"===item.mediaType&&item.isRemote)output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"audio"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"audio"===item.mediaType)if(prop.indexOf("_recv")>0){output.audio.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.audio.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.audio.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.audio.receiving.totalBytes=bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.audio.receiving.totalPackets=packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.audio.receiving.totalPacketsLost=packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost")}else{output.audio.sending.rtt=parseInt(item.googRtt||"0",10),output.audio.sending.audioInputLevel=parseInt(item.audioInputLevel||"0",10),output.audio.sending.echoReturnLoss=parseInt(item.googEchoCancellationReturnLoss||"0",10),output.audio.sending.echoReturnLossEnhancement=parseInt(item.googEchoCancellationReturnLossEnhancement||"0",10);var bytesSent=parseInt(item.bytesSent||"0",10);output.audio.sending.totalBytes=bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.audio.sending.totalPackets=packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent")}else if(0===prop.indexOf("inbound_rtp_audio"))output.audio.receiving.jitter=item.jitter||0,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if(0===prop.indexOf("outbound_rtp_audio")){output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.audio.sending.rtt=rtcpItem.roundTripTime||0}}else{output.audio.sending.targetBitrate=item.targetBitrate,output.audio.sending.rtt=item.roundTripTime,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.audio.sending.audioInputLevel=trackItem.audioLevel,output.audio.sending.echoReturnLoss=trackItem.echoReturnLoss,output.audio.sending.echoReturnLossEnhancement=trackItem.echoReturnLossEnhancement}},videoStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPVideoStream"))output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.framesDecoded=item.framesDecoded,output.video.receiving.qpSum=item.qpSum,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.video.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if(0===prop.indexOf("RTCMediaStreamTrack_remote_video_"))output.video.receiving.frameHeight=item.frameHeight,output.video.receiving.frameWidth=item.frameWidth,output.video.receiving.framesCorrupted=item.framesCorrupted,output.video.receiving.framesPerSecond=item.framesPerSecond,output.video.receiving.framesDropped=item.framesDropped,output.video.receiving.totalFrames=item.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,item,"framesReceived");else if(0===prop.indexOf("RTCOutboundRTPVideoStream"))output.video.sending.qpSum=item.qpSum,output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"video"===item.mediaType&&item.isRemote){output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.receiving.framesCorrupted=trackItem.framesCorrupted,output.video.receiving.framesDropped=trackItem.framesDropped,output.video.receiving.framesDecoded=trackItem.framesDecoded,output.video.receiving.totalFrames=trackItem.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,trackItem,"framesReceived")}else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"video"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType)if(prop.indexOf("_recv")>0){output.video.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.video.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.video.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10),output.video.receiving.renderDelayMs=parseInt(item.googRenderDelayMs||"0",10),output.video.receiving.frameWidth=parseInt(item.googFrameWidthReceived||"0",10),output.video.receiving.frameHeight=parseInt(item.googFrameHeightReceived||"0",10),output.video.receiving.framesDecoded=parseInt(item.framesDecoded||"0",10),output.video.receiving.frameRateOutput=parseInt(item.googFrameRateOutput||"0",10),output.video.receiving.frameRateDecoded=parseInt(item.googFrameRateDecoded||"0",10),output.video.receiving.frameRateReceived=parseInt(item.googFrameRateReceived||"0",10),output.video.receiving.qpSum=parseInt(item.qpSum||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.video.receiving.totalBytes=bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.video.receiving.totalPackets=packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.video.receiving.totalPacketsLost=packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost");var nacksSent=parseInt(item.googNacksSent||"0",10);output.video.receiving.totalNacks=nacksSent,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"googNacksSent");var plisSent=parseInt(item.googPlisSent||"0",10);output.video.receiving.totalPlis=plisSent,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"googPlisSent");var firsSent=parseInt(item.googFirsSent||"0",10);output.video.receiving.totalFirs=firsSent,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"googFirsSent")}else{output.video.sending.rtt=parseInt(item.googRtt||"0",10),output.video.sending.frameWidth=parseInt(item.googFrameWidthSent||"0",10),output.video.sending.frameHeight=parseInt(item.googFrameHeightSent||"0",10),output.video.sending.framesEncoded=parseInt(item.framesEncoded||"0",10),output.video.sending.frameRateInput=parseInt(item.googFrameRateInput||"0",10),output.video.sending.frameRateEncoded=parseInt(item.googFrameRateEncoded||"0",10),output.video.sending.frameRateSent=parseInt(item.googFrameRateSent||"0",10),output.video.sending.cpuLimitedResolution="true"===item.googCpuLimitedResolution,output.video.sending.bandwidthLimitedResolution="true"===item.googBandwidthLimitedResolution;var bytesSent=parseInt(item.bytesSent||"0",10);output.video.sending.totalBytes=bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.video.sending.totalPackets=packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent");var nacksReceived=parseInt(item.googNacksReceived||"0",10);output.video.sending.totalNacks=nacksReceived,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"googNacksReceived");var plisReceived=parseInt(item.googPlisReceived||"0",10);output.video.sending.totalPlis=plisReceived,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"googPlisReceived");var firsReceived=parseInt(item.googFirsReceived||"0",10);output.video.sending.totalFirs=firsReceived,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"googFirsReceived")}else if(0===prop.indexOf("inbound_rtp_video"))output.video.receiving.jitter=item.jitter||0,output.video.receiving.framesDecoded=item.framesDecoded||0,output.video.receiving.frameRateMean=item.framerateMean||0,output.video.receiving.frameRateStdDev=item.framerateStdDev||0,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,
-output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount");else if(0===prop.indexOf("outbound_rtp_video")){output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.frameRateMean=item.framerateMean||0,output.video.sending.frameRateStdDev=item.framerateStdDev||0,output.video.sending.framesDropped=item.droppedFrames||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.video.sending.rtt=rtcpItem.roundTripTime||0}}else{output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.roundTripTime=item.roundTripTime||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.sending.frameHeight=trackItem.frameHeight,output.video.sending.frameWidth=trackItem.frameWidth,output.video.sending.framesPerSecond=trackItem.framesPerSecond,output.video.sending.totalFrames=trackItem.framesSent,output.video.sending.frames=self._parseConnectionStats(prevStats,trackItem,"framesSent")}},videoE2EStatsFn=function(item,prop){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType){var captureStartNtpTimeMs=parseInt(item.googCaptureStartNtpTimeMs||"0",10),remoteStream=pc.getRemoteStreams()[0];if(!(captureStartNtpTimeMs>0&&prop.indexOf("_recv")>0&&remoteStream&&document&&"function"==typeof document.getElementsByTagName))return;try{var elements=document.getElementsByTagName("plugin"===AdapterJS.webrtcDetectedType?"object":"video");"plugin"!==AdapterJS.webrtcDetectedType&&0===elements.length&&(elements=document.getElementsByTagName("audio"));for(var e=0;e0))break;for(var ec=0;ec"],error)}}},successCbFn=function(stats){"function"==typeof stats.forEach?stats.forEach(function(item,prop){output.raw[prop]=item}):output.raw=stats;var edgeTracksKind={remote:{},local:{}};"edge"===AdapterJS.webrtcDetectedBrowser&&(pc.remoteStream&&pc.remoteStream.getTracks().forEach(function(track){edgeTracksKind.remote[track.id]=track.kind}),pc.localStream&&pc.localStream.getTracks().forEach(function(track){edgeTracksKind.local[track.id]=track.kind})),Object.keys(output.raw).forEach(function(prop){if(0!==prop.indexOf("ssrc_")||output.raw[prop].mediaType){if("edge"===AdapterJS.webrtcDetectedBrowser&&!output.raw[prop].mediaType&&["inboundrtp","outboundrtp"].indexOf(output.raw[prop].type)>-1){var trackItem=output.raw[output.raw[prop].mediaTrackId]||{};output.raw[prop].mediaType=edgeTracksKind[output.raw[prop].isRemote?"remote":"local"][trackItem.trackIdentifier]||""}}else output.raw[prop].mediaType=output.raw[prop].audioInputLevel||output.raw[prop].audioOutputLevel?"audio":"video";certificateFn(output.raw[prop],prop),candidatePairFn(output.raw[prop],prop),codecsFn(output.raw[prop],prop),audioStatsFn(output.raw[prop],prop),videoStatsFn(output.raw[prop],prop),videoE2EStatsFn(output.raw[prop],prop),isAutoBwStats&&!self._peerBandwidth[peerId][prop]?self._peerBandwidth[peerId][prop]=output.raw[prop]:isAutoBwStats||self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=output.raw[prop])}),output.audio.sending.bytes=output.audio.sending.bytes||0,output.audio.sending.packets=output.audio.sending.packets||0,output.audio.sending.totalBytes=output.audio.sending.totalBytes||0,output.audio.sending.totalPackets=output.audio.sending.totalPackets||0,output.video.sending.bytes=output.video.sending.bytes||0,output.video.sending.packets=output.video.sending.packets||0,output.video.sending.totalBytes=output.video.sending.totalBytes||0,output.video.sending.totalPackets=output.video.sending.totalPackets||0,output.audio.receiving.bytes=output.audio.receiving.bytes||0,output.audio.receiving.packets=output.audio.receiving.packets||0,output.audio.receiving.totalBytes=output.audio.receiving.totalBytes||0,output.audio.receiving.totalPackets=output.audio.receiving.totalPackets||0,output.video.receiving.bytes=output.video.receiving.bytes||0,output.video.receiving.packets=output.video.receiving.packets||0,output.video.receiving.totalBytes=output.video.receiving.totalBytes||0,output.video.receiving.totalPackets=output.video.receiving.totalPackets||0,callback(null,output)},errorCbFn=function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)};if("function"!=typeof pc.getStats)return errorCbFn(new Error("getStats() API is not available."));"plugin"===AdapterJS.webrtcDetectedType?pc.getStats(null,successCbFn,errorCbFn):pc.getStats(null).then(successCbFn).catch(errorCbFn)},Skylink.prototype._addPeer=function(targetMid,cert,peerBrowser,receiveOnly,isSS){var self=this;return self._peerConnections[targetMid]?void log.error([targetMid,null,null,"Connection to peer has already been made"]):(self._peerConnStatus[targetMid]={connected:!1,init:!1},log.log([targetMid,null,null,"Starting the connection to peer. Options provided:"],{peerBrowser:peerBrowser,receiveOnly:receiveOnly,enableDataChannel:self._initOptions.enableDataChannel}),log.info("Adding peer",isSS),self._peerConnections[targetMid]=self._createPeerConnection(targetMid,!!isSS,cert),self._peerConnections[targetMid]?(self._peerConnStatus[targetMid].init=!0,void(self._peerConnections[targetMid].hasScreen=!!isSS)):void log.error([targetMid,null,null,"Failed creating the connection to peer."]))},Skylink.prototype._restartPeerConnection=function(peerId,doIceRestart,bwOptions,callback){var self=this;if(!self._peerConnections[peerId])return void log.error([peerId,null,null,"Peer does not have an existing connection. Unable to restart"]);var pc=self._peerConnections[peerId],agent=(self.getPeerInfo(peerId)||{}).agent||{};if(self._isLowerThanVersion(agent.SMProtocolVersion||"","0.1.2")){var notSupportedError=new Error("Failed restarting with other agents connecting from other SDKs as re-negotiation is not supported by other SDKs");return log.warn([peerId,"RTCPeerConnection",null,"Ignoring restart request as agent's SDK does not support it"],notSupportedError),void("function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(notSupportedError)))}if(pc.signalingState===self.PEER_CONNECTION_STATE.STABLE&&self._peerConnections[peerId]){log.log([peerId,null,null,"Sending restart message to signaling server ->"],{iceRestart:doIceRestart,options:bwOptions}),self._peerCustomConfigs[peerId]=self._peerCustomConfigs[peerId]||{},self._peerCustomConfigs[peerId].bandwidth=self._peerCustomConfigs[peerId].bandwidth||{},self._peerCustomConfigs[peerId].googleXBandwidth=self._peerCustomConfigs[peerId].googleXBandwidth||{},bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._peerCustomConfigs[peerId].bandwidth.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._peerCustomConfigs[peerId].bandwidth.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._peerCustomConfigs[peerId].bandwidth.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._peerCustomConfigs[peerId].googleXBandwidth.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._peerCustomConfigs[peerId].googleXBandwidth.max=bwOptions.googleXBandwidth.max));var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===doIceRestart&&self._enableIceRestart&&self._peerInformations[peerId]&&self._peerInformations[peerId].config.enableIceRestart,isRestartResend:!1,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._peerEndOfCandidatesCounter[peerId]=self._peerEndOfCandidatesCounter[peerId]||{},self._peerEndOfCandidatesCounter[peerId].len=0,self._sendChannelMessage(restartMsg),self._trigger("peerRestart",peerId,self.getPeerInfo(peerId),!0,!0===doIceRestart),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart callback"]),callback(null))}else if(pc.signalingState===self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER){var hasLocalDescription=pc.localDescription&&pc.localDescription.sdp;if(hasLocalDescription)self._sendChannelMessage({type:pc.localDescription.type,sdp:pc.localDescription.sdp,mid:self._user.sid,target:peerId,rid:self._room.id,restart:!0});else{var noLocalDescriptionError="Failed re-sending localDescription as there is no localDescription set to connection. There could be a handshaking step error";log.error([peerId,"RTCPeerConnection",null,noLocalDescriptionError],{localDescription:pc.localDescription,remoteDescription:pc.remoteDescription}),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(noLocalDescriptionError)))}}else{var unableToRestartError="Failed restarting as peer connection state is "+pc.signalingState;log.warn([peerId,"RTCPeerConnection",null,unableToRestartError]),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(unableToRestartError)))}},Skylink.prototype._removePeer=function(peerId){if(!this._peerConnections[peerId]&&!this._peerInformations[peerId])return void log.debug([peerId,"RTCPeerConnection",null,"Dropping the hangup from Peer as not connected to Peer at all."]);var peerInfo=clone(this.getPeerInfo(peerId))||{userData:"",settings:{audio:!1,video:!1,data:!1},mediaStatus:{audioMuted:!0,videoMuted:!0},agent:{name:"unknown",version:0,os:"",pluginVersion:null},config:{enableDataChannel:!0,enableIceRestart:!1,enableIceTrickle:!0,priorityWeight:0,publishOnly:!1,receiveOnly:!0},parentId:null,room:clone(this._selectedRoom)};"MCU"!==peerId?this._trigger("peerLeft",peerId,peerInfo,!1):(this._hasMCU=!1,log.log([peerId,null,null,"MCU has stopped listening and left"]),this._trigger("serverPeerLeft",peerId,this.SERVER_PEER_TYPE.MCU)),this._peerConnections[peerId]&&(this._peerConnections[peerId].signalingState!==this.PEER_CONNECTION_STATE.CLOSED&&(this._peerConnections[peerId].close(),"AppleWebKit"===AdapterJS.webrtcDetectedType&&(this._peerConnections[peerId].signalingStateClosed||(this._peerConnections[peerId].signalingStateClosed=!0,this._trigger("peerConnectionState",this.PEER_CONNECTION_STATE.CLOSED,peerId)),this._peerConnections[peerId].iceConnectionStateClosed||(this._peerConnections[peerId].iceConnectionStateClosed=!0,this._trigger("iceConnectionState",this.ICE_CONNECTION_STATE.CLOSED,peerId)))),"MCU"!==peerId&&this._handleEndedStreams(peerId),delete this._peerConnections[peerId]),this._peerInformations[peerId]&&delete this._peerInformations[peerId],this._peerMessagesStamps[peerId]&&delete this._peerMessagesStamps[peerId],this._streamsSession[peerId]&&delete this._streamsSession[peerId],this._peerEndOfCandidatesCounter[peerId]&&delete this._peerEndOfCandidatesCounter[peerId],this._peerCandidatesQueue[peerId]&&delete this._peerCandidatesQueue[peerId],this._sdpSessions[peerId]&&delete this._sdpSessions[peerId],this._peerStats[peerId]&&delete this._peerStats[peerId],this._peerBandwidth[peerId]&&delete this._peerBandwidth[peerId],this._gatheredCandidates[peerId]&&delete this._gatheredCandidates[peerId],this._peerCustomConfigs[peerId]&&delete this._peerCustomConfigs[peerId],this._peerConnStatus[peerId]&&delete this._peerConnStatus[peerId],this._dataChannels[peerId]&&this._closeDataChannel(peerId),log.log([peerId,"RTCPeerConnection",null,"Successfully removed peer"])},Skylink.prototype._createPeerConnection=function(targetMid,isScreenSharing,cert){var pc,self=this;if(self._inRoom&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)){var constraints={iceServers:self._room.connection.peerConfig.iceServers,iceTransportPolicy:self._initOptions.filterCandidatesType.host&&self._initOptions.filterCandidatesType.srflx&&!self._initOptions.filterCandidatesType.relay?"relay":"all",bundlePolicy:self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.NONE?self.BUNDLE_POLICY.BALANCED:self._peerConnectionConfig.bundlePolicy,rtcpMuxPolicy:self._peerConnectionConfig.rtcpMuxPolicy,iceCandidatePoolSize:self._peerConnectionConfig.iceCandidatePoolSize},optional={optional:[{DtlsSrtpKeyAgreement:!0},{googIPv6:!0}]};cert&&(constraints.certificates=[cert]),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].constraints=constraints,self._peerConnStatus[targetMid].optional=optional);try{log.debug([targetMid,"RTCPeerConnection",null,"Creating peer connection ->"],{constraints:constraints,optional:optional}),pc=new(self._initOptions.useEdgeWebRTC&&window.msRTCPeerConnection?window.msRTCPeerConnection:RTCPeerConnection)(constraints,optional)}catch(error){return log.error([targetMid,null,null,"Failed creating peer connection:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),null}pc.setOffer="",pc.setAnswer="",pc.hasStream=!1,pc.hasScreen=!!isScreenSharing,pc.hasMainChannel=!1,pc.firefoxStreamId="",pc.processingLocalSDP=!1,pc.processingRemoteSDP=!1,pc.gathered=!1,pc.gathering=!1,pc.localStream=null,pc.localStreamId=null,pc.remoteStream=null,pc.remoteStreamId=null,pc.iceConnectionStateClosed=!1,pc.signalingStateClosed=!1,self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}},self._streamsSession[targetMid]=self._streamsSession[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._sdpSessions[targetMid]={local:{},remote:{}},self._peerBandwidth[targetMid]={};var bandwidth=null;return pc.ondatachannel=function(event){var dc=event.channel||event;if(log.debug([targetMid,"RTCDataChannel",dc.label,"Received datachannel ->"],dc),self._initOptions.enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel){self.DATA_CHANNEL_TYPE.DATA,dc.label;pc.hasMainChannel||(self.DATA_CHANNEL_TYPE.MESSAGING,"main",pc.hasMainChannel=!0),self._createDataChannel(targetMid,dc)}else log.warn([targetMid,"RTCDataChannel",dc.label,"Not adding datachannel as enable datachannel is set to false"])},pc.onaddstream=function(evt){if(self._peerConnections[targetMid]){var stream=evt.stream||evt;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received empty remote stream ->"],stream);pc.remoteStream=stream,pc.remoteStreamId=pc.remoteStreamId||stream.id||stream.label;var peerSettings=clone(self.getPeerInfo(targetMid).settings);self._streamsSession[targetMid][pc.remoteStreamId]=peerSettings,0===stream.getAudioTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].audio=!1),0===stream.getVideoTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].video=!1),pc.hasStream=!0,pc.hasScreen=peerSettings.video&&"object"==typeof peerSettings.video&&peerSettings.video.screenshare,self._onRemoteStreamAdded(targetMid,stream,!!pc.hasScreen)}},pc.onicecandidate=function(event){self._onIceCandidate(targetMid,event.candidate||event)},pc.oniceconnectionstatechange=function(evt){var iceConnectionState=pc.iceConnectionState;if(log.debug([targetMid,"RTCIceConnectionState",null,"Ice connection state changed ->"],iceConnectionState),"edge"===AdapterJS.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),"AppleWebKit"===AdapterJS.webrtcDetectedType&&iceConnectionState===self.ICE_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.iceConnectionStateClosed||self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.CLOSED,targetMid)},10);if(self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._initOptions.enableIceTrickle&&self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.TRICKLE_FAILED,targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].connected=[self.ICE_CONNECTION_STATE.COMPLETED,self.ICE_CONNECTION_STATE.CONNECTED].indexOf(iceConnectionState)>-1),!self._hasMCU&&[self.ICE_CONNECTION_STATE.CONNECTED,self.ICE_CONNECTION_STATE.COMPLETED].indexOf(iceConnectionState)>-1&&self._bandwidthAdjuster&&!bandwidth&&"edge"!==AdapterJS.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),"AppleWebKit"===AdapterJS.webrtcDetectedType&&pc.signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.signalingStateClosed||self._trigger("peerConnectionState",self.PEER_CONNECTION_STATE.CLOSED,targetMid)},10);self._trigger("peerConnectionState",pc.signalingState,targetMid)},pc.onicegatheringstatechange=function(){log.log([targetMid,"RTCIceGatheringState",null,"Ice gathering state changed ->"],pc.iceGatheringState),self._trigger("candidateGenerationState",pc.iceGatheringState,targetMid)},"firefox"===AdapterJS.webrtcDetectedBrowser&&(pc.removeStream=function(stream){for(var senders=pc.getSenders(),s=0;s"],restartMsg),self._sendChannelMessage(restartMsg)};bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=bwOptions.googleXBandwidth.max));for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers},null):callback(null,{listOfPeers:listOfPeers}))};self.once("peerJoined",peerJoinedFn,function(peerId,peerInfo,isSelf){return isSelf}),self.leaveRoom(!1,function(error,success){if(error){if("function"==typeof callback){for(var i=0;i=self._peerEndOfCandidatesCounter[targetMid].expectedLen&&(!self._peerCandidatesQueue[targetMid]||0===self._peerCandidatesQueue[targetMid].length)&&!self._peerEndOfCandidatesCounter[targetMid].hasSet){log.debug([targetMid,"RTCPeerConnection",null,"Signaling of end-of-candidates remote ICE gathering."]),self._peerEndOfCandidatesCounter[targetMid].hasSet=!0;try{if("edge"===AdapterJS.webrtcDetectedBrowser){for(var mLineCounter=-1,addedMids=[],sdpLines=self._peerConnections[targetMid].remoteDescription.sdp.split("\r\n"),rejected=!1,i=0;i"],error)}}},Skylink.prototype.setUserData=function(userData){var self=this,updatedUserData="";void 0!==userData&&null!==userData&&(updatedUserData=userData),this._userData=updatedUserData,self._inRoom?(log.log("Updated userData -> ",updatedUserData),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.UPDATE_USER,mid:self._user.sid,rid:self._room.id,userData:updatedUserData,stamp:(new Date).getTime()}),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0)):log.warn("User is not in the room. Broadcast of updated information will be dropped")},Skylink.prototype.getUserData=function(peerId){if(peerId&&this._peerInformations[peerId]){var userData=this._peerInformations[peerId].userData;return null!==userData&&void 0===userData||(userData=""),userData}return this._userData},Skylink.prototype.getPeerInfo=function(peerId){var peerInfo=null;return"string"==typeof peerId&&"object"==typeof this._peerInformations[peerId]?(peerInfo=clone(this._peerInformations[peerId]),peerInfo.room=clone(this._selectedRoom),peerInfo.settings.bandwidth=peerInfo.settings.bandwidth||{},peerInfo.settings.googleXBandwidth=peerInfo.settings.googleXBandwidth||{},"boolean"==typeof peerInfo.settings.video||peerInfo.settings.video&&"object"==typeof peerInfo.settings.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"==typeof peerInfo.settings.audio||peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.audioMuted&&(peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.videoMuted&&(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.maxBandwidth&&(peerInfo.settings.bandwidth=clone(peerInfo.settings.maxBandwidth),delete peerInfo.settings.maxBandwidth),peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&peerInfo.settings.video.customSettings&&"object"==typeof peerInfo.settings.video.customSettings&&(peerInfo.settings.video.customSettings.frameRate&&(peerInfo.settings.video.frameRate=clone(peerInfo.settings.video.customSettings.frameRate)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode)),peerInfo.settings.video.customSettings.width&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.width=clone(peerInfo.settings.video.customSettings.width)),peerInfo.settings.video.customSettings.height&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.height=clone(peerInfo.settings.video.customSettings.height)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode))),peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&(peerInfo.settings.audio.stereo=!0===peerInfo.settings.audio.stereo),null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),peerInfo.parentId=peerInfo.parentId||null,"MCU"===peerId?(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1):this._hasMCU&&(peerInfo.config.receiveOnly=!1,peerInfo.config.publishOnly=!0),this._sdpSettings.direction.audio.receive||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.direction.video.receive||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),
-this._sdpSettings.connection.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.data=!!(this._dataChannels[peerId]&&this._dataChannels[peerId].main&&this._dataChannels[peerId].main.channel&&this._dataChannels[peerId].main.channel.readyState===this.DATA_CHANNEL_STATE.OPEN),peerInfo.connected=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].connected,peerInfo.init=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].init,this._sdpSessions[peerId]&&this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&"object"==typeof this._sdpSessions[peerId].remote.connection&&(this._sdpSessions[peerId].remote.connection.audio&&this._sdpSessions[peerId].remote.connection.audio.indexOf("send")>-1||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSessions[peerId].remote.connection.video&&this._sdpSessions[peerId].remote.connection.video.indexOf("send")>-1||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSessions[peerId].remote.connection.data&&this._sdpSessions[peerId].remote.connection.data.indexOf("send")>-1||(peerInfo.settings.data=!1))):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,os:window.navigator.platform,pluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:this.SMProtocolVersion,DTProtocolVersion:this.DTProtocolVersion},room:clone(this._selectedRoom),config:{enableDataChannel:this._initOptions.enableDataChannel,enableIceTrickle:this._initOptions.enableIceTrickle,enableIceRestart:this._enableIceRestart,priorityWeight:this._peerPriorityWeight,receiveOnly:!1,publishOnly:!!this._publishOnly},connected:null,init:null},null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),this._streams.screenshare?peerInfo.settings=clone(this._streams.screenshare.settings):this._streams.userMedia&&(peerInfo.settings=clone(this._streams.userMedia.settings)),peerInfo.settings.bandwidth=clone(this._streamsBandwidthSettings.bAS),peerInfo.settings.googleXBandwidth=clone(this._streamsBandwidthSettings.googleX),peerInfo.parentId=this._parentId?this._parentId:null,peerInfo.config.receiveOnly=!peerInfo.settings.video&&!peerInfo.settings.audio,peerInfo.settings.data=this._initOptions.enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._initOptions.codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._initOptions.codecParams.audio.opus.stereo),"boolean"==typeof this._initOptions.codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._initOptions.codecParams.audio.opus.usedtx),"number"==typeof this._initOptions.codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._initOptions.codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._initOptions.codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._initOptions.codecParams.audio.opus.useinbandfec))),peerInfo.settings.audio||(peerInfo.mediaStatus.audioMuted=!0),peerInfo.settings.video||(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.audio||peerInfo.settings.video||(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1),peerInfo},Skylink.prototype.getPeersInRoom=function(){for(var listOfPeersInfo={},listOfPeers=Object.keys(this._peerInformations),i=0;i-1||(customSettings.settings.audio=!1,customSettings.mediaStatus.audioMuted=!0),self._sdpSessions[usePeerId].local.connection.video&&self._sdpSessions[usePeerId].local.connection.video.indexOf("send")>-1||(customSettings.settings.video=!1,customSettings.mediaStatus.videoMuted=!0),self._sdpSessions[usePeerId].local.connection.data&&self._sdpSessions[usePeerId].local.connection.data.indexOf("send")>-1||(customSettings.settings.data=!1)),customSettings},Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo()),userCustomInfoForPeer=peerId?this._getPeerCustomSettings(peerId):null;return userCustomInfoForPeer&&"object"==typeof userCustomInfoForPeer&&(userInfo.settings=userCustomInfoForPeer.settings,userInfo.mediaStatus=userCustomInfoForPeer.mediaStatus),userInfo.settings.video&&"object"==typeof userInfo.settings.video&&(userInfo.settings.video.customSettings={},userInfo.settings.video.frameRate&&"object"==typeof userInfo.settings.video.frameRate&&(userInfo.settings.video.customSettings.frameRate=clone(userInfo.settings.video.frameRate),userInfo.settings.video.frameRate=-1),userInfo.settings.video.facingMode&&"object"==typeof userInfo.settings.video.facingMode&&(userInfo.settings.video.customSettings.facingMode=clone(userInfo.settings.video.facingMode),userInfo.settings.video.facingMode="-1"),userInfo.settings.video.resolution&&"object"==typeof userInfo.settings.video.resolution&&(userInfo.settings.video.resolution.width&&"object"==typeof userInfo.settings.video.resolution.width&&(userInfo.settings.video.customSettings.width=clone(userInfo.settings.video.width),userInfo.settings.video.resolution.width=-1),userInfo.settings.video.resolution.height&&"object"==typeof userInfo.settings.video.resolution.height&&(userInfo.settings.video.customSettings.height=clone(userInfo.settings.video.height),userInfo.settings.video.resolution.height=-1))),userInfo.settings.bandwidth&&(userInfo.settings.maxBandwidth=clone(userInfo.settings.bandwidth),delete userInfo.settings.bandwidth),this._getSDPCommonSupports(peerId).video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._getSDPCommonSupports(peerId).audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype._doOffer=function(targetMid,iceRestart){var self=this,pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of creating of offer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription","offer",'Dropping of creating of offer as signalingState is not "'+self.PEER_CONNECTION_STATE.STABLE+'" ->'],pc.signalingState);var offerConstraints={offerToReceiveAudio:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).video,offerToReceiveVideo:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).audio,iceRestart:!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,voiceActivityDetection:self._voiceActivityDetection};self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._initOptions.enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._dataChannels[targetMid]&&self._dataChannels[targetMid].main||(self._createDataChannel(targetMid),self._peerConnections[targetMid].hasMainChannel=!0)),log.debug([targetMid,null,null,"Creating offer with config:"],offerConstraints),pc.endOfCandidates=!1,self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=offerConstraints);var onSuccessCbFn=function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)};pc.createOffer(onSuccessCbFn,onErrorCbFn,"plugin"===AdapterJS.webrtcDetectedType?{mandatory:{OfferToReceiveAudio:offerConstraints.offerToReceiveAudio,OfferToReceiveVideo:offerConstraints.offerToReceiveVideo,iceRestart:offerConstraints.iceRestart,voiceActivityDetection:offerConstraints.voiceActivityDetection}}:offerConstraints)},Skylink.prototype._doAnswer=function(targetMid){var self=this;log.log([targetMid,null,null,"Creating answer with config:"],self._room.connection.sdpConstraints);var pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of creating of answer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription","answer",'Dropping of creating of answer as signalingState is not "'+self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER+'" ->'],pc.signalingState);var answerConstraints="edge"===AdapterJS.webrtcDetectedBrowser?{offerToReceiveVideo:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).video,offerToReceiveAudio:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).audio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints);var onSuccessCbFn=function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},onErrorCbFn=function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.createAnswer(onSuccessCbFn,onErrorCbFn,answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,_sessionDescription){var self=this,pc=self._peerConnections[targetMid];if(!_sessionDescription||!_sessionDescription.sdp)return void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],_sessionDescription);if(!pc)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as connection does not exists ->"],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(pc.processingLocalSDP)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as another is being processed ->"],_sessionDescription);pc.processingLocalSDP=!0;var sessionDescription={type:_sessionDescription.type,sdp:_sessionDescription.sdp};sessionDescription.sdp=self._removeSDPFirefoxH264Pref(targetMid,sessionDescription),sessionDescription.sdp=self._setSDPCodecParams(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPUnknownAptRtx(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPCodecs(targetMid,sessionDescription),sessionDescription.sdp=self._handleSDPConnectionSettings(targetMid,sessionDescription,"local"),sessionDescription.sdp=self._removeSDPREMBPackets(targetMid,sessionDescription),log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description updated ->"],sessionDescription.sdp);var onSuccessCbFn=function(){if(log.debug([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description has been set ->"],sessionDescription),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",sessionDescription.type,targetMid),sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER?pc.setAnswer="local":pc.setOffer="local",!self._initOptions.enableIceTrickle&&!pc.gathered)return void log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description sending is halted to complete ICE gathering."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},onErrorCbFn=function(error){log.error([targetMid,"RTCSessionDescription",sessionDescription.type,"Local description failed setting ->"],error),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.setLocalDescription(new RTCSessionDescription(sessionDescription),onSuccessCbFn,onErrorCbFn)},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._initOptions.appKey?("function"==typeof showAll&&(callback=showAll,showAll=!1),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.GET_PEERS,showAll:showAll||!1}),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.ENQUIRED,self._user.sid,null),log.log("Enquired server for peers within the realm"),void("function"==typeof callback&&self.once("getPeersStateChange",function(state,privilegedPeerId,peerList){callback(null,peerList)},function(state,privilegedPeerId,peerList){return state===self.GET_PEERS_STATE.RECEIVED}))):void log.warn("App key is not defined. Please authenticate again."):void log.warn("Please upgrade your key to privileged to use this function")},Skylink.prototype.introducePeer=function(sendingPeerId,receivingPeerId){var self=this;if(!self._isPrivileged)return log.warn("Please upgrade your key to privileged to use this function"),void self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,sendingPeerId,receivingPeerId,"notPrivileged");self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.INTRODUCE,sendingPeerId:sendingPeerId,receivingPeerId:receivingPeerId}),self._trigger("introduceStateChange",self.INTRODUCE_STATE.INTRODUCING,self._user.sid,sendingPeerId,receivingPeerId,null),log.log("Introducing",sendingPeerId,"to",receivingPeerId)},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._initOptions.defaultRoom,previousRoom=self._selectedRoom,mediaOptions={},timestamp=(new Date).getTime()+Math.floor(1e4*Math.random());self._joinRoomManager.timestamp=timestamp,room&&"string"==typeof room?selectedRoom=room:room&&"object"==typeof room?mediaOptions=room:"function"==typeof room&&(callback=room),options&&"object"==typeof options?mediaOptions=options:"function"==typeof options&&(callback=options);var resolveAsErrorFn=function(error,tryRoom,readyState){log.error(error),"function"==typeof callback&&callback({room:tryRoom,errorCode:readyState||null,error:error instanceof Error?error:new Error(JSON.stringify(error))})},joinRoomFn=function(){if(self._joinRoomManager.timestamp!==timestamp)return void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom);self._initSelectedRoom(selectedRoom,function(initError,initSuccess){return initError?void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState):self._joinRoomManager.timestamp!==timestamp?void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom):void self._waitForOpenChannel(mediaOptions||{},timestamp,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);if(self._joinRoomManager.timestamp!==timestamp)return void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom);if("AppleWebKit"===AdapterJS.webrtcDetectedType){var checkStream=self._streams.screenshare&&self._streams.screenshare.stream?self._streams.screenshare.stream:self._streams.userMedia&&self._streams.userMedia.stream?self._streams.userMedia.stream:null;checkStream&&0!==checkStream.getTracks().length?0===checkStream.getAudioTracks().length?log.warn("Note that receiving audio streams may fail as safari 11 needs stream with audio and video tracks and not just with video tracks"):0===checkStream.getVideoTracks().length&&log.warn("Note that receiving video streams may fail as safari 11 needs stream with audio and video tracks and not just with audio tracks"):log.warn("Note that receiving audio and video streams may fail as safari 11 needs stream with audio and video tracks")}if("function"==typeof callback){var peerOnJoin=function(peerId,peerInfo,isSelf){self.off("systemAction",peerFailedJoin),self.off("channelClose",peerSocketFailedJoin),log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo})},peerFailedJoin=function(action,message){self.off("peerJoined",peerOnJoin),self.off("channelClose",peerSocketFailedJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room ->"],message),resolveAsErrorFn(new Error(message),self._selectedRoom,self._readyState)},peerSocketFailedJoin=function(){self.off("systemAction",peerFailedJoin),self.off("peerJoined",peerOnJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room due to abrupt disconnection."]),resolveAsErrorFn(new Error("Channel closed abruptly before session was established"),self._selectedRoom,self._readyState)};self.once("peerJoined",peerOnJoin,function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),self.once("systemAction",peerFailedJoin,function(action){return action===self.SYSTEM_ACTION.REJECT}),self.once("channelClose",peerSocketFailedJoin)}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.JOIN_ROOM,uid:self._user.uid,cid:self._key,rid:self._room.id,userCred:self._user.token,timeStamp:self._user.timeStamp,apiOwner:self._appKeyOwner,roomCred:self._room.token,start:self._room.startDateTime,len:self._room.duration,isPrivileged:!0===self._isPrivileged,autoIntroduce:!1!==self._autoIntroduce,key:self._initOptions.appKey})})})};if(null===room||["number","boolean"].indexOf(typeof room)>-1)return void resolveAsErrorFn("Invalid room name is provided",room);if(null===options||["number","boolean"].indexOf(typeof options)>-1)return void resolveAsErrorFn("Invalid mediaOptions is provided",selectedRoom);self._joinRoomManager.socketsFn.forEach(function(fnItem){fnItem(timestamp)}),self._joinRoomManager.socketsFn=[];var stopStream=!1===mediaOptions.audio&&!1===mediaOptions.video;self._inRoom?self.leaveRoom({userMedia:stopStream},function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()}):(stopStream&&self.stopStream(),joinRoomFn())},Skylink.prototype.leaveRoom=function(stopMediaOptions,callback){var self=this,stopUserMedia=!0,stopScreenshare=!0,previousRoom=self._selectedRoom,previousUserPeerId=self._user?self._user.sid:null,peersThatLeft=[],isNotInRoom=!self._inRoom;"boolean"==typeof stopMediaOptions?!1===stopMediaOptions&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=!1!==stopMediaOptions.userMedia,stopScreenshare=!1!==stopMediaOptions.screenshare):"function"==typeof stopMediaOptions&&(callback=stopMediaOptions);for(var infoPeerId in self._peerInformations)self._peerInformations.hasOwnProperty(infoPeerId)&&self._peerInformations[infoPeerId]&&(peersThatLeft.push(infoPeerId),self._removePeer(infoPeerId));for(var connPeerId in self._peerConnections)self._peerConnections.hasOwnProperty(connPeerId)&&self._peerConnections[connPeerId]&&-1===peersThatLeft.indexOf(connPeerId)&&(peersThatLeft.push(connPeerId),self._removePeer(connPeerId));if(self._inRoom=!1,self._closeChannel(),isNotInRoom){var notInRoomError="Unable to leave room as user is not in any room";return log.error([null,"Room",previousRoom,notInRoomError]),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}self._stopStreams({userMedia:stopUserMedia,screenshare:stopScreenshare}),self._wait(function(){log.log([null,"Room",previousRoom,"User left the room"]),self._trigger("peerLeft",previousUserPeerId,self.getPeerInfo(),!0),"function"==typeof callback&&callback(null,{peerId:previousUserPeerId,previousRoom:previousRoom})},function(){return!self._channelOpen})},Skylink.prototype.lockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!0),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!0}),this._roomLocked=!0,this._trigger("roomLock",!0,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype.unlockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!1),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!1}),this._roomLocked=!1,this._trigger("roomLock",!1,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype._waitForOpenChannel=function(mediaOptions,joinRoomTimestamp,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){var onChannelOpen=function(){self.off("socketError",onChannelError),setTimeout(function(){if(mediaOptions=mediaOptions||{},self._userData=mediaOptions.userData||self._userData||"",self._streamsBandwidthSettings={googleX:{},bAS:{}},self._publishOnly=!1,self._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},self._voiceActivityDetection="boolean"!=typeof mediaOptions.voiceActivityDetection||mediaOptions.voiceActivityDetection,self._peerConnectionConfig={bundlePolicy:self.BUNDLE_POLICY.BALANCED,rtcpMuxPolicy:self.RTCP_MUX_POLICY.REQUIRE,iceCandidatePoolSize:0,certificate:self.PEER_CERTIFICATE.AUTO},self._bandwidthAdjuster=null,mediaOptions.bandwidth&&("number"==typeof mediaOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=mediaOptions.bandwidth.audio),"number"==typeof mediaOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=mediaOptions.bandwidth.video),"number"==typeof mediaOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=mediaOptions.bandwidth.data)),mediaOptions.googleXBandwidth&&("number"==typeof mediaOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=mediaOptions.googleXBandwidth.min),"number"==typeof mediaOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=mediaOptions.googleXBandwidth.max)),mediaOptions.sdpSettings&&(mediaOptions.sdpSettings.direction&&(mediaOptions.sdpSettings.direction.audio&&(self._sdpSettings.direction.audio.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.receive||mediaOptions.sdpSettings.direction.audio.receive,self._sdpSettings.direction.audio.send="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.send||mediaOptions.sdpSettings.direction.audio.send),mediaOptions.sdpSettings.direction.video&&(self._sdpSettings.direction.video.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.video.receive||mediaOptions.sdpSettings.direction.video.receive,self._sdpSettings.direction.video.send="boolean"!=typeof mediaOptions.sdpSettings.direction.video.send||mediaOptions.sdpSettings.direction.video.send)),mediaOptions.sdpSettings.connection&&(self._sdpSettings.connection.audio="boolean"!=typeof mediaOptions.sdpSettings.connection.audio||mediaOptions.sdpSettings.connection.audio,self._sdpSettings.connection.video="boolean"!=typeof mediaOptions.sdpSettings.connection.video||mediaOptions.sdpSettings.connection.video,self._sdpSettings.connection.data="boolean"!=typeof mediaOptions.sdpSettings.connection.data||mediaOptions.sdpSettings.connection.data)),mediaOptions.publishOnly&&(self._sdpSettings.direction.audio.send=!0,self._sdpSettings.direction.audio.receive=!1,self._sdpSettings.direction.video.send=!0,self._sdpSettings.direction.video.receive=!1,self._publishOnly=!0,"object"==typeof mediaOptions.publishOnly&&mediaOptions.publishOnly.parentId&&"string"==typeof mediaOptions.publishOnly.parentId&&(self._parentId=mediaOptions.publishOnly.parentId)),mediaOptions.parentId&&(self._parentId=mediaOptions.parentId),mediaOptions.peerConnection&&"object"==typeof mediaOptions.peerConnection){
-if("string"==typeof mediaOptions.peerConnection.bundlePolicy)for(var bpProp in self.BUNDLE_POLICY)self.BUNDLE_POLICY.hasOwnProperty(bpProp)&&self.BUNDLE_POLICY[bpProp]===mediaOptions.peerConnection.bundlePolicy&&(self._peerConnectionConfig.bundlePolicy=mediaOptions.peerConnection.bundlePolicy);if("string"==typeof mediaOptions.peerConnection.rtcpMuxPolicy)for(var rmpProp in self.RTCP_MUX_POLICY)self.RTCP_MUX_POLICY.hasOwnProperty(rmpProp)&&self.RTCP_MUX_POLICY[rmpProp]===mediaOptions.peerConnection.rtcpMuxPolicy&&(self._peerConnectionConfig.rtcpMuxPolicy=mediaOptions.peerConnection.rtcpMuxPolicy);if("number"==typeof mediaOptions.peerConnection.iceCandidatePoolSize&&mediaOptions.peerConnection.iceCandidatePoolSize>0&&(self._peerConnectionConfig.iceCandidatePoolSize=mediaOptions.peerConnection.iceCandidatePoolSize),"string"==typeof mediaOptions.peerConnection.certificate)for(var pcProp in self.PEER_CERTIFICATE)self.PEER_CERTIFICATE.hasOwnProperty(pcProp)&&self.PEER_CERTIFICATE[pcProp]===mediaOptions.peerConnection.certificate&&(self._peerConnectionConfig.certificate=mediaOptions.peerConnection.certificate)}if(mediaOptions.autoBandwidthAdjustment&&(self._bandwidthAdjuster={interval:10,limitAtPercentage:100,useUploadBwOnly:!1},"object"==typeof mediaOptions.autoBandwidthAdjustment&&("number"==typeof mediaOptions.autoBandwidthAdjustment.interval&&mediaOptions.autoBandwidthAdjustment.interval>=10&&(self._bandwidthAdjuster.interval=mediaOptions.autoBandwidthAdjustment.interval),"number"==typeof mediaOptions.autoBandwidthAdjustment.limitAtPercentage&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage>=0&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage<=100&&(self._bandwidthAdjuster.limitAtPercentage=mediaOptions.autoBandwidthAdjustment.limitAtPercentage),"boolean"==typeof mediaOptions.autoBandwidthAdjustment.useUploadBwOnly&&(self._bandwidthAdjuster.useUploadBwOnly=mediaOptions.autoBandwidthAdjustment.useUploadBwOnly))),!0===mediaOptions.manualGetUserMedia){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){!0===mediaAccessRequiredFailure?self._onUserMediaError(new Error("Waiting for stream timeout"),!1,!1):callback(null,self._streams.userMedia.stream)},function(){return current50Block+=1,600===current50Block?(mediaAccessRequiredFailure=!0,!0):!(!self._streams.userMedia||!self._streams.userMedia.stream)||void 0},50)}if(mediaOptions.audio||mediaOptions.video)return void self.getUserMedia({useExactConstraints:!!mediaOptions.useExactConstraints,audio:mediaOptions.audio,video:mediaOptions.video},function(error,success){error?callback(error,null):callback(null,success)});callback(null,null)},1)},onChannelError=function(errorState,error){self.off("channelOpen",onChannelOpen),callback(error)};self._channelOpen?onChannelOpen():(self.once("channelOpen",onChannelOpen),self.once("socketError",onChannelError,function(errorState){return errorState===self.SOCKET_ERROR.RECONNECTION_ABORTED}),self._openChannel(joinRoomTimestamp))},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.generateUUID=function(){var d=(new Date).getTime();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"===c?r:r&&15).toString(16)})},Skylink.prototype.init=function(_options,_callback){var self=this,options={},callback=function(){};if("function"==typeof _options?callback=_options:_options&&"object"==typeof _options?(options=clone(_options),options.appKey&&"string"==typeof options.appKey||!options.apiKey||"string"!=typeof options.apiKey||(options.appKey=options.apiKey)):_options&&"string"==typeof _options&&(options.appKey=_options),"function"==typeof _callback&&(callback=_callback),options.defaultRoom=options.defaultRoom&&"string"==typeof options.defaultRoom?options.defaultRoom:options.appKey,options.roomServer=options.roomServer&&"string"==typeof options.roomServer?options.roomServer:"//api.temasys.io",options.enableIceTrickle=!1!==options.enableIceTrickle,options.enableDataChannel=!1!==options.enableDataChannel,options.enableSTUNServer=!1!==options.enableSTUNServer,options.enableTURNServer=!1!==options.enableTURNServer,options.audioFallback=!0===options.audioFallback,options.forceSSL=!1!==options.forceSSL,options.socketTimeout="number"==typeof options.socketTimeout&&options.socketTimeout>=5e3?options.socketTimeout:7e3,options.apiTimeout="number"==typeof options.apiTimeout?options.apiTimeout:4e3,options.forceTURNSSL=!0===options.forceTURNSSL,options.forceTURN=!0===options.forceTURN,options.usePublicSTUN=!0===options.usePublicSTUN,options.disableVideoFecCodecs=!0===options.disableVideoFecCodecs,options.disableComfortNoiseCodec=!0===options.disableComfortNoiseCodec,options.disableREMB=!0===options.disableREMB,options.throttleShouldThrowError=!0===options.throttleShouldThrowError,options.mcuUseRenegoRestart=!0===options.mcuUseRenegoRestart,options.useEdgeWebRTC=!0===options.useEdgeWebRTC,options.enableSimultaneousTransfers=!1!==options.enableSimultaneousTransfers,options.priorityWeightScheme=self._containsInList("PRIORITY_WEIGHT_SCHEME",options.priorityWeightScheme,"AUTO"),options.TURNServerTransport=self._containsInList("TURN_TRANSPORT",options.TURNServerTransport,"ANY"),options.credentials=options.credentials&&"object"==typeof options.credentials&&options.credentials.startDateTime&&"string"==typeof options.credentials.startDateTime&&options.credentials.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration?options.credentials:null,options.filterCandidatesType=options.filterCandidatesType&&"object"==typeof options.filterCandidatesType?options.filterCandidatesType:{},options.filterCandidatesType.host=!0===options.filterCandidatesType.host,options.filterCandidatesType.srflx=!0===options.filterCandidatesType.srflx,options.filterCandidatesType.relay=!0===options.filterCandidatesType.relay,options.throttleIntervals=options.throttleIntervals&&"object"==typeof options.throttleIntervals?options.throttleIntervals:{},options.throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:1e4,options.throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:5e3,options.throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:0,options.iceServer&&"string"==typeof options.iceServer?options.iceServer={urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0?options.iceServer={urls:options.iceServer}:options.iceServer=null,options.socketServer&&"string"==typeof options.socketServer?options.socketServer=options.socketServer:options.socketServer&&"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url?options.socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)?options.socketServer.ports:[],protocol:options.socketServer.protocol?options.socketServer.protocol:null}:options.socketServer=null,options.audioCodec&&"object"==typeof options.audioCodec&&self._containsInList("AUDIO_CODEC",options.audioCodec.codec,"-")?options.audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels?options.audioCodec.channels:null}:options.audioCodec=self._containsInList("AUDIO_CODEC",options.audioCodec,"AUTO"),options.videoCodec&&"object"==typeof options.videoCodec&&self._containsInList("VIDEO_CODEC",options.videoCodec.codec,"-")?options.videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate?options.videoCodec.samplingRate:null}:options.videoCodec=self._containsInList("VIDEO_CODEC",options.videoCodec,"AUTO"),options.codecParams=options.codecParams&&"object"==typeof options.codecParams?options.codecParams:{},options.codecParams.audio=options.codecParams.audio&&"object"==typeof options.codecParams.audio?options.codecParams.audio:{},options.codecParams.video=options.codecParams.video&&"object"==typeof options.codecParams.video?options.codecParams.video:{},options.codecParams.audio.opus=options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus?options.codecParams.audio.opus:{},options.codecParams.audio.opus.stereo="boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,options.codecParams.audio.opus["sprop-stereo"]="boolean"==typeof options.codecParams.audio.opus["sprop-stereo"]?options.codecParams.audio.opus["sprop-stereo"]:null,options.codecParams.audio.opus.usedtx="boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,options.codecParams.audio.opus.useinbandfec="boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,options.codecParams.audio.opus.maxplaybackrate="number"==typeof options.codecParams.audio.opus.maxplaybackrate&&options.codecParams.audio.opus.maxplaybackrate>=8e3&&options.codecParams.audio.opus.maxplaybackrate<=48e3?options.codecParams.audio.opus.maxplaybackrate:null,options.codecParams.audio.opus.minptime="number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null,options.codecParams.video.h264=options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264?options.codecParams.video.h264:{},options.codecParams.video.h264.profileLevelId=options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,options.codecParams.video.h264.levelAsymmetryAllowed="boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,options.codecParams.video.h264.packetizationMode="boolean"==typeof options.codecParams.video.h264.packetizationMode?!0===options.codecParams.video.h264.packetizationMode?1:0:"number"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null,options.codecParams.video.vp8=options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8?options.codecParams.video.vp8:{},options.codecParams.video.vp8.maxFs="number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,options.codecParams.video.vp8.maxFr="number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null,options.codecParams.video.vp9=options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9?options.codecParams.video.vp9:{},options.codecParams.video.vp9.maxFs="number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,options.codecParams.video.vp9.maxFr="number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null,options.forceTURN&&(options.enableTURNServer=!0,options.enableSTUNServer=!1,options.filterCandidatesType.host=!0,options.filterCandidatesType.srflx=!0,options.filterCandidatesType.relay=!1),self.once("readyStateChange",function(){},function(state,error){if(state===self.READY_STATE_CHANGE.ERROR)return log.error("Failed init() process ->",error),callback({error:error.content,errorCode:error.errorCode,status:error.status},null),!0;if(state===self.READY_STATE_CHANGE.COMPLETED){log.info("Completed init() successfully ->",options);var success=clone(self._initOptions);return success.serverUrl=self._path,success.readyState=self._readyState,success.selectedRoom=self._selectedRoom,success.TURNTransport=success.TURNServerTransport,callback(null,success),!0}}),self._initOptions=options,self._readyState=self.READY_STATE_CHANGE.INIT,self._selectedRoom=self._initOptions.defaultRoom,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),!options||!options.appKey||"string"!=typeof options.appKey)return self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{content:new Error("Please provide an app key"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH,status:-2},self._selectedRoom);self._path=self._initOptions.roomServer+"/api/"+self._initOptions.appKey+"/"+self._selectedRoom+(self._initOptions.credentials?"/"+self._initOptions.credentials.startDateTime+"/"+self._initOptions.credentials.duration+"?cred="+self._initOptions.credentials.credentials:"")+(self._initOptions.credentials?"&":"?")+"rand="+Date.now(),self._loadInfo()},Skylink.prototype._containsInList=function(listName,value,defaultProperty){var self=this;for(var property in self[listName])if(self[listName].hasOwnProperty(property)&&self[listName][property]===value)return value;return self[listName][defaultProperty]},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,retries=0;self._socketUseXDR="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest,url=self._initOptions.forceSSL?"https:"+url:url,function requestFn(){var xhr=new XMLHttpRequest,completed=!1;self._socketUseXDR&&(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest for CORS authentication."]),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}),xhr.onload=function(){if(!completed){completed=!0;var response=JSON.parse(xhr.responseText||xhr.response||"{}"),status=xhr.status||(response.success?200:400);if(response.success)return log.debug([null,"XMLHttpRequest",method,"Received sessions parameters ->"],response),void callback(response);log.error([null,"XMLHttpRequest",method,"Failed retrieving sessions parameters ->"],response),self._readyState=self.READY_STATE_CHANGE.ERROR,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:new Error(response.info||"XMLHttpRequest status not OK\nStatus was: "+status),errorCode:response.error||status},self._selectedRoom)}},xhr.onerror=function(error){completed||(completed=!0,log.error([null,"XMLHttpRequest",method,"Failed retrieving information with status ->"],xhr.status),self._readyState=self.READY_STATE_CHANGE.ERROR,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||-1,content:new Error("Network error occurred. (Status: "+xhr.status+")"),errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom))},xhr.onprogress=function(){log.debug([null,"XMLHttpRequest",method,"Retrieving information and config from webserver ->"],{url:url,params:params})};try{xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()}catch(error){return completed=!0,self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||-1,content:new Error("Failed starting XHR process."),errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom)}setTimeout(function(){completed||(completed=!0,xhr.onload=null,xhr.onerror=null,xhr.onprogress=null,retries<2?(retries++,requestFn()):(self._readyState=self.READY_STATE_CHANGE.ERROR,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||-1,content:new Error("Response timed out from API server"),errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_NO_REPONSE_ERROR},self._selectedRoom)))},self._initOptions.apiTimeout)}()},Skylink.prototype._parseInfo=function(info){if(log.log("Parsing parameter from server",info),!info.pc_constraints&&!info.offer_constraints)return void this._trigger("readyStateChange",this.READY_STATE_CHANGE.ERROR,{status:200,content:info.info,errorCode:info.error},self._selectedRoom);log.debug("Peer connection constraints:",info.pc_constraints),log.debug("Offer constraints:",info.offer_constraints),this._key=info.cid,this._appKeyOwner=info.apiOwner,this._signalingServer=info.ipSigserver,this._isPrivileged=info.isPrivileged,this._autoIntroduce=info.autoIntroduce,this._user={uid:info.username,token:info.userCred,timeStamp:info.timeStamp,streams:[],info:{}},this._room={id:info.room_key,token:info.roomCred,startDateTime:info.start,duration:info.len,connection:{peerConstraints:JSON.parse(info.pc_constraints),peerConfig:null,offerConstraints:JSON.parse(info.offer_constraints),sdpConstraints:{mandatory:{OfferToReceiveAudio:!0,OfferToReceiveVideo:!0}},mediaConstraints:JSON.parse(info.media_constraints)}},this._socketPorts={"http:":Array.isArray(info.httpPortList)&&info.httpPortList.length>0?info.httpPortList:[80,3e3],"https:":Array.isArray(info.httpsPortList)&&info.httpsPortList.length>0?info.httpsPortList:[443,3443]},this._readyState=this.READY_STATE_CHANGE.COMPLETED,this._trigger("readyStateChange",this.READY_STATE_CHANGE.COMPLETED,null,this._selectedRoom),log.info("Parsed parameters from webserver. Ready for web-realtime communication")},Skylink.prototype._loadInfo=function(){var self=this;if("function"!=typeof(globals.AdapterJS||window.AdapterJS||{}).webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used"),errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return globals.io||window.io?window.XMLHttpRequest?self._path?void AdapterJS.webRTCReady(function(){if(self._enableIceRestart="firefox"!==AdapterJS.webrtcDetectedBrowser||AdapterJS.webrtcDetectedVersion>=48,self._binaryChunkType="firefox"===AdapterJS.webrtcDetectedBrowser?self.DATA_TRANSFER_DATA_TYPE.BLOB:self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&"plugin"===AdapterJS.webrtcDetectedType?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("plugin"===AdapterJS.webrtcDetectedType&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error(error.message||error.toString()),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):0===Object.keys(self._currentCodecSupport.audio).length&&0===Object.keys(self._currentCodecSupport.video).length?(log.error("No audio/video codecs available to start connection."),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("No audio/video codecs available to start connection"),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=self.READY_STATE_CHANGE.LOADING,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(response){self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("No API Path is found"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH},self._selectedRoom)):(log.error("XMLHttpRequest not supported. Please upgrade your browser"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("XMLHttpRequest not available"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_XMLHTTPREQUEST_SUPPORT},self._selectedRoom)):(log.error("Socket.io not loaded. Please load socket.io"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("Socket.io not found"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_SOCKET_IO},self._selectedRoom))},Skylink.prototype._initSelectedRoom=function(room,callback){var self=this;if("function"==typeof room||void 0===room)return log.error("Invalid room provided. Room:",room),void callback(new Error("Invalid room provided"),null);var defaultRoom=self._initOptions.defaultRoom,options=clone(self._initOptions);options.iceServer=options.iceServer?options.iceServer.urls:null,options.defaultRoom!==room&&(options.defaultRoom=room),self.init(options,function(error,success){self._initOptions.defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})};var _LOG_KEY="SkylinkJS",_LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!1,_printTimestamp=!1,_storedLogs=[],_getStoredLogsFn=function(logLevel){if(void 0===logLevel)return _storedLogs;for(var returnLogs=[],i=0;i<_storedLogs.length;i++)_storedLogs[i][1]===_LOG_LEVELS[logLevel]&&returnLogs.push(_storedLogs[i]);return returnLogs},_clearAllStoredLogsFn=function(){_storedLogs=[]},_printAllStoredLogsFn=function(){for(var i=0;i<_storedLogs.length;i++){var timestamp=_storedLogs[i][0],log="undefined"!==console[_storedLogs[i][1]]?_storedLogs[i][1]:"log",message=_storedLogs[i][2],debugObject=_storedLogs[i][3];void 0!==debugObject?console[log](message,debugObject,timestamp):console[log](message,timestamp)}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="",datetime=new Date;if("object"==typeof message){if(outputLog+=message[0]?" ["+message[0]+"] -":" -",outputLog+=message[1]?" <<"+message[1]+">>":"",message[2])if(outputLog+=" ","object"==typeof message[2])for(var i=0;i=logLevel)if(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace){void 0===console.trace&&logLevel[3];void 0!==debugObject?(console[_LOG_LEVELS[logLevel]](outputLog,debugObject),void 0!==console.trace&&console.trace("")):(console[_LOG_LEVELS[logLevel]](outputLog),void 0!==console.trace&&console.trace(""))}else void 0!==debugObject?console[_LOG_LEVELS[logLevel]](outputLog,debugObject):console[_LOG_LEVELS[logLevel]](outputLog)},log={debug:function(message,object){_logFn(4,message,object)},log:function(message,object){_logFn(3,message,object)},info:function(message,object){_logFn(2,message,object)},warn:function(message,object){_logFn(1,message,object)},error:function(message,object){_logFn(0,message,object)}};Skylink.prototype.setLogLevel=function(logLevel){for(var level in this.LOG_LEVEL)if(this.LOG_LEVEL[level]===logLevel)return _logLevel=logLevel,void log.log([null,"Log",level,"Log level exists. Level is set"]);log.error([null,"Log",level,"Log level does not exist. Level is not set"])},Skylink.prototype.setDebugMode=function(isDebugMode){isDebugMode&&"object"==typeof isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0===isDebugMode.trace,_enableDebugStack=!0===isDebugMode.storeLogs,_printTimestamp=!0===isDebugMode.printTimestamp):!0===isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0,_printTimestamp=!1):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1,_printTimestamp=!1)};Skylink.prototype.on=function(eventName,callback){"function"==typeof callback?(this._EVENTS[eventName]=this._EVENTS[eventName]||[],this._EVENTS[eventName].push(callback),log.log([null,"Event",eventName,"Event is subscribed"])):log.error([null,"Event",eventName,"Provided parameter is not a function"])},Skylink.prototype.once=function(eventName,callback,condition,fireAlways){"boolean"==typeof condition&&(fireAlways=condition,condition=null),fireAlways=void 0!==fireAlways&&fireAlways,condition="function"!=typeof condition?function(){return!0}:condition,"function"==typeof callback?(this._onceEvents[eventName]=this._onceEvents[eventName]||[],this._onceEvents[eventName].push([callback,condition,fireAlways]),log.log([null,"Event",eventName,"Event is subscribed on condition"])):log.error([null,"Event",eventName,"Provided callback is not a function"])},Skylink.prototype.off=function(eventName,callback){if(eventName&&"string"==typeof eventName){if(void 0===callback)return this._EVENTS[eventName]=[],this._onceEvents[eventName]=[],void log.log([null,"Event",eventName,"All events are unsubscribed"]);for(var arr=this._EVENTS[eventName]||[],once=this._onceEvents[eventName]||[],i=0;i"],message);self._user.sid&&!self._peerMessagesStamps[self._user.sid]&&(self._peerMessagesStamps[self._user.sid]={userData:0,audioMuted:0,videoMuted:0});var checkStampFn=function(statusMessage){return statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].userData:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].videoMuted:statusMessage.type!==self._SIG_MESSAGE_TYPE.MUTE_AUDIO||!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].audioMuted},setStampFn=function(statusMessage){statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?self._peerMessagesStamps[self._user.sid].userData=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?self._peerMessagesStamps[self._user.sid].videoMuted=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&(self._peerMessagesStamps[self._user.sid].audioMuted=statusMessage.stamp)},setQueueFn=function(){log.debug([null,"Socket",null,"Starting queue timeout"]),self._socketMessageTimeout=setTimeout(function(){if((new Date).getTime()-self._timestamp.socketMessage<=interval)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},interval-((new Date).getTime()-self._timestamp.socketMessage))},triggerEventFn=function(eventMessage){eventMessage.type===self._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE&&self._trigger("incomingMessage",{content:eventMessage.data,isPrivate:!1,targetPeerId:null,listOfPeers:Object.keys(self._peerInformations),isDataChannel:!1,senderPeerId:self._user.sid},self._user.sid,self.getPeerInfo(),!0)},sendGroupMessageFn=function(groupMessageList){if(self._socketMessageTimeout=null,!(self._channelOpen&&self._user&&self._user.sid&&self._socket))return void log.warn([message.target||"Server","Socket",null,"Dropping of group messages as Socket connection is not opened or is at incorrect step ->"],groupMessageList);for(var strGroupMessageList=[],stamps={userData:0,audioMuted:0,videoMuted:0},k=0;kself._peerMessagesStamps[self._user.sid].userData&&groupMessageList[k].stamp>stamps.userData?stamps.userData=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].audioMuted&&groupMessageList[k].stamp>stamps.audioMuted?stamps.audioMuted=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].videoMuted&&groupMessageList[k].stamp>stamps.videoMuted&&(stamps.videoMuted=groupMessageList[k].stamp));for(var i=0;i"],clone(groupMessageList[i])),groupMessageList.splice(i,1),i--):strGroupMessageList.push(JSON.stringify(groupMessageList[i]));if(strGroupMessageList.length>0){var groupMessage={
-type:self._SIG_MESSAGE_TYPE.GROUP,lists:strGroupMessageList,mid:self._user.sid,rid:self._room.id};log.log([message.target||"Server","Socket",groupMessage.type,"Sending queued grouped message (max: 16 per group) ->"],clone(groupMessage)),self._socket.send(JSON.stringify(groupMessage)),self._timestamp.socketMessage=(new Date).getTime();for(var j=0;j0&&(self._socketMessageQueue.length-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=interval)log.debug([message.target||"Server","Socket",message.type,"Queueing socket message to prevent message drop ->"],clone(message)),self._socketMessageQueue.push(message),self._socketMessageTimeout||setQueueFn();else{if(!checkStampFn(message))return void log.warn([message.target||"Server","Socket",message.type,"Dropping of outdated status message ->"],clone(message));self._socketMessageTimeout&&clearTimeout(self._socketMessageTimeout),log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),setStampFn(message),triggerEventFn(message),self._timestamp.socketMessage=(new Date).getTime()}else log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),message.type===self._SIG_MESSAGE_TYPE.BYE&&self._inRoom&&self._user&&self._user.sid&&message.mid===self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo()))},Skylink.prototype._createSocket=function(type,joinRoomTimestamp){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._initOptions.socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._initOptions.socketServer&&"object"==typeof self._initOptions.socketServer&&Array.isArray(self._initOptions.socketServer.ports)&&self._initOptions.socketServer.ports.length>0?self._initOptions.socketServer.ports:self._socketPorts[self._signalingServerProtocol],fallbackType=null;null===self._signalingServerPort?(self._signalingServerPort=ports[0],fallbackType=self.SOCKET_FALLBACK.NON_FALLBACK):ports.indexOf(self._signalingServerPort)===ports.length-1||"string"==typeof self._initOptions.socketServer?"WebSocket"===type?(type="Polling",self._signalingServerPort=ports[0]):self._socketSession.finalAttempts++:self._signalingServerPort=ports[ports.indexOf(self._signalingServerPort)+1],"Polling"===type&&(options.reconnectionDelayMax=1e3,options.reconnectionAttempts=4,options.transports=["xhr-polling","jsonp-polling","polling"]);var url=self._signalingServerProtocol+"//"+self._signalingServer+":"+self._signalingServerPort+"?rand="+Date.now(),retries=0;self._initOptions.socketServer&&(url="string"==typeof self._initOptions.socketServer?self._initOptions.socketServer:(self._initOptions.socketServer.protocol?self._initOptions.socketServer.protocol:self._signalingServerProtocol)+"//"+self._initOptions.socketServer.url+":"+self._signalingServerPort),self._socketSession.transportType=type,self._socketSession.socketOptions=options,self._socketSession.socketServer=url,null===fallbackType&&(fallbackType="http:"===self._signalingServerProtocol?"Polling"===type?self.SOCKET_FALLBACK.LONG_POLLING:self.SOCKET_FALLBACK.FALLBACK_PORT:"Polling"===type?self.SOCKET_FALLBACK.LONG_POLLING_SSL:self.SOCKET_FALLBACK.FALLBACK_SSL_PORT,self._socketSession.attempts++,self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ATTEMPT,null,fallbackType,clone(self._socketSession)),self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))),self._socket&&self._closeChannel(),self._channelOpen=!1,log.log("Opening channel with signaling server url:",clone(self._socketSession));var socket=null;try{socket=io.connect(url,options)}catch(error){return log.error("Failed creating socket connection object ->",error),fallbackType===self.SOCKET_FALLBACK.NON_FALLBACK?self._trigger("socketError",self.SOCKET_ERROR.CONNECTION_FAILED,error,fallbackType,clone(self._socketSession)):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_FAILED,error,fallbackType,clone(self._socketSession)),void self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ABORTED,new Error("Reconnection aborted as there no more available ports, transports and final attempts left."),fallbackType,clone(self._socketSession))}socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),socket.on("reconnect_failed",function(){fallbackType===self.SOCKET_FALLBACK.NON_FALLBACK?self._trigger("socketError",self.SOCKET_ERROR.CONNECTION_FAILED,new Error('Failed connection with transport "'+type+'" and port '+self._signalingServerPort+"."),fallbackType,clone(self._socketSession)):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_FAILED,new Error('Failed reconnection with transport "'+type+'" and port '+self._signalingServerPort+"."),fallbackType,clone(self._socketSession)),self._socketSession.finalAttempts<2?self._createSocket(type,joinRoomTimestamp):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ABORTED,new Error("Reconnection aborted as there no more available ports, transports and final attempts left."),fallbackType,clone(self._socketSession))}),socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),socket.on("error",function(error){if(error&&error.message.indexOf("xhr poll error")>-1)return log.error([null,"Socket",null,"XHR poll connection unstable. Disconnecting.. ->"],error),void self._closeChannel();log.error([null,"Socket",null,"Exception occurred ->"],error),self._trigger("channelError",error,clone(self._socketSession))}),socket.on("disconnect",function(){self._channelOpen&&(self._channelOpen=!1,self._trigger("channelClose",clone(self._socketSession)),log.log([null,"Socket",null,"Channel closed"]),self._inRoom&&self._user&&self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo())))}),socket.on("message",function(messageStr){var message=JSON.parse(messageStr);if(log.log([null,"Socket",null,"Received message ->"],message),message.type===self._SIG_MESSAGE_TYPE.GROUP){log.debug("Bundle of "+message.lists.length+" messages");for(var i=0;i",message);for(var i=0;i-1:state===self.RECORDING_STATE.STOP})}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.STOP_RECORDING,rid:self._room.id,target:"MCU"}),log.debug(["MCU","Recording",null,"Stopping recording"])},Skylink.prototype.getRecordings=function(){return clone(this._recordings)},Skylink.prototype._processSigMessage=function(message,session){var origin=message.mid;if(origin&&origin!==this._user.sid||(origin="Server"),log.debug([origin,"Socket",message.type,"Received from peer ->"],clone(message)),message.mid===this._user.sid&&message.type!==this._SIG_MESSAGE_TYPE.REDIRECT&&message.type!==this._SIG_MESSAGE_TYPE.IN_ROOM)return void log.debug([origin,"Socket",message.type,"Ignoring message ->"],clone(message));switch(message.type){case this._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE:this._publicMessageHandler(message);break;case this._SIG_MESSAGE_TYPE.PRIVATE_MESSAGE:this._privateMessageHandler(message);break;case this._SIG_MESSAGE_TYPE.IN_ROOM:this._inRoomHandler(message);break;case this._SIG_MESSAGE_TYPE.ENTER:this._enterHandler(message);break;case this._SIG_MESSAGE_TYPE.WELCOME:this._welcomeHandler(message);break;case this._SIG_MESSAGE_TYPE.RESTART:this._restartHandler(message);break;case this._SIG_MESSAGE_TYPE.OFFER:this._offerHandler(message);break;case this._SIG_MESSAGE_TYPE.ANSWER:this._answerHandler(message);break;case this._SIG_MESSAGE_TYPE.CANDIDATE:this._candidateHandler(message);break;case this._SIG_MESSAGE_TYPE.BYE:this._byeHandler(message);break;case this._SIG_MESSAGE_TYPE.REDIRECT:this._redirectHandler(message);break;case this._SIG_MESSAGE_TYPE.UPDATE_USER:this._updateUserEventHandler(message);break;case this._SIG_MESSAGE_TYPE.MUTE_VIDEO:this._muteVideoEventHandler(message);break;case this._SIG_MESSAGE_TYPE.MUTE_AUDIO:this._muteAudioEventHandler(message);break;case this._SIG_MESSAGE_TYPE.STREAM:this._streamEventHandler(message);break;case this._SIG_MESSAGE_TYPE.ROOM_LOCK:this._roomLockEventHandler(message);break;case this._SIG_MESSAGE_TYPE.PEER_LIST:this._peerListEventHandler(message);break;case this._SIG_MESSAGE_TYPE.INTRODUCE_ERROR:this._introduceErrorEventHandler(message);break;case this._SIG_MESSAGE_TYPE.APPROACH:this._approachEventHandler(message);break;case this._SIG_MESSAGE_TYPE.RECORDING:this._recordingEventHandler(message);break;case this._SIG_MESSAGE_TYPE.END_OF_CANDIDATES:this._endOfCandidatesHandler(message);break;default:log.error([message.mid,"Socket",message.type,"Unsupported message ->"],clone(message))}},Skylink.prototype._peerListEventHandler=function(message){var self=this;self._peerList=message.result,log.log(["Server",null,message.type,"Received list of peers"],self._peerList),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.RECEIVED,self._user.sid,self._peerList)},Skylink.prototype._endOfCandidatesHandler=function(message){var self=this,targetMid=message.mid;self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&(self._peerEndOfCandidatesCounter[targetMid].expectedLen=message.noOfExpectedCandidates||0,self._signalingEndOfCandidates(targetMid))},Skylink.prototype._introduceErrorEventHandler=function(message){var self=this;log.log(["Server",null,message.type,"Introduce failed. Reason: "+message.reason]),self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,message.sendingPeerId,message.receivingPeerId,message.reason)},Skylink.prototype._approachEventHandler=function(message){var self=this;log.log(["Server",null,message.type,"Approaching peer"],message.target),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._redirectHandler=function(message){if(log.log(["Server",null,message.type,"System action warning:"],{message:message.info,reason:message.reason,action:message.action}),message.action===this.SYSTEM_ACTION.REJECT)for(var key in this._peerConnections)this._peerConnections.hasOwnProperty(key)&&this._removePeer(key);"toClose"===message.reason&&(message.reason="toclose"),this._trigger("systemAction",message.action,message.info,message.reason)},Skylink.prototype._updateUserEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer updated userData:"],message.userData),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].userData=message.stamp}this._peerInformations[targetMid].userData=message.userData||{},this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._roomLockEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,message.type,"Room lock status:"],message.lock),this._trigger("roomLock",message.lock,targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._muteAudioEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's audio muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].audioMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.audioMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,message.type,"Peer does not have any user information"])},Skylink.prototype._muteVideoEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's video muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].videoMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.videoMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._streamEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Peer's stream status:"],message.status),this._peerInformations[targetMid]&&message.streamId?(this._streamsSession[targetMid]=this._streamsSession[targetMid]||{},"ended"===message.status&&(message.settings&&"object"==typeof message.settings&&void 0===this._streamsSession[targetMid][message.streamId]&&(this._streamsSession[targetMid][message.streamId]={audio:message.settings.audio,video:message.settings.video}),this._handleEndedStreams(targetMid,message.streamId))):log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._byeHandler=function(message){var targetMid=message.mid;(this._user||{}).sid!==targetMid?(log.log([targetMid,null,message.type,"Peer has left the room"]),this._removePeer(targetMid)):log.log([targetMid,null,message.type,"Self has left the room"])},Skylink.prototype._privateMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received private message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!0,targetPeerId:message.target,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._publicMessageHandler=function(message){var targetMid=message.mid;log.log([targetMid,null,message.type,"Received public message from peer:"],message.data),this._trigger("incomingMessage",{content:message.data,isPrivate:!1,targetPeerId:null,isDataChannel:!1,senderPeerId:targetMid},targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._recordingEventHandler=function(message){var self=this;if(log.debug(["MCU","Recording",null,"Received recording message ->"],message),"on"===message.action)self._recordings[message.recordingId]||(log.debug(["MCU","Recording",message.recordingId,"Started recording"]),self._currentRecordingId=message.recordingId,self._recordings[message.recordingId]={active:!0,state:self.RECORDING_STATE.START,startedDateTime:(new Date).toISOString(),endedDateTime:null,mixingDateTime:null,links:null,error:null},self._recordingStartInterval=setTimeout(function(){log.log(["MCU","Recording",message.recordingId,"4 seconds has been recorded. Recording can be stopped now"]),self._recordingStartInterval=null},4e3),self._trigger("recordingState",self.RECORDING_STATE.START,message.recordingId,null,null));else if("off"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,'Received request of "off" but the session is empty']);self._currentRecordingId=null,self._recordingStartInterval&&(clearTimeout(self._recordingStartInterval),log.warn(["MCU","Recording",message.recordingId,"Recording stopped abruptly before 4 seconds"]),self._recordingStartInterval=null),log.debug(["MCU","Recording",message.recordingId,"Stopped recording"]),self._recordings[message.recordingId].active=!1,self._recordings[message.recordingId].state=self.RECORDING_STATE.STOP,self._recordings[message.recordingId].endedDateTime=(new Date).toISOString(),self._trigger("recordingState",self.RECORDING_STATE.STOP,message.recordingId,null,null)}else if("url"===message.action){if(!self._recordings[message.recordingId])return void log.error(["MCU","Recording",message.recordingId,"Received URL but the session is empty"]);var links={};if(Array.isArray(message.urls))for(var i=0;i"],recordingError);log.error(["MCU","Recording",message.recordingId,"Recording failure ->"],recordingError),self._recordings[message.recordingId].state=self.RECORDING_STATE.ERROR,self._recordings[message.recordingId].error=recordingError,self._recordings[message.recordingId].active&&(log.debug(["MCU","Recording",message.recordingId,"Stopped recording abruptly"]),self._recordings[message.recordingId].active=!1),self._trigger("recordingState",self.RECORDING_STATE.ERROR,message.recordingId,null,recordingError)}},Skylink.prototype._inRoomHandler=function(message){var self=this;log.log(["Server",null,message.type,"User is now in the room and functionalities are now available. Config received:"],message.pc_config),self._room.connection.peerConfig=self._setIceServers((message.pc_config||{}).iceServers||[]),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._initOptions.priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._initOptions.priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.ENFORCE_OFFERER?2e15:-2e15),self._trigger("peerJoined",self._user.sid,self.getPeerInfo(),!0),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var streamId=null;self._streams.screenshare&&self._streams.screenshare.stream?(streamId=self._streams.screenshare.stream.id||self._streams.screenshare.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.screenshare.stream,!0,self.getPeerInfo(),!0,streamId)):self._streams.userMedia&&self._streams.userMedia.stream&&(streamId=self._streams.userMedia.stream.id||self._streams.userMedia.stream.label,self._trigger("incomingStream",self._user.sid,self._streams.userMedia.stream,!0,self.getPeerInfo(),!1,streamId));var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._enterHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "enter" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid)}self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0};var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),receiveOnly:self.getPeerInfo().config.receiveOnly,os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg),isNewPeer&&self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._restartHandler=function(message){var self=this,targetMid=message.mid,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,
-userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "restart" received ->'],message),!self._peerInformations[targetMid])return void log.error([targetMid,"RTCPeerConnection",null,"Peer does not have an existing session. Ignoring restart process."]);if("MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId or publishOnly case ->'],message);if(self._hasMCU&&!self._initOptions.mcuUseRenegoRestart)return log.warn([targetMid,"RTCPeerConnection",null,"Dropping restart request as MCU does not support re-negotiation. Restart workaround is to re-join Room for Peer."]),void self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!1);if(self._peerInformations[targetMid]=userInfo,self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid].len=0,self._peerPriorityWeight>message.weight){if(log.debug([targetMid,"RTCPeerConnection",null,"Re-negotiating new offer/answer."]),self._peerMessagesStamps[targetMid].hasRestart)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "restart" received.']);self._peerMessagesStamps[targetMid].hasRestart=!0,self._doOffer(targetMid,!0===message.doIceRestart,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start re-negotiation."]);var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===message.doIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,isRestartResend:!0,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._sendChannelMessage(restartMsg)}self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!0===message.doIceRestart)},Skylink.prototype._welcomeHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "welcome" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)}if(self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0,hasWelcome:!1},self._hasMCU||self._peerPriorityWeight>message.weight){if(self._peerMessagesStamps[targetMid].hasWelcome)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "welcome" received.']);log.debug([targetMid,"RTCPeerConnection",null,"Starting negotiation"]),self._peerMessagesStamps[targetMid].hasWelcome=!0,self._doOffer(targetMid,!1,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start negotiation."]);var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg)}};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._offerHandler=function(message){var self=this,targetMid=message.mid,pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for offer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}log.log([targetMid,null,message.type,"Received offer from peer. Session description:"],clone(message));var offer={type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],offer),offer.sdp=self._removeSDPFilteredCandidates(targetMid,offer),offer.sdp=self._setSDPCodec(targetMid,offer),offer.sdp=self._setSDPBitrate(targetMid,offer),offer.sdp=self._setSDPCodecParams(targetMid,offer),offer.sdp=self._removeSDPCodecs(targetMid,offer),offer.sdp=self._removeSDPREMBPackets(targetMid,offer),offer.sdp=self._handleSDPConnectionSettings(targetMid,offer,"remote"),offer.sdp=self._removeSDPUnknownAptRtx(targetMid,offer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "stable" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.resend});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,offer);var onSuccessCbFn=function(){log.debug([targetMid,"RTCSessionDescription",message.type,"Remote description set"]),pc.setOffer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.OFFER,targetMid),self._addIceCandidateFromQueue(targetMid),self._doAnswer(targetMid)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,offer:offer})};pc.setRemoteDescription(new RTCSessionDescription(offer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._candidateHandler=function(message){var targetMid=message.mid;if(!message.candidate&&!message.id)return void log.warn([targetMid,"RTCIceCandidate",null,"Received invalid ICE candidate message ->"],message);var canId="can-"+(new Date).getTime(),candidateType=message.candidate.split(" ")[7]||"",candidate=new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate,sdpMid:message.id});if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Received ICE candidate ->"],candidate),this._peerEndOfCandidatesCounter[targetMid]=this._peerEndOfCandidatesCounter[targetMid]||{},this._peerEndOfCandidatesCounter[targetMid].len=this._peerEndOfCandidatesCounter[targetMid].len||0,this._peerEndOfCandidatesCounter[targetMid].hasSet=!1,this._peerEndOfCandidatesCounter[targetMid].len++,this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.RECEIVED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!this._peerConnections[targetMid]||this._peerConnections[targetMid].signalingState===this.PEER_CONNECTION_STATE.CLOSED)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed.")),void this._signalingEndOfCandidates(targetMid);if(this._initOptions.filterCandidatesType[candidateType]){if(!this._hasMCU||!this._initOptions.forceTURN)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping received ICE candidate as it matches ICE candidate filtering flag ->"],candidate),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Dropping of processing ICE candidate as it matches ICE candidate filtering flag.")),void this._signalingEndOfCandidates(targetMid);log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Not dropping received ICE candidate as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured ->"],candidate)}this._peerConnections[targetMid].remoteDescription&&this._peerConnections[targetMid].remoteDescription.sdp&&this._peerConnections[targetMid].localDescription&&this._peerConnections[targetMid].localDescription.sdp?this._addIceCandidate(targetMid,canId,candidate):this._addIceCandidateToQueue(targetMid,canId,candidate),this._signalingEndOfCandidates(targetMid),this._gatheredCandidates[targetMid]||(this._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),this._gatheredCandidates[targetMid].receiving[candidateType].push({sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate})},Skylink.prototype._answerHandler=function(message){var self=this,targetMid=message.mid;log.log([targetMid,null,message.type,"Received answer from peer. Session description:"],clone(message));var pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for answer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}var answer={type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],answer),answer.sdp=self._removeSDPFilteredCandidates(targetMid,answer),answer.sdp=self._setSDPCodec(targetMid,answer),answer.sdp=self._setSDPBitrate(targetMid,answer),answer.sdp=self._setSDPCodecParams(targetMid,answer),answer.sdp=self._removeSDPCodecs(targetMid,answer),answer.sdp=self._removeSDPREMBPackets(targetMid,answer),answer.sdp=self._handleSDPConnectionSettings(targetMid,answer,"remote"),answer.sdp=self._removeSDPUnknownAptRtx(targetMid,answer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "have-local-offer" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.restart});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,answer);var onSuccessCbFn=function(){log.debug([targetMid,null,message.type,"Remote description set"]),pc.setAnswer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ANSWER,targetMid),self._addIceCandidateFromQueue(targetMid),self._peerMessagesStamps[targetMid]&&(self._peerMessagesStamps[targetMid].hasRestart=!1),self._dataChannels[targetMid]&&(-1===pc.remoteDescription.sdp.indexOf("m=application")||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,answer:answer})};pc.setRemoteDescription(new RTCSessionDescription(answer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=(agentVer||"").split("."),partsB=(requiredVer||"").split("."),i=0;i0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for sendStream() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream)):"function"==typeof callback&&callback(null,stream)};if(!("object"==typeof options&&null!==options||AdapterJS&&AdapterJS.WebRTCPlugin&&AdapterJS.WebRTCPlugin.plugin&&["function","object"].indexOf(typeof options)>-1)){var invalidOptionsError="Provided stream settings is invalid";return log.error(invalidOptionsError,options),void("function"==typeof callback&&callback(new Error(invalidOptionsError),null))}if(self._inRoom||log.warn("There are no peers to send stream to as not in room!"),"edge"===AdapterJS.webrtcDetectedBrowser){var edgeNotSupportError="Edge browser currently does not support renegotiation.";return log.error(edgeNotSupportError,options),void("function"==typeof callback&&callback(new Error(edgeNotSupportError),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0&&(useMediaSource=enableAudioArr)}else enableAudio&&"object"==typeof enableAudio?enableAudio.sourceId&&enableAudio.mediaSource||(enableAudioSettings={usedtx:"boolean"==typeof enableAudio.usedtx?enableAudio.usedtx:null,useinbandfec:"boolean"==typeof enableAudio.useinbandfec?enableAudio.useinbandfec:null,stereo:!0===enableAudio.stereo,echoCancellation:!1!==enableAudio.echoCancellation,deviceId:enableAudio.deviceId}):!0===enableAudio?enableAudioSettings=!0===enableAudio&&{usedtx:null,useinbandfec:null,stereo:!1,echoCancellation:!0,deviceId:null}:"function"==typeof enableAudio&&(callback=enableAudio,enableAudio=!1);if(mediaSource&&"string"==typeof mediaSource||mediaSource&&"object"==typeof mediaSource&&mediaSource.sourceId&&mediaSource.mediaSource)checkIfSourceExistsFn("object"==typeof mediaSource?mediaSource.mediaSource:mediaSource)&&(useMediaSource=["object"==typeof mediaSource?mediaSource.mediaSource:mediaSource]),useMediaSourceId="object"==typeof mediaSource?mediaSource.sourceId:null;else if(Array.isArray(mediaSource)){for(var mediaSourceArr=[],i=0;i0&&(useMediaSource=mediaSourceArr)}else"function"==typeof mediaSource&&(callback=mediaSource);useMediaSource.indexOf("audio")>-1&&-1===useMediaSource.indexOf("tab")&&(useMediaSource.splice(useMediaSource.indexOf("audio"),1),0===useMediaSource.length&&(useMediaSource=[self.MEDIA_SOURCE.SCREEN])),self._throttle(function(runFn){if(runFn){var settings={settings:{audio:enableAudioSettings,video:{screenshare:!0,exactConstraints:!1}},getUserMediaSettings:{audio:!1,video:{mediaSource:useMediaSource}}};"plugin"===AdapterJS.webrtcDetectedType&&useMediaSourceId&&(settings.getUserMediaSettings.video.optional=[{screenId:useMediaSourceId}]);var mediaAccessSuccessFn=function(stream){self.off("mediaAccessError",mediaAccessErrorFn),self._inRoom?(self._trigger("incomingStream",self._user.sid,stream,!0,self.getPeerInfo(),!0,stream.id||stream.label),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0),Object.keys(self._peerConnections).length>0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for shareScreen() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream)):"function"==typeof callback&&callback(null,stream)},mediaAccessErrorFn=function(error){self.off("mediaAccessSuccess",mediaAccessSuccessFn),"function"==typeof callback&&callback(error,null)};self.once("mediaAccessSuccess",mediaAccessSuccessFn,function(stream,isScreensharing){return isScreensharing}),self.once("mediaAccessError",mediaAccessErrorFn,function(error,isScreensharing){return isScreensharing});var getUserMediaAudioSettings=!!enableAudioSettings&&{echoCancellation:enableAudioSettings.echoCancellation};try{var hasDefaultAudioTrack=!1;enableAudioSettings&&("firefox"===AdapterJS.webrtcDetectedBrowser?(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio=getUserMediaAudioSettings):useMediaSource.indexOf("audio")>-1&&useMediaSource.indexOf("tab")>-1&&(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio={}));var onSuccessCbFn=function(stream){if(hasDefaultAudioTrack||!enableAudioSettings)return void self._onStreamAccessSuccess(stream,settings,!0,!1);settings.getUserMediaSettings.audio=getUserMediaAudioSettings;var onAudioSuccessCbFn=function(audioStream){try{audioStream.addTrack(stream.getVideoTracks()[0]),self.once("mediaAccessSuccess",function(){self._streams.screenshare.streamClone=stream},function(stream,isScreensharing){return isScreensharing}),self._onStreamAccessSuccess(audioStream,settings,!0,!1)}catch(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)}},onAudioErrorCbFn=function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)};navigator.getUserMedia({audio:getUserMediaAudioSettings},onAudioSuccessCbFn,onAudioErrorCbFn)},onErrorCbFn=function(error){self._onStreamAccessError(error,settings,!0,!1)};if("function"!=typeof(AdapterJS||{}).webRTCReady)return onErrorCbFn(new Error("Failed to call getUserMedia() as AdapterJS is not yet loaded!"));AdapterJS.webRTCReady(function(){navigator.getUserMedia(settings.getUserMediaSettings,onSuccessCbFn,onErrorCbFn)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._initOptions.throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._initOptions.throttleIntervals.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._initOptions.throttleIntervals.shareScreen)},Skylink.prototype.stopScreen=function(){this._streams.screenshare&&(this._stopStreams({screenshare:!0}),this._inRoom&&(this._streams.userMedia&&this._streams.userMedia.stream&&(this._trigger("incomingStream",this._user.sid,this._streams.userMedia.stream,!0,this.getPeerInfo(),!1,this._streams.userMedia.stream.id||this._streams.userMedia.stream.label),this._trigger("peerUpdated",this._user.sid,this.getPeerInfo(),!0)),this._refreshPeerConnection(Object.keys(this._peerConnections),{},!1)))},Skylink.prototype.getStreamSources=function(callback){var outputSources={audio:{input:[],output:[]},video:{input:[]}};if("function"!=typeof callback)return log.error("Please provide the callback.");var sourcesListFn=function(sources){sources.forEach(function(sourceItem){var item={deviceId:sourceItem.deviceId||sourceItem.sourceId||"default",label:sourceItem.label,groupId:sourceItem.groupId||null};item.label=item.label||"Source for "+item.deviceId,["audio","audioinput"].indexOf(sourceItem.kind)>-1?outputSources.audio.input.push(item):["video","videoinput"].indexOf(sourceItem.kind)>-1?outputSources.video.input.push(item):"audiooutput"===sourceItem.kind&&outputSources.audio.output.push(item)}),callback(outputSources)}
-;navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.enumerateDevices?navigator.mediaDevices.enumerateDevices().then(sourcesListFn):window.MediaStreamTrack&&"function"==typeof MediaStreamTrack.getSources?MediaStreamTrack.getSources(sourcesListFn):sourcesListFn("function"==typeof navigator.getUserMedia?[{deviceId:"default",kind:"audioinput",label:"Default Audio Track"},{deviceId:"default",kind:"videoinput",label:"Default Video Track"}]:[])},Skylink.prototype.getScreenSources=function(callback){var outputSources={mediaSource:[],mediaSourceInput:[]};return"function"!=typeof callback?log.error("Please provide the callback."):navigator.userAgent.toLowerCase().indexOf("android")>-1?("chrome"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=59&&(outputSources.mediaSource=["screen"]),void callback(outputSources)):"plugin"===AdapterJS.webrtcDetectedType?void AdapterJS.webRTCReady(function(){if(AdapterJS.WebRTCPlugin.plugin&&AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable&&AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature&&(outputSources.mediaSource=["window","screen"],"function"==typeof AdapterJS.WebRTCPlugin.plugin.getScreensharingSources))return void AdapterJS.WebRTCPlugin.plugin.getScreensharingSources(function(sources){sources.forEach(sources,function(sourceItem){var item={sourceId:sourceItem.id||sourceItem.sourceId||"default",label:sourceItem.label,mediaSource:sourceItem.kind||"screen"};item.label=item.label||"Source for "+item.sourceId,outputSources.mediaSourceInput.push(item)}),callback(outputSources)});callback(outputSources)}):(("chrome"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=34||"firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=38||"opera"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=21)&&("opera"!==AdapterJS.webrtcDetectedBrowser||AdapterJS.extensionInfo&&AdapterJS.extensionInfo.opera&&AdapterJS.extensionInfo.opera.extensionId||log.warn("Please ensure that your application allows Opera screensharing!"),outputSources.mediaSource=["window","screen"],"chrome"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=52||"opera"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>=39?outputSources.mediaSource.push("tab","audio"):"firefox"===AdapterJS.webrtcDetectedBrowser&&outputSources.mediaSource.push("browser","camera","application")),void callback(outputSources))},Skylink.prototype._muteStreams=function(){var self=this,hasVideo=!1,hasAudio=!1,muteFn=function(stream){for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",self._streamsMutedSettings),{hasVideo:hasVideo,hasAudio:hasAudio}},Skylink.prototype._stopStreams=function(options){var self=this,stopFn=function(stream){var streamId=stream.id||stream.label;log.debug([null,"MediaStream",streamId,"Stopping Stream ->"],stream);try{for(var audioTracks=stream.getAudioTracks(),videoTracks=stream.getVideoTracks(),a=0;a",options)},Skylink.prototype._parseStreamSettings=function(options){var settings={settings:{audio:!1,video:!1},mutedSettings:{shouldAudioMuted:!1,shouldVideoMuted:!1},getUserMediaSettings:{audio:!1,video:!1}};return options.audio&&(settings.settings.audio={stereo:!1,exactConstraints:!!options.useExactConstraints,echoCancellation:!0},settings.getUserMediaSettings.audio={echoCancellation:!0},"object"==typeof options.audio&&("boolean"==typeof options.audio.stereo&&(settings.settings.audio.stereo=options.audio.stereo),"boolean"==typeof options.audio.useinbandfec&&(settings.settings.audio.useinbandfec=options.audio.useinbandfec),"boolean"==typeof options.audio.usedtx&&(settings.settings.audio.usedtx=options.audio.usedtx),"number"==typeof options.audio.maxplaybackrate&&options.audio.maxplaybackrate>=8e3&&options.audio.maxplaybackrate<=48e3&&(settings.settings.audio.maxplaybackrate=options.audio.maxplaybackrate),"boolean"==typeof options.audio.mute&&(settings.mutedSettings.shouldAudioMuted=options.audio.mute),"edge"!==AdapterJS.webrtcDetectedBrowser&&("boolean"==typeof options.audio.echoCancellation&&(settings.settings.audio.echoCancellation=options.audio.echoCancellation,settings.getUserMediaSettings.audio.echoCancellation=options.audio.echoCancellation),Array.isArray(options.audio.optional)&&(settings.settings.audio.optional=clone(options.audio.optional),settings.getUserMediaSettings.audio.optional=clone(options.audio.optional)),options.audio.deviceId&&"string"==typeof options.audio.deviceId&&"firefox"!==AdapterJS.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,settings.getUserMediaSettings.audio.deviceId=options.useExactConstraints?{exact:options.audio.deviceId}:{ideal:options.audio.deviceId}))),"edge"===AdapterJS.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio=!0)),options.video&&(settings.settings.video={resolution:clone(this.VIDEO_RESOLUTION.VGA),screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video={},"object"==typeof options.video?("boolean"==typeof options.video.mute&&(settings.mutedSettings.shouldVideoMuted=options.video.mute),Array.isArray(options.video.optional)&&(settings.settings.video.optional=clone(options.video.optional),settings.getUserMediaSettings.video.optional=clone(options.video.optional)),options.video.deviceId&&"string"==typeof options.video.deviceId&&"firefox"!==AdapterJS.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,settings.getUserMediaSettings.video.deviceId=options.useExactConstraints?{exact:options.video.deviceId}:{ideal:options.video.deviceId}),options.video.resolution&&"object"==typeof options.video.resolution&&((options.video.resolution.width&&"object"==typeof options.video.resolution.width||"number"==typeof options.video.resolution.width)&&(settings.settings.video.resolution.width=options.video.resolution.width),(options.video.resolution.height&&"object"==typeof options.video.resolution.height||"number"==typeof options.video.resolution.height)&&(settings.settings.video.resolution.height=options.video.resolution.height)),settings.getUserMediaSettings.video.width="object"==typeof settings.settings.video.resolution.width?settings.settings.video.resolution.width:options.useExactConstraints?{exact:settings.settings.video.resolution.width}:{max:settings.settings.video.resolution.width},settings.getUserMediaSettings.video.height="object"==typeof settings.settings.video.resolution.height?settings.settings.video.resolution.height:options.useExactConstraints?{exact:settings.settings.video.resolution.height}:{max:settings.settings.video.resolution.height},(options.video.frameRate&&"object"==typeof options.video.frameRate||"number"==typeof options.video.frameRate&&"plugin"!==AdapterJS.webrtcDetectedType)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}),options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&"plugin"===AdapterJS.webrtcDetectedType&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):settings.getUserMediaSettings.video={width:options.useExactConstraints?{exact:settings.settings.video.resolution.width}:{max:settings.settings.video.resolution.width},height:options.useExactConstraints?{exact:settings.settings.video.resolution.height}:{max:settings.settings.video.resolution.height}},"edge"===AdapterJS.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,streamHasEnded=!1;if(log.log([null,"MediaStream",streamId,"Has access to stream ->"],stream),!isScreenSharing&&self._streams.userMedia?self._stopStreams({userMedia:!0,screenshare:!1}):isScreenSharing&&self._streams.screenshare&&self._stopStreams({userMedia:!1,screenshare:!0}),self._streamsStoppedCbs[streamId]=function(){log.log([null,"MediaStream",streamId,"Stream has ended"]),streamHasEnded=!0,self._trigger("mediaAccessStopped",!!isScreenSharing,!!isAudioFallback,streamId),self._inRoom&&(log.debug([null,"MediaStream",streamId,"Sending Stream ended status to Peers"]),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.STREAM,mid:self._user.sid,rid:self._room.id,cid:self._key,streamId:streamId,settings:settings.settings,status:"ended"}),self._trigger("streamEnded",self._user.sid,self.getPeerInfo(),!0,!!isScreenSharing,streamId),isScreenSharing&&self._streams.screenshare&&self._streams.screenshare.stream&&(self._streams.screenshare.stream.id||self._streams.screenshare.stream.label)===streamId?self._streams.screenshare=null:!isScreenSharing&&self._streams.userMedia&&self._streams.userMedia.stream&&(self._streams.userMedia.stream.id||self._streams.userMedia.stream.label)===streamId&&(self._streams.userMedia=null))},["chrome","opera"].indexOf(AdapterJS.webrtcDetectedBrowser)>-1?(stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},isScreenSharing&&stream.getVideoTracks().length>0&&(stream.getVideoTracks()[0].onended=function(){setTimeout(function(){!streamHasEnded&&self._inRoom&&self.stopScreen()},350)})):"firefox"===AdapterJS.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._initOptions.audioFallback){log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0);var onAudioSuccessCbFn=function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},onAudioErrorCbFn=function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)};return void navigator.getUserMedia({audio:!0},onAudioSuccessCbFn,onAudioErrorCbFn)}log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this,streamId=self._peerConnections[targetMid]&&self._peerConnections[targetMid].remoteStreamId||stream.id||stream.label;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",streamId,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",streamId,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",streamId,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,streamId),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId];if(pc){var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)&&self._getSDPCommonSupports(peerId,pc.remoteDescription).video,offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPCommonSupports(peerId,pc.remoteDescription).audio;if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){if(!updatedStream||(!pc.localStreamId||updatedStream.id!==pc.localStreamId)){if("edge"!==AdapterJS.webrtcDetectedBrowser||self._initOptions.useEdgeWebRTC&&window.msRTCPeerConnection?pc.getLocalStreams().forEach(function(stream){pc.removeStream(stream)}):pc.getSenders().forEach(function(sender){pc.removeTrack(sender)}),!offerToReceiveAudio&&!offerToReceiveVideo)return;updatedStream&&("edge"!==AdapterJS.webrtcDetectedBrowser||self._initOptions.useEdgeWebRTC&&window.msRTCPeerConnection?pc.addStream(updatedStream):updatedStream.getTracks().forEach(function(track){"audio"===track.kind&&!offerToReceiveAudio||"video"===track.kind&&!offerToReceiveVideo||pc.addTrack(track,updatedStream)}),pc.localStreamId=updatedStream.id||updatedStream.label,pc.localStream=updatedStream)}};self._streams.screenshare&&self._streams.screenshare.stream?(log.debug([peerId,"MediaStream",null,"Sending screen"],self._streams.screenshare.stream),updateStreamFn(self._streams.screenshare.stream)):self._streams.userMedia&&self._streams.userMedia.stream?(log.debug([peerId,"MediaStream",null,"Sending stream"],self._streams.userMedia.stream),updateStreamFn(self._streams.userMedia.stream)):(log.warn([peerId,"MediaStream",null,"No media to send. Will be only receiving"]),updateStreamFn(null))}else log.warn([peerId,"MediaStream",null,"Not adding any stream as signalingState is closed"])}else log.warn([peerId,"MediaStream",self._mediaStream,"Not adding stream as peerconnection object does not exists"])}catch(error){(error.message||"").indexOf("already added")>-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){if(self._streamsSession[peerId][streamId]){var peerInfo=clone(self.getPeerInfo(peerId));peerInfo.settings.audio=clone(self._streamsSession[peerId][streamId].audio),peerInfo.settings.video=clone(self._streamsSession[peerId][streamId].video);var hasScreenshare=peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&!!peerInfo.settings.video.screenshare;self._streamsSession[peerId][streamId]=!1,self._trigger("streamEnded",peerId,peerInfo,!1,hasScreenshare,streamId)}};if(checkStreamId)renderEndedFn(checkStreamId);else if(self._peerConnections[peerId])for(var streamId in self._streamsSession[peerId])self._streamsSession[peerId].hasOwnProperty(streamId)&&self._streamsSession[peerId][streamId]&&renderEndedFn(streamId)},Skylink.prototype._setSDPCodecParams=function(targetMid,sessionDescription){var self=this,parseFn=function(type,codecName,samplingRate,settings){var mLine=sessionDescription.sdp.match(new RegExp("m="+type+" .*\r\n","gi"));if(Array.isArray(mLine)&&mLine.length>0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-1===cLineIndex?void log.error([targetMid,"RTCSessionDesription",sessionDescription.type,'Failed setting "'+type+'" bandwidth as c-line is missing.']):(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Limiting maximum sending "'+type+'" bandwidth ->'],bw),void sdpLines.splice(cLineIndex+1,0,"firefox"===window.webrtcDetectedBrowser?"b=TIAS:"+(1e3*bw*(window.webrtcDetectedVersion>52&&window.webrtcDetectedVersion<55?1e3:1)).toFixed(0):"b=AS:"+bw)):void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not limiting "'+type+'" bandwidth'])},bASAudioBw=this._streamsBandwidthSettings.bAS.audio,bASVideoBw=this._streamsBandwidthSettings.bAS.video,bASDataBw=this._streamsBandwidthSettings.bAS.data,googleXMinBw=this._streamsBandwidthSettings.googleX.min,googleXMaxBw=this._streamsBandwidthSettings.googleX.max;if(this._peerCustomConfigs[targetMid]&&(this._peerCustomConfigs[targetMid].bandwidth&&"object"==typeof this._peerCustomConfigs[targetMid].bandwidth&&("number"==typeof this._peerCustomConfigs[targetMid].bandwidth.audio&&(bASAudioBw=this._peerCustomConfigs[targetMid].bandwidth.audio),"number"==typeof this._peerCustomConfigs[targetMid].bandwidth.video&&(bASVideoBw=this._peerCustomConfigs[targetMid].bandwidth.video),"number"==typeof this._peerCustomConfigs[targetMid].bandwidth.data&&(bASDataBw=this._peerCustomConfigs[targetMid].bandwidth.data)),this._peerCustomConfigs[targetMid].googleXBandwidth&&"object"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth&&("number"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth.min&&(googleXMinBw=this._peerCustomConfigs[targetMid].googleXBandwidth.min),"number"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth.max&&(googleXMaxBw=this._peerCustomConfigs[targetMid].googleXBandwidth.max))),parseFn("audio",bASAudioBw),parseFn("video",bASVideoBw),parseFn("data",bASDataBw),"number"==typeof googleXMinBw||"number"==typeof googleXMaxBw){for(var codec=null,codecRtpMapLineIndex=-1,codecFmtpLineIndex=-1,j=0;j-1){var xGoogleParams="";"number"==typeof googleXMinBw&&(xGoogleParams+="x-google-min-bitrate="+googleXMinBw+";"),"number"==typeof googleXMaxBw&&(xGoogleParams+="x-google-max-bitrate="+googleXMaxBw+";"),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Limiting x-google-bitrate ->"],xGoogleParams),codecFmtpLineIndex>-1?sdpLines[codecFmtpLineIndex]+=(sdpLines[codecFmtpLineIndex].split(" ")[1]?";":"")+xGoogleParams:sdpLines.splice(codecRtpMapLineIndex+1,0,"a=fmtp:"+codec+" "+xGoogleParams)}}return sdpLines.join("\r\n")},Skylink.prototype._setSDPCodec=function(targetMid,sessionDescription,overrideSettings){var self=this,parseFn=function(type,codecSettings){var codec="object"==typeof codecSettings?codecSettings.codec:codecSettings,samplingRate="object"==typeof codecSettings?codecSettings.samplingRate:null,channels="object"==typeof codecSettings?codecSettings.channels:null;if(codec===self["audio"===type?"AUDIO_CODEC":"VIDEO_CODEC"].AUTO)return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not preferring any codec for "'+type+'" streaming. Using browser selection.']);var mLine=sessionDescription.sdp.match(new RegExp("m="+type+" .*\r\n","gi"));if(!(Array.isArray(mLine)&&mLine.length>0))return void log.error([targetMid,"RTCSessionDesription",sessionDescription.type,'Not preferring any codec for "'+type+'" streaming as m= line is not found.']);var setLineFn=function(codecsList,isSROk,isChnlsOk){if(Array.isArray(codecsList)&&codecsList.length>0){isSROk||(samplingRate=null),isChnlsOk||(channels=null),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Preferring "'+codec+'" (samplingRate: '+(samplingRate||"n/a")+", channels: "+(channels||"n/a")+') for "'+type+'" streaming.']);var line=mLine[0],lineParts=line.replace("\r\n","").split(" ");line=lineParts[0]+" "+lineParts[1]+" "+lineParts[2]+" ",lineParts.splice(0,3);for(var i=0;i0?(lineParts.splice(j,1),j--):sessionDescription.sdp.match(new RegExp("a=rtpmap:"+lineParts[j]+" "+codec+"/.*\r\n","gi"))&&(line+=lineParts[j]+" ",lineParts.splice(j,1),j--);return line+=lineParts.join(" ")+"\r\n",sessionDescription.sdp=sessionDescription.sdp.replace(mLine[0],line),!0}};if(samplingRate){if("audio"===type&&channels&&setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/"+samplingRate+(1===channels?"[/1]*":"/"+channels)+"\r\n","gi")),!0,!0))return;if(setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/"+samplingRate+"[/]*.*\r\n","gi")),!0))return}"audio"===type&&channels&&setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/.*/"+channels+"\r\n","gi")),!1,!0)||setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/.*\r\n","gi")))};return parseFn("audio",overrideSettings?overrideSettings.audio:self._initOptions.audioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._initOptions.videoCodec),sessionDescription.sdp},Skylink.prototype._removeSDPFirefoxH264Pref=function(targetMid,sessionDescription){return log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing Firefox experimental H264 flag to ensure interopability reliability"]),sessionDescription.sdp.replace(/a=fmtp:0 profile-level-id=0x42e00c;packetization-mode=1\r\n/g,"")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var mediaLines=(sessionDescription.sdp.split("\r\n"),sessionDescription.sdp.split("m=")),formatRtx=function(str){return(str.match(/a=rtpmap:.*\ rtx\/.*\r\n/gi)||[]).forEach(function(line){var payload=(line.split("a=rtpmap:")[1]||"").split(" ")[0]||"",fmtpLine=(str.match(new RegExp("a=fmtp:"+payload+" .*\r\n","gi"))||[])[0];if(!fmtpLine)return void(str=str.replace(new RegExp(line,"g"),""));var codecPayload=(fmtpLine.split(" apt=")[1]||"").replace(/\r\n/gi,"");str.match(new RegExp("a=rtpmap:"+codecPayload+" .*\r\n","gi"))||(str=str.replace(new RegExp(line,"g"),""),str=str.replace(new RegExp(fmtpLine,"g"),""))}),str},formatFmtpRtcpFb=function(str){return(str.match(/a=(fmtp|rtcp-fb):.*\ rtx\/.*\r\n/gi)||[]).forEach(function(line){var payload=(line.split("a="+(line.indexOf("rtcp")>0?"rtcp-fb":"fmtp"))[1]||"").split(" ")[0]||"";str.match(new RegExp("a=rtpmap:"+payload+" .*\r\n","gi"))||(str=str.replace(new RegExp(line,"g"),""))}),str},m=0;m0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}
-sessionDescription.sdp=sdpLines.join("\r\n")}};return this._initOptions.disableVideoFecCodecs&&(this._hasMCU?log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "ulpfec" or "red" codecs as connected to MCU to prevent connectivity issues.']):(parseFn("video","red"),parseFn("video","ulpfec"))),this._initOptions.disableComfortNoiseCodec&&audioSettings&&"object"==typeof audioSettings&&audioSettings.stereo&&parseFn("audio","CN"),"edge"===window.webrtcDetectedBrowser&&"edge"!==(((this._peerInformations[targetMid]||{}).agent||{}).name||"unknown").name&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=rtcp-fb:.*\ x-message\ .*\r\n/gi,"")),sessionDescription.sdp},Skylink.prototype._removeSDPREMBPackets=function(targetMid,sessionDescription){return this._initOptions.disableREMB?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing REMB packets."]),sessionDescription.sdp.replace(/a=rtcp-fb:\d+ goog-remb\r\n/g,"")):sessionDescription.sdp},Skylink.prototype._getSDPSelectedCodec=function(targetMid,sessionDescription,type,beSilentOnLogs){var codecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index&&0===mediaItem.indexOf(type+" ")){var codecs=(mediaItem.split("\r\n")[0]||"").split(" ");codecs.splice(0,3);for(var i=0;i-1)){codecInfo.name=parts[0],codecInfo.clockRate=parseInt(parts[1],10)||0,codecInfo.channels=parseInt(parts[2]||"1",10)||1,codecInfo.payloadType=parseInt(codecs[i],10),codecInfo.params="";(mediaItem.match(new RegExp("a=fmtp:"+codecs[i]+".*\r\n","gi"))||[]).forEach(function(paramItem){codecInfo.params+=paramItem.replace(new RegExp("a=fmtp:"+codecs[i],"gi"),"").replace(/\ /g,"").replace(/\r\n/g,"")});break}}}}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,'Parsing session description "'+type+'" codecs ->'],codecInfo),codecInfo):codecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._initOptions.forceTURN&&this._hasMCU?(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not filtering ICE candidates as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured"]),sessionDescription.sdp):(this._initOptions.filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._initOptions.filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._initOptions.filterCandidatesType.relay&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "relay" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*relay.*\r\n/g,"")),sessionDescription.sdp)},Skylink.prototype._getCodecsSupport=function(callback){var self=this;if(self._currentCodecSupport)return void callback(null);if(self._currentCodecSupport={audio:{},video:{}},"AppleWebKit"===AdapterJS.webrtcDetectedType)return self._currentCodecSupport.audio={opus:["48000/2"]},self._currentCodecSupport.video={h264:["48000"]},callback(null);try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints="plugin"!==AdapterJS.webrtcDetectedType?{offerToReceiveAudio:!0,offerToReceiveVideo:!0}:{mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}};try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){self._currentCodecSupport=self._getSDPCodecsSupport(null,offer),callback(null)},function(error){callback(error)},offerConstraints)}}catch(error){callback(error)}},Skylink.prototype._handleSDPConnectionSettings=function(targetMid,sessionDescription,direction){var self=this;if(!self._sdpSessions[targetMid])return sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;"remote"!==direction||self.getPeerInfo(targetMid).config.enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",mediaType=(self._peerInformations[targetMid],""),bundleLineIndex=-1,bundleLineMids=[],mLineIndex=-1,settings=clone(self._sdpSettings);if("MCU"===targetMid&&(settings.connection.audio=!0,settings.connection.video=!0,settings.connection.data=!0),self._hasMCU){var peerStreamSettings=clone(self.getPeerInfo(targetMid)).settings||{};settings.direction.audio.receive="MCU"!==targetMid&&!!peerStreamSettings.audio,settings.direction.audio.send="MCU"===targetMid,settings.direction.video.receive="MCU"!==targetMid&&!!peerStreamSettings.video,settings.direction.video.send="MCU"===targetMid}if("remote"===direction){var offerCodecs=self._getSDPCommonSupports(targetMid,sessionDescription);offerCodecs.audio||(settings.connection.audio=!1),offerCodecs.video||(settings.connection.video=!1)}self._sdpSessions[targetMid][direction].mLines=[],self._sdpSessions[targetMid][direction].bundleLine="",self._sdpSessions[targetMid][direction].connection={audio:null,video:null,data:null};for(var i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");else if(mediaType&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){if(-1===["audio","video"].indexOf(mediaType)){self._sdpSessions[targetMid][direction].connection.data=sdpLines[i];continue}if("local"===direction)settings.direction[mediaType].send&&!settings.direction[mediaType].receive?sdpLines[i]=sdpLines[i].indexOf("send")>-1?"a=sendonly":"a=inactive":!settings.direction[mediaType].send&&settings.direction[mediaType].receive?sdpLines[i]=sdpLines[i].indexOf("recv")>-1?"a=recvonly":"a=inactive":settings.direction[mediaType].send||settings.direction[mediaType].receive||(sdpLines[i]="a=inactive"),self._hasMCU||"firefox"===window.webrtcDetectedBrowser||"firefox"!==peerAgent||sessionDescription.type!==self.HANDSHAKE_PROGRESS.OFFER||"a=recvonly"!==sdpLines[i]||(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Overriding any original settings to receive only to send and receive to resolve chrome BUNDLE errors."]),sdpLines[i]="a=sendrecv",settings.direction[mediaType].send=!0,settings.direction[mediaType].receive=!0);else if(sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER){var localOfferRes=self._sdpSessions[targetMid].local.connection[mediaType];"a=sendonly"===localOfferRes?sdpLines[i]=-1===["a=inactive","a=recvonly"].indexOf(sdpLines[i])?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=-1===["a=inactive","a=sendonly"].indexOf(sdpLines[i])?"a=recvonly"===sdpLines[i]?"a=inactive":"a=sendonly":sdpLines[i]:"a=inactive"===localOfferRes&&(sdpLines[i]="a=inactive")}self._sdpSessions[targetMid][direction].connection[mediaType]=sdpLines[i]}}else sdpLines.splice(i,1),i--;(sdpLines[i]||"").replace(/\n|\r|\s|\ /gi,"")||(sdpLines.splice(i,1),i--)}return bundleLineIndex>-1&&(self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE?sdpLines[bundleLineIndex]="a=group:BUNDLE "+bundleLineMids.join(" "):self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.NONE&&sdpLines.splice(bundleLineIndex,1)),"edge"!==window.webrtcDetectedBrowser&&(sdpLines[sdpLines.length-1].replace(/\n|\r|\s/gi,"")?sdpLines.push(""):sdpLines[sdpLines.length-1]=""),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Handling connection lines and direction ->"],settings),sdpLines.join("\r\n")},Skylink.prototype._getSDPFingerprint=function(targetMid,sessionDescription,beSilentOnLogs){var fingerprint={fingerprint:null,fingerprintAlgorithm:null,derBase64:null};if(!sessionDescription||!sessionDescription.sdp)return fingerprint;for(var sdpLines=sessionDescription.sdp.split("\r\n"),i=0;i"],fingerprint),fingerprint},Skylink.prototype._renderSDPOutput=function(targetMid,sessionDescription){var self=this,localStream=null,localStreamId=null;if(sessionDescription&&sessionDescription.sdp){if(!self._peerConnections[targetMid])return sessionDescription.sdp;self._peerConnections[targetMid].localStream&&(localStream=self._peerConnections[targetMid].localStream,localStreamId=self._peerConnections[targetMid].localStreamId||self._peerConnections[targetMid].localStream.id);var sdpLines=(self._initOptions.enableIceTrickle?sessionDescription.sdp:sessionDescription.sdp.replace(/a=end-of-candidates\r\n/g,"")).split("\r\n");self._peerInformations[targetMid];if(localStream)for(var mediaType="",i=0;i0?ssrcParts=sdpLines[i].split(" msid:"):sdpLines[i].indexOf(" mslabel:")>0&&(ssrcParts=sdpLines[i].split(" mslabel:")),ssrcParts){var ssrcMsidParts=(ssrcParts[1]||"").split(" ");ssrcMsidParts[0]=localStreamId,ssrcParts[1]=ssrcMsidParts.join(" "),sdpLines[i].indexOf(" msid:")>0?sdpLines[i]=ssrcParts.join(" msid:"):sdpLines[i].indexOf(" mslabel:")>0&&(sdpLines[i]=ssrcParts.join(" mslabel:"))}}if(!self._initOptions.enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var e=0;e"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),log.info([targetMid,"RTCSessionDescription",sessionDescription.type,"Formatted output ->"],sdpLines.join("\r\n")),sdpLines.join("\r\n")}},Skylink.prototype._parseSDPMediaStreamIDs=function(targetMid,sessionDescription){if(this._peerConnections[targetMid]){if(!sessionDescription||!sessionDescription.sdp)return void(this._peerConnections[targetMid].remoteStreamId=null);for(var sdpLines=sessionDescription.sdp.split("\r\n"),currentStreamId=null,i=0;i0){currentStreamId=(sdpLines[i].split(" msid:")[1]||"").split(" ")[0];break}}currentStreamId?currentStreamId!==this._peerConnections[targetMid].remoteStreamId?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"New remote stream is sent ->"],currentStreamId),this._peerConnections[targetMid].remoteStreamId=currentStreamId):log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Same remote stream is sent ->"],currentStreamId):(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"No remote stream is sent."]),this._peerConnections[targetMid].remoteStreamId=null)}},Skylink.prototype._getSDPICECandidates=function(targetMid,sessionDescription,beSilentOnLogs){var candidates={host:[],srflx:[],relay:[]};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index){var sdpMid=((mediaItem.match(/a=mid:.*\r\n/gi)||[])[0]||"").replace(/a=mid:/gi,"").replace(/\r\n/,""),sdpMLineIndex=index-1;(mediaItem.match(/a=candidate:.*\r\n/gi)||[]).forEach(function(item){var canType=(item.split(" ")[7]||"host").replace(/\r\n/g,"");candidates[canType]=candidates[canType]||[],candidates[canType].push(new RTCIceCandidate({sdpMid:sdpMid,sdpMLineIndex:sdpMLineIndex,candidate:(item.split("a=")[1]||"").replace(/\r\n/g,"")}))})}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,"Parsing session description ICE candidates ->"],candidates),candidates):candidates},Skylink.prototype._getSDPMediaSSRC=function(targetMid,sessionDescription,beSilentOnLogs){var ssrcs={audio:0,video:0};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index){var mediaType=mediaItem.split(" ")[0]||"",ssrcLine=(mediaItem.match(/a=ssrc:.*\r\n/)||[])[0];"number"==typeof ssrcs[mediaType]&&ssrcLine&&(ssrcs[mediaType]=parseInt((ssrcLine.split("a=ssrc:")[1]||"").split(" ")[0],10)||0)}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,"Parsing session description media SSRCs ->"],ssrcs),ssrcs):ssrcs},Skylink.prototype._getSDPCodecsSupport=function(targetMid,sessionDescription){var codecs={audio:{},video:{}};if(!sessionDescription||!sessionDescription.sdp)return codecs;for(var sdpLines=sessionDescription.sdp.split("\r\n"),mediaType="",i=0;i-1)continue;codecs[mediaType][codec]=codecs[mediaType][codec]||[],-1===codecs[mediaType][codec].indexOf(info)&&codecs[mediaType][codec].push(info)}}else mediaType=(sdpLines[i].split("m=")[1]||"").split(" ")[0];return log.info([targetMid||null,"RTCSessionDescription",sessionDescription.type,"Parsed codecs support ->"],codecs),codecs},Skylink.prototype._getSDPCommonSupports=function(targetMid,sessionDescription){var self=this,offer={audio:!1,video:!1};if(!targetMid||!sessionDescription||!sessionDescription.sdp){if(offer.video=!(!self._currentCodecSupport.video.h264&&!self._currentCodecSupport.video.vp8),offer.audio=!!self._currentCodecSupport.audio.opus,targetMid){var peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"";AdapterJS.webrtcDetectedBrowser===peerAgent&&(offer.video=Object.keys(self._currentCodecSupport.video).length>0,offer.audio=Object.keys(self._currentCodecSupport.audio).length>0)}return offer}var remoteCodecs=self._getSDPCodecsSupport(targetMid,sessionDescription),localCodecs=self._currentCodecSupport;for(var ac in localCodecs.audio)if(localCodecs.audio.hasOwnProperty(ac)&&localCodecs.audio[ac]&&remoteCodecs.audio[ac]){offer.audio=!0;break}for(var vc in localCodecs.video)if(localCodecs.video.hasOwnProperty(vc)&&localCodecs.video[vc]&&remoteCodecs.video[vc]){offer.video=!0;break}return offer},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this);
\ No newline at end of file
+/*! skylinkjs - v0.6.30 - 2018-02-21 */
+!function(globals){"use strict";function Skylink(){this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._peerInformations={},this._user=null,this._userData="",this._peerPriorityWeight=0,this._autoIntroduce=!0,this._isPrivileged=!1,this._peerList=null,this._selectedRoom=null,this._roomLocked=!1,this._inRoom=!1,this._EVENTS={},this._onceEvents={},this._timestamp={socketMessage:null,shareScreen:null,refreshConnection:null,getUserMedia:null,lastRestart:null},this._socketSession={},this._socketMessageQueue=[],this._socketMessageTimeout=null,this._socketPorts={"http:":[80,3e3],"https:":[443,3443]},this._channelOpen=!1,this._signalingServer=null,this._signalingServerProtocol=window.location.protocol,this._signalingServerPort=null,this._socket=null,this._socketUseXDR=!1,this._enableIceRestart=!1,this._hasMCU=!1,this._path=null,this._readyState=null,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._streams={userMedia:null,screenshare:null},this._streamsDefaultSettings={userMedia:{audio:{stereo:!1},video:{resolution:{width:640,height:480},frameRate:50}},screenshare:{video:!0}},this._streamsMutedSettings={audioMuted:!1,videoMuted:!1},this._streamsBandwidthSettings={googleX:{},bAS:{}},this._streamsStoppedCbs={},this._streamsSession={},this._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},this._publishOnly=!1,this._parentId=null,this._recordings={},this._currentRecordingId=!1,this._recordingStartInterval=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType=this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._bandwidthAdjuster=null,this._peerConnStatus={},this._joinRoomManager={timestamp:0,socketsFn:[]},this._initOptions={}}!function(){Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,r=!{toString:null}.propertyIsEnumerable("toString"),e=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],o=e.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var c=[];for(var l in n)t.call(n,l)&&c.push(l);if(r)for(var p=0;o>p;p++)t.call(n,e[p])&&c.push(e[p]);return c}}())}(),function(){function t(t){return 10>t?"0"+t:t}Date.prototype.toISOString=function(){return this.getUTCFullYear()+"-"+t(this.getUTCMonth()+1)+"-"+t(this.getUTCDate())+"T"+t(this.getUTCHours())+":"+t(this.getUTCMinutes())+":"+t(this.getUTCSeconds())+"."+(this.getUTCMilliseconds()/1e3).toFixed(3).slice(2,5)+"Z"}}(),function(){"function"!=typeof Date.now&&(Date.now=function(){return(new Date).getTime()})}(),function(e,t){function n(e){var n=t[e];t[e]=function(e){return o(n(e))}}function a(t,n,a){return(a=this).attachEvent("on"+t,function(t){var t=t||e.event;t.preventDefault=t.preventDefault||function(){t.returnValue=!1},t.stopPropagation=t.stopPropagation||function(){t.cancelBubble=!0},n.call(a,t)})}function o(e,t){if(t=e.length)for(;t--;)e[t].addEventListener=a;else e.addEventListener=a;return e}e.addEventListener||(o([t,e]),"Element"in e?e.Element.prototype.addEventListener=a:(t.attachEvent("onreadystatechange",function(){o(t.all)}),n("getElementsByTagName"),n("getElementById"),n("createElement"),o(t.all)))}(window,document),function(){if("performance"in window==0&&(window.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in window.performance==0){var a=Date.now();performance.timing&&performance.timing.navigationStart&&(a=performance.timing.navigationStart),window.performance.now=function(){return Date.now()-a}}}(),window.BlobBuilder=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,Array.prototype.forEach||(Array.prototype.forEach=function(callback){var T,k;if(null==this)throw new TypeError("this is null or not defined");var O=Object(this),len=O.length>>>0;if("function"!=typeof callback)throw new TypeError(callback+" is not a function");for(arguments.length>1&&(T=arguments[1]),k=0;k"],error),void self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CREATE_ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))}self._dataChannels[peerId]?self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel.label===channelName&&(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING):(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING,self._dataChannels[peerId]={},log.debug([peerId,"RTCDataChannel",channelProp,"initializing main DataChannel"])),dataChannel.onerror=function(evt){var channelError=evt.error||evt;log.error([peerId,"RTCDataChannel",channelProp,"Datachannel has an exception ->"],channelError),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,channelError,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onbufferedamountlow=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel buffering data transfer low"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.BUFFERED_AMOUNT_LOW,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onmessage=function(event){self._processDataChannelData(event.data,peerId,channelName,channelType)};var onOpenHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has opened"]),dataChannel.bufferedAmountLowThreshold=bufferThreshold||0,self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.OPEN,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))};dataChannel.readyState===self.DATA_CHANNEL_STATE.OPEN?setTimeout(onOpenHandlerFn,1):(self._trigger("dataChannelState",dataChannel.readyState,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),dataChannel.onopen=onOpenHandlerFn);var onCloseHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has closed"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSED,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),self._peerConnections[peerId]&&self._peerConnections[peerId].remoteDescription&&self._peerConnections[peerId].remoteDescription.sdp&&(-1===self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")||self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application 0")>0)||channelType===self.DATA_CHANNEL_TYPE.MESSAGING&&setTimeout(function(){self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[peerId].localDescription&&self._peerConnections[peerId].localDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&(log.debug([peerId,"RTCDataChannel",channelProp,"Reviving Datachannel connection"]),self._createDataChannel(peerId,channelName,bufferThreshold,!0))},100)};if("firefox"===AdapterJS.webrtcDetectedBrowser){var hasTriggeredClose=!1,timeBlockAfterClosing=0;dataChannel.onclose=function(){hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())};var onFFClosed=setInterval(function(){dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSED||hasTriggeredClose||5===timeBlockAfterClosing?(clearInterval(onFFClosed),hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())):dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSING&&timeBlockAfterClosing++},1e3)}else dataChannel.onclose=onCloseHandlerFn;channelType===self.DATA_CHANNEL_TYPE.MESSAGING?self._dataChannels[peerId].main={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}:self._dataChannels[peerId][channelName]={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}},Skylink.prototype.refreshDatachannel=function(peerId){var self=this;if(self._dataChannels[peerId]&&self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel){var channelName=self._dataChannels[peerId].main.channelName,channelType=self._dataChannels[peerId].main.channelType,bufferThreshold=self._dataChannels[peerId].main.channel.bufferedAmountLowThreshold||0;channelType===self.DATA_CHANNEL_TYPE.MESSAGING&&setTimeout(function(){self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[peerId].localDescription&&self._peerConnections[peerId].localDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&(self._closeDataChannel(peerId,"main",!0),log.debug([peerId,"RTCDataChannel","main","Reviving Datachannel connection"]),self._createDataChannel(peerId,channelName,bufferThreshold,!0))},100)}else log.debug([peerId,"RTCDataChannel","Not a valid Datachannel connection"])},Skylink.prototype._getDataChannelBuffer=function(peerId,channelProp){if("object"==typeof peerId)return{bufferedAmountLow:"number"==typeof peerId.bufferedAmountLow?peerId.bufferedAmountLow:parseInt(peerId.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?peerId.bufferedAmountLowThreshold:parseInt(peerId.bufferedAmountLowThreshold,10)||0};if(!(this._dataChannels[peerId]&&this._dataChannels[peerId][channelProp]&&this._dataChannels[peerId][channelProp].channel))return{bufferedAmountLow:0,bufferedAmountLowThreshold:0};var channel=this._dataChannels[peerId][channelProp].channel;return{bufferedAmountLow:"number"==typeof channel.bufferedAmountLow?channel.bufferedAmountLow:parseInt(channel.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof channel.bufferedAmountLowThreshold?channel.bufferedAmountLowThreshold:parseInt(channel.bufferedAmountLowThreshold,10)||0}},Skylink.prototype._sendMessageToDataChannel=function(peerId,data,channelProp,doNotConvert){var self=this;if(channelProp&&channelProp!==peerId||(channelProp="main"),!("object"==typeof data&&data||data&&"string"==typeof data))return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping invalid data ->"],data);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Peer connection does not exists or is closed ->"],data);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Datachannel connection does not exists ->"],data);var channelName=self._dataChannels[peerId][channelProp].channelName,channelType=self._dataChannels[peerId][channelProp].channelType,readyState=self._dataChannels[peerId][channelProp].channel.readyState,messageType="object"==typeof data&&data.type===self._DC_PROTOCOL_TYPE.MESSAGE?self.DATA_CHANNEL_MESSAGE_ERROR.MESSAGE:self.DATA_CHANNEL_MESSAGE_ERROR.TRANSFER;if(readyState!==self.DATA_CHANNEL_STATE.OPEN){var notOpenError='Failed sending message as Datachannel connection state is not opened. Current readyState is "'+readyState+'"';throw log.error([peerId,"RTCDataChannel",channelProp,notOpenError+" ->"],data),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,new Error(notOpenError),channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),new Error(notOpenError)}try{doNotConvert||"object"!=typeof data?(log.debug([peerId,"RTCDataChannel",channelProp,"Sending data with size ->"],data.size||data.length||data.byteLength),self._dataChannels[peerId][channelProp].channel.send(data)):(log.debug([peerId,"RTCDataChannel",channelProp,'Sending "'+data.type+'" protocol message ->'],data),self._dataChannels[peerId][channelProp].channel.send(JSON.stringify(data)))}catch(error){throw log.error([peerId,"RTCDataChannel",channelProp,"Failed sending "+(doNotConvert||"object"!=typeof data?"data":'"'+data.type+'" protocol message')+" ->"],error),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,error,channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),error}},Skylink.prototype._closeDataChannel=function(peerId,channelProp,isCloseMainChannel){var self=this;if(!self._dataChannels[peerId])return void log.warn([peerId,"RTCDataChannel",channelProp||null,"Aborting closing Datachannels as Peer connection does not have Datachannel sessions"]);var closeFn=function(rChannelProp){var channelName=self._dataChannels[peerId][rChannelProp].channelName,channelType=self._dataChannels[peerId][rChannelProp].channelType;self._dataChannels[peerId][rChannelProp].readyState!==self.DATA_CHANNEL_STATE.CLOSED&&(log.debug([peerId,"RTCDataChannel",channelProp,"Closing Datachannel"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSING,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(peerId,rChannelProp)),self._dataChannels[peerId][rChannelProp].channel.close(),delete self._dataChannels[peerId][rChannelProp])};if(isCloseMainChannel)closeFn(channelProp);else if(channelProp&&"main"!==channelProp){if(!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Aborting closing Datachannel as it does not exists"]);closeFn(channelProp)}else{for(var channelNameProp in self._dataChannels)self._dataChannels[peerId].hasOwnProperty(channelNameProp)&&self._dataChannels[peerId][channelNameProp]&&closeFn(channelNameProp);delete self._dataChannels[peerId]}},Skylink.prototype._base64ToBlob=function(dataURL){for(var byteString=atob(dataURL),ab=new ArrayBuffer(byteString.length),ia=new Uint8Array(ab),j=0;jchunkSize){for(;blobByteSize-1>endCount;)endCount=startCount+chunkSize,chunksArray.push(blob.slice(startCount,endCount)),startCount+=chunkSize;blobByteSize-(startCount+1)>0&&chunksArray.push(blob.slice(startCount,blobByteSize-1))}else chunksArray.push(blob);return chunksArray},Skylink.prototype._chunkDataURL=function(dataURL,chunkSize){var outputStr=dataURL,dataURLArray=[],startCount=0,endCount=0,dataByteSize=dataURL.size||dataURL.length;if(dataByteSize>chunkSize){for(;dataByteSize-1>endCount;)endCount=startCount+chunkSize,dataURLArray.push(outputStr.slice(startCount,endCount)),startCount+=chunkSize;dataByteSize-(startCount+1)>0&&chunksArray.push(outputStr.slice(startCount,dataByteSize-1))}else dataURLArray.push(outputStr);return dataURLArray},Skylink.prototype.sendBlobData=function(data,timeout,targetPeerId,sendChunksAsBinary,callback){this._startDataTransfer(data,timeout,targetPeerId,sendChunksAsBinary,callback,"blob")},Skylink.prototype.sendURLData=function(data,timeout,targetPeerId,callback){this._startDataTransfer(data,timeout,targetPeerId,callback,null,"data")},Skylink.prototype.respondBlobRequest=Skylink.prototype.acceptDataTransfer=function(peerId,transferId,accept){var self=this;if("string"!=typeof transferId&&"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as data transfer ID or peer ID is not provided"]);if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as Peer does not have any Datachannel connections"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting accept data transfer as invalid transfer ID is provided"]);var channelProp="main",dataChannelStateCbFn=null;self._dataChannels[peerId][transferId]&&(channelProp=transferId),self.once("dataTransferState",function(){dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),delete self._dataTransfers[transferId],self._dataChannels[peerId]&&("main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),channelProp===transferId&&self._closeDataChannel(peerId,transferId))},function(state,evtTransferId,evtPeerId){return evtTransferId===transferId&&evtPeerId===peerId&&[self.DATA_TRANSFER_STATE.ERROR,self.DATA_TRANSFER_STATE.CANCEL,self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED,self.DATA_TRANSFER_STATE.USER_REJECTED].indexOf(state)>-1}),accept?(log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]),dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){log.error([peerId,"RTCDataChannel",channelProp,'Data transfer "'+transferId+'" has been terminated due to connection.']),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD,message:new Error("Data transfer terminated as Peer Datachannel connection closed abruptly.")})},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_STATE.MESSAGING:channelName===transferId)&&[self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED,self.DATA_CHANNEL_STATE.ERROR].indexOf(state)>-1:void self.off("dataChannelState",dataChannelStateCbFn)}),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:0},channelProp),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_STARTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)):(log.warn([peerId,"RTCDataChannel",transferId,"Rejected data transfer and data transfer request has been aborted"]),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:-1},channelProp),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_REJECTED,transferId,peerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as User has rejected data transfer request."),transferType:self.DATA_TRANSFER_TYPE.DOWNLOAD}))},Skylink.prototype.cancelBlobTransfer=Skylink.prototype.cancelDataTransfer=function(peerId,transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer ID is not provided"]);if(!peerId||"string"!=typeof peerId)return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as peer ID is not provided"]);if(!self._dataTransfers[transferId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as data transfer session does not exists."]);log.debug([peerId,"RTCDataChannel",transferId,"Canceling data transfer ..."]);var emitEventFn=function(peers,transferInfoPeerId){for(var i=0;i0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},"main"),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._sendMessageToDataChannel("MCU",{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},transferId),emitEventFn(Object.keys(self._dataTransfers[transferId].peers.main).concat(Object.keys(self._dataTransfers[transferId].peers[transferId])))}else{var channelProp="main";if(!self._dataChannels[peerId])return void log.error([peerId,"RTCDataChannel",transferId,"Aborting cancel data transfer as Peer does not have any Datachannel connections"]);self._dataChannels[peerId][transferId]&&(channelProp=transferId),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.CANCEL,sender:self._user.sid,content:"Peer cancelled download transfer",name:self._dataTransfers[transferId].name,ackN:0},channelProp),emitEventFn([peerId],peerId)}},Skylink.prototype.sendP2PMessage=function(message,targetPeerId){var listOfPeers=Object.keys(this._dataChannels),isPrivate=!1;if(Array.isArray(targetPeerId)?(listOfPeers=targetPeerId,isPrivate=!0):targetPeerId&&"string"==typeof targetPeerId&&(listOfPeers=[targetPeerId],isPrivate=!0),!this._inRoom||!this._user||!this._user.sid)return void log.error("Unable to send message as User is not in Room. ->",message);if(!this._initOptions.enableDataChannel)return void log.error("Unable to send message as User does not have Datachannel enabled. ->",message);for(var i=0;i-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeStreamingFn=function(error){log.error(error)};if(!this._inRoom||!this._user||!this._user.sid)return emitErrorBeforeStreamingFn("Unable to start data streaming as User is not in Room.");if(!this._initOptions.enableDataChannel)return emitErrorBeforeStreamingFn("Unable to start data streaming as User does not have Datachannel enabled.");if(0===listOfPeers.length)return emitErrorBeforeStreamingFn("Unable to start data streaming as there are no Peers to start session with.");if(self._hasMCU)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature is current not supported by MCU yet.");if(!self._initOptions.enableSimultaneousTransfers)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature requires simultaneous data transfers to be enabled");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},listenToPeerFn=function(peerId,channelProp){var hasStarted=!1;sessions[peerId]=channelProp,self.once("dataStreamState",function(){},function(state,evtTransferId,evtPeerId,evtSessionInfo){if(evtTransferId===transferId&&evtPeerId===peerId){evtSessionInfo.chunk;return delete clone(evtSessionInfo).chunk,state===self.DATA_STREAM_STATE.SENDING_STARTED?void(hasStarted=!0):hasStarted&&[self.DATA_STREAM_STATE.ERROR,self.DATA_STREAM_STATE.SENDING_STOPPED].indexOf(state)>-1?(channelProp===transferId&&self._closeDataChannel(peerId,transferId),self._dataStreams[transferId]&&self._dataStreams[transferId].sessions[peerId]&&(delete self._dataStreams[transferId].sessions[peerId],0===Object.keys(self._dataStreams[transferId].sessions).length&&delete self._dataStreams[transferId]),!0):void 0}})},i=0;i-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE)};if(peersNonInterop.length>0)if(self._hasMCU)waitForChannelOpenFn("MCU",peersNonInterop);else for(var pni=0;pni0)if(self._hasMCU)startDataSessionFn("MCU","main",peersInterop);else for(var pi=0;piself._CHUNK_DATAURL_SIZE:updatedDataChunk.length>self._BINARY_FILE_SIZE)return void log.error("Failed streaming data chunk as data chunk exceeds maximum chunk limit.");var sessionInfo={chunk:updatedDataChunk,chunkSize:updatedDataChunk.size||updatedDataChunk.length||updatedDataChunk.byteLength,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){var onSendDataFn=function(buffer){self._sendMessageToDataChannel(peerId,buffer,channelProp,!0);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype.stopStreamingData=function(transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error("Failed streaming data chunk as stream session ID is not provided.");if(!(self._inRoom&&self._user&&self._user.sid))return void log.error("Failed streaming data chunk as User is not in the Room.");if(!self._dataStreams[transferId])return void log.error("Failed stopping data streaming session as it does not exists.");if(!self._dataStreams[transferId].isUpload)return void log.error("Failed stopping data streaming session as it is not sending.");if(self._hasMCU)return void log.error("Failed stopping data streaming session as MCU does not support this feature yet.");var sessionInfo={chunk:null,chunkSize:0,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:transferId,size:0,originalSize:0,dataType:"fastBinaryStop",mimeType:null,chunkType:self._dataStreams[transferId].sessionChunkType,chunkSize:0,timeout:0,isPrivate:self._dataStreams[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype._startDataTransfer=function(data,timeout,targetPeerId,sendChunksAsBinary,callback,sessionType){var self=this,transferId=(self._user?self._user.sid:"")+"_"+(new Date).getTime(),transferErrors={},transferCompleted=[],chunks=[],listOfPeers=Object.keys(self._peerConnections),sessionChunkType="string",transferInfo={name:null,size:null,chunkSize:null,chunkType:null,dataType:null,mimeType:null,direction:self.DATA_TRANSFER_TYPE.UPLOAD,timeout:60,isPrivate:!1,percentage:0};"number"==typeof timeout?transferInfo.timeout=timeout:Array.isArray(timeout)?listOfPeers=timeout:timeout&&"string"==typeof timeout?listOfPeers=[timeout]:timeout&&"boolean"==typeof timeout?sessionChunkType="binary":"function"==typeof timeout&&(callback=timeout),Array.isArray(targetPeerId)?listOfPeers=targetPeerId:targetPeerId&&"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:targetPeerId&&"boolean"==typeof targetPeerId?sessionChunkType="binary":"function"==typeof targetPeerId&&(callback=targetPeerId),sendChunksAsBinary&&"boolean"==typeof sendChunksAsBinary?sessionChunkType="binary":"function"==typeof sendChunksAsBinary&&(callback=sendChunksAsBinary),listOfPeers.indexOf("MCU")>-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeDataTransferFn=function(error){if(log.error(error),"function"==typeof callback){var transferErrors={};if(0===listOfPeers.length)transferErrors.self=new Error(error);else for(var i=0;i0){var bsChunkSize="firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_CHUNK_FILE_SIZE:self._CHUNK_FILE_SIZE,bsChunks=self._chunkBlobData(new Blob(chunks),bsChunkSize);self._dataTransfers[transferId].enforceBSInfo={chunkSize:4*Math.ceil(bsChunkSize/3),chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,size:4*Math.ceil(transferInfo.originalSize/3),chunks:bsChunks}}}for(var completeFn=function(peerId,error){transferCompleted.indexOf(peerId)>-1||(log.debug([peerId,"RTCDataChannel",transferId,"Data transfer result. Is errors present? ->"],error),transferCompleted.push(peerId),error&&(transferErrors[peerId]=new Error(error)),listOfPeers.length===transferCompleted.length&&(log.log([null,"RTCDataChannel",transferId,"Data transfer request completed"]),"function"==typeof callback&&(Object.keys(transferErrors).length>0?callback({transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),transferErrors:transferErrors,listOfPeers:listOfPeers},null):callback(null,{transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),listOfPeers:listOfPeers}))))},i=0;i0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,"main",Object.keys(self._dataTransfers[transferId].peers.main)),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,transferId,Object.keys(self._dataTransfers[transferId].peers[transferId])))},Skylink.prototype._startDataTransferToPeer=function(transferId,peerId,callback,channelProp,targetPeers){var self=this,peerConnectionStateCbFn=null,dataChannelStateCbFn=null,emitEventFn=function(cb){for(var peers=targetPeers||[peerId],i=0;i-1&&(log.warn([peerId,"RTCDataChannel",transferId,"Binary data chunks transfer is not yet supported with Peer connecting from Android, iOS and C++ SDK. Fallbacking to binary string data chunks transfer."]),size=self._dataTransfers[transferId].enforceBSInfo.size,chunkSize=self._dataTransfers[transferId].enforceBSInfo.chunkSize,chunkType="string"),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:self._dataTransfers[transferId].name,size:size,originalSize:self._dataTransfers[transferId].originalSize,dataType:self._dataTransfers[transferId].sessionType,mimeType:self._dataTransfers[transferId].mimeType,chunkType:chunkType,chunkSize:chunkSize,timeout:self._dataTransfers[transferId].timeout,isPrivate:self._dataTransfers[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp),emitEventFn(function(evtPeerId){self._trigger("incomingDataRequest",transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_UPLOAD_REQUEST,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)})};if("MCU"!==peerId){var dataTransferStateCbFn=function(state,evtTransferId,evtPeerId,transferInfo,error){peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],callback(peerId,state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?null:error.message.message||error.message.toString()),delete self._dataTransfers[transferId].sessions[peerId],self._hasMCU&&0===Object.keys(self._dataTransfers[transferId].peers.main).length&&self._dataChannels.MCU&&self._dataChannels.MCU.main?self._dataChannels.MCU.main.transferId=null:"main"===channelProp&&self._dataChannels[peerId]&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),0===Object.keys(self._dataTransfers[transferId].sessions).length&&delete self._dataTransfers[transferId]};self.once("dataTransferState",dataTransferStateCbFn,function(state,evtTransferId,evtPeerId){return self._dataTransfers[transferId]&&(self._hasMCU?self._dataTransfers[transferId].peers.main[peerId]||self._dataTransfers[transferId].peers[transferId][peerId]:self._dataTransfers[transferId].sessions[peerId])?evtTransferId===transferId&&evtPeerId===peerId&&[self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,self.DATA_TRANSFER_STATE.ERROR,self.DATA_TRANSFER_STATE.CANCEL,self.DATA_TRANSFER_STATE.REJECTED].indexOf(state)>-1:(dataTransferStateCbFn&&self.off("dataTransferState",dataTransferStateCbFn),peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),void(dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn)))})}if(!self._peerConnections[peerId])return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer connection does not exists.");if(!self._peerInformations[peerId])return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer connection does not exists.");if(self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer connection is not stable.");if(!self._dataTransfers[transferId])return void returnErrorBeforeTransferFn("Unable to start data transfer as data transfer session is not in order.");if(!self._dataChannels[peerId]||!self._dataChannels[peerId].main)return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel connection does not exists.");if(self._dataChannels[peerId].main.channel.readyState!==self.DATA_CHANNEL_STATE.OPEN)return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel connection is not opened.");var streamId=self._dataChannels[peerId].main.streamId;if(streamId&&"main"===channelProp&&self._dataStreams[streamId]&&("string"===self._dataStreams[streamId].sessionChunkType&&("string"===self._dataTransfers[transferId].sessionChunkType||self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1)||"binary"===self._dataStreams[streamId].sessionChunkType&&"binary"===self._dataStreams[streamId].sessionChunkType&&-1===self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)))return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel currently has an active "+self._dataStreams[streamId].sessionChunkType+" data streaming session.");var protocolVer=(self._peerInformations[peerId].agent||{}).DTProtocolVersion||"0.1.0",requireInterop=self._isLowerThanVersion(protocolVer,"0.1.2")||!self._initOptions.enableSimultaneousTransfers;return self._isLowerThanVersion(protocolVer,"0.1.2")&&"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer do not support DATA_URL type of data transfers"):"MCU"!==peerId&&self._hasMCU?(channelProp=requireInterop?"main":transferId,peerConnectionStateCbFn=function(){returnErrorBeforeTransferFn("Data transfer terminated as Peer connection is not stable.")},self.once("peerConnectionState",peerConnectionStateCbFn,function(state,evtPeerId){return self._dataTransfers[transferId]?state!==self.PEER_CONNECTION_STATE.STABLE&&evtPeerId===peerId:void self.off("peerConnectionState",peerConnectionStateCbFn)}),requireInterop):(requireInterop||"main"===channelProp)&&self._dataChannels[peerId].main.transferId?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel has a data transfer in-progress."):(self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0},dataChannelStateCbFn=function(state,evtPeerId,error){self._dataTransfers[transferId].sessions[peerId].ackN>=self._dataTransfers[transferId].chunks.length-1||returnErrorBeforeTransferFn(error?error.message||error.toString():"Data transfer terminated as Peer Datachannel connection closed abruptly.")},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void self.off("dataChannelState",dataChannelStateCbFn);if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId))return state===self.DATA_CHANNEL_STATE.OPEN&&"main"!==channelProp&&channelName===transferId?(self._dataChannels[peerId][channelProp].transferId=transferId,sendWRQFn(),!1):[self.DATA_CHANNEL_STATE.CREATE_ERROR,self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSING,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(channelProp="main",self._dataChannels[peerId].main.transferId=transferId,sendWRQFn()):(channelProp=transferId,self._createDataChannel(peerId,transferId,"data"===self._dataTransfers[transferId].sessionType?self._CHUNK_DATAURL_SIZE:"string"===self._dataTransfers[transferId].sessionChunkType?"firefox"===AdapterJS.webrtcDetectedBrowser?16384:65546:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE))))},Skylink.prototype._getTransferInfo=function(transferId,peerId,returnDataProp,hidePercentage,returnDataAtStart){if(!this._dataTransfers[transferId])return{};var transferInfo={name:this._dataTransfers[transferId].name,size:this._dataTransfers[transferId].size,dataType:this._dataTransfers[transferId].dataType||this.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:this._dataTransfers[transferId].mimeType||null,chunkSize:this._dataTransfers[transferId].chunkSize,chunkType:this._dataTransfers[transferId].chunkType,timeout:this._dataTransfers[transferId].timeout,isPrivate:this._dataTransfers[transferId].isPrivate,direction:this._dataTransfers[transferId].direction};if(this._dataTransfers[transferId].originalSize?transferInfo.size=this._dataTransfers[transferId].originalSize:this._dataTransfers[transferId].chunkType===this.DATA_TRANSFER_DATA_TYPE.BINARY_STRING&&(transferInfo.size=Math.ceil(3*transferInfo.size/4)),!hidePercentage){if(transferInfo.percentage=0,!this._dataTransfers[transferId].sessions[peerId])return returnDataProp&&(transferInfo.data=null),transferInfo;if(this._dataTransfers[transferId].direction===this.DATA_TRANSFER_TYPE.DOWNLOAD)this._dataTransfers[transferId].sessions[peerId].receivedSize===this._dataTransfers[transferId].sessions[peerId].size?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].receivedSize/this._dataTransfers[transferId].size*100).toFixed(2),10);else{var chunksLength=this._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?this._dataTransfers[transferId].enforceBSInfo.chunks.length:this._dataTransfers[transferId].chunks.length;this._dataTransfers[transferId].sessions[peerId].ackN===chunksLength?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].ackN/chunksLength*100).toFixed(2),10)}returnDataProp&&("number"!=typeof returnDataAtStart?100===transferInfo.percentage?transferInfo.data=this._getTransferData(transferId):transferInfo.data=null:(transferInfo.percentage=returnDataAtStart,
+0===returnDataAtStart&&(transferInfo.data=this._getTransferData(transferId))))}return transferInfo},Skylink.prototype._getTransferData=function(transferId){if(!this._dataTransfers[transferId])return null;if(this._dataTransfers[transferId].dataType===this.DATA_TRANSFER_SESSION_TYPE.BLOB){var mimeType={name:this._dataTransfers[transferId].name};return this._dataTransfers[transferId].mimeType&&(mimeType.type=this._dataTransfers[transferId].mimeType),new Blob(this._dataTransfers[transferId].chunks,mimeType)}return this._dataTransfers[transferId].chunks.join("")},Skylink.prototype._handleDataTransferTimeoutForPeer=function(transferId,peerId,setPeerTO){var self=this;if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer does not exists for Peer. Ignoring timeout."]);log.debug([peerId,"RTCDataChannel",transferId,"Clearing data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer&&clearTimeout(self._dataTransfers[transferId].sessions[peerId].timer),self._dataTransfers[transferId].sessions[peerId].timer=null,setPeerTO&&(log.debug([peerId,"RTCDataChannel",transferId,"Setting data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer=setTimeout(function(){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer already ended for Peer. Ignoring expired timeout."]);if(!self._user||!self._user.sid)return void log.debug([peerId,"RTCDataChannel",transferId,"User is not in Room. Ignoring expired timeout."]);if(!self._dataChannels[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Datachannel connection does not exists. Ignoring expired timeout."]);log.error([peerId,"RTCDataChannel",transferId,"Data transfer response has timed out."]);var emitEventFn=function(cb){if("MCU"===peerId){for(var broadcastedPeers=[self._dataTransfers[transferId].peers.main,self._dataTransfers[transferId].peers[transferId]],i=0;i"],rawData);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping data received from Peer as Datachannel connection is not present ->"],rawData);if("string"==typeof rawData)try{var protocolData=JSON.parse(rawData);if(isStreamChunk=!1,log.debug([peerId,"RTCDataChannel",channelProp,'Received protocol "'+protocolData.type+'" message ->'],protocolData),[self._DC_PROTOCOL_TYPE.ACK,self._DC_PROTOCOL_TYPE.ERROR,self._DC_PROTOCOL_TYPE.CANCEL].indexOf(protocolData.type)>-1&&!(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded protocol message as data transfer session is not present ->"],protocolData);switch(protocolData.type){case self._DC_PROTOCOL_TYPE.WRQ:if(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId])return log.warn([peerId,"RTCDataChannel",channelProp,"Rejecting bidirectional data transfer request as it is currently not supported in the SDK ->"],protocolData),void self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,ackN:-1,sender:self._user.sid},channelProp);self._WRQProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ACK:self._ACKProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ERROR:self._ERRORProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.CANCEL:self._CANCELProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.MESSAGE:self._MESSAGEProtocolHandler(peerId,protocolData,channelProp);break;default:log.warn([peerId,"RTCDataChannel",channelProp,'Discarded unknown "'+protocolData.type+'" message ->'],protocolData)}}catch(error){if(rawData.indexOf("{")>-1&&rawData.indexOf("}")>0)throw log.error([peerId,"RTCDataChannel",channelProp,"Failed parsing protocol step data error ->"],{data:rawData,error:error}),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(peerId,channelProp)),error;if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING;if(isStreamChunk||self._dataTransfers[transferId].dataType===self.DATA_TRANSFER_SESSION_TYPE.DATA_URL)log.debug([peerId,"RTCDataChannel",channelProp,"Received string data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.length||rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.STRING,rawData.length||rawData.size||0,channelProp);else{var removeSpaceData=rawData.replace(/\s|\r|\n/g,"");log.debug([peerId,"RTCDataChannel",channelProp,"Received binary string data chunk @"+self._dataTransfers[transferId].sessions[peerId].ackN+" with size ->"],removeSpaceData.length||removeSpaceData.size),self._DATAProtocolHandler(peerId,self._base64ToBlob(removeSpaceData),self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,removeSpaceData.length||removeSpaceData.size||0,channelProp)}}else{if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);if(rawData instanceof Blob)log.debug([peerId,"RTCDataChannel",channelProp,"Received blob data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.BLOB,rawData.size,channelProp);else{var byteArray=rawData,blob=null;if(rawData.constructor&&"Array"===rawData.constructor.name&&(byteArray=new Int8Array(rawData)),"IE"===AdapterJS.webrtcDetectedBrowser){if(window.BlobBuilder){var bb=new BlobBuilder;bb.append(rawData.constructor&&"ArrayBuffer"===rawData.constructor.name?byteArray:new Uint8Array(byteArray).buffer),blob=bb.getBlob()}}else blob=new Blob([byteArray]);log.debug([peerId,"RTCDataChannel",channelProp,"Received arraybuffer data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],blob.size),self._DATAProtocolHandler(peerId,blob,self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,blob.size,channelProp)}}},Skylink.prototype._WRQProtocolHandler=function(peerId,data,channelProp){var self=this,transferId="main"===channelProp?data.transferId||null:channelProp,senderPeerId=data.sender||peerId;if(["fastBinaryStart","fastBinaryStop"].indexOf(data.dataType)>-1)if("fastBinaryStart"===data.dataType){transferId||(transferId="stream_"+peerId+"_"+(new Date).getTime()),self._dataStreams[transferId]={chunkSize:0,chunkType:"string"===data.chunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:data.chunkType,isPrivate:!!data.isPrivate,isStringStream:"string"===data.chunkType,senderPeerId:senderPeerId,isUpload:!1},self._dataChannels[peerId][channelProp].streamId=transferId;self.once("dataChannelState",function(){},function(state,evtPeerId,channelName,channelType,error){if(!self._dataStreams[transferId])return!0;if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId&&channelType===self.DATA_CHANNEL_TYPE.DATA)&&[self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');return self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},updatedError),!0}}),self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STARTED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStarted",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1)}else transferId=self._dataChannels[peerId][channelProp].streamId,self._dataStreams[transferId]&&!self._dataStreams[transferId].isUpload&&(self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STOPPED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStopped",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1),self._dataChannels[peerId][channelProp].streamId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp),delete self._dataStreams[transferId]);else transferId||(transferId="transfer_"+peerId+"_"+(new Date).getTime()),self._dataTransfers[transferId]={name:data.name||transferId,size:data.size||0,chunkSize:data.chunkSize,originalSize:data.originalSize||0,timeout:data.timeout||60,isPrivate:!!data.isPrivate,senderPeerId:data.sender||peerId,dataType:self.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:data.mimeType||null,chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,direction:self.DATA_TRANSFER_TYPE.DOWNLOAD,chunks:[],sessions:{},sessionType:data.dataType||"blob",sessionChunkType:data.chunkType||"string"},"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?(self._dataTransfers[transferId].dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,self._dataTransfers[transferId].chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING):"blob"===self._dataTransfers[transferId].sessionType&&"binary"===self._dataTransfers[transferId].sessionChunkType&&(self._dataTransfers[transferId].chunkType=self._binaryChunkType),self._dataChannels[peerId][channelProp].transferId=transferId,self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0,receivedSize:0},self._trigger("incomingDataRequest",transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!1),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_REQUEST,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)},Skylink.prototype._ACKProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ACK event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};if(data.ackN>-1){if(0===data.ackN)emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_STARTED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,0),null)});else if(self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?data.ackN===self._dataTransfers[transferId].enforceBSInfo.chunks.length:data.ackN===self._dataTransfers[transferId].chunks.length)return self._dataTransfers[transferId].sessions[peerId].ackN=data.ackN,emitEventFn(function(evtPeerId){self._trigger("incomingData",self._getTransferData(transferId),transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,100),null)}),void(self._dataChannels[peerId][channelProp]&&(self._dataChannels[peerId][channelProp].transferId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp)));var uploadFn=function(chunk){self._sendMessageToDataChannel(peerId,chunk,channelProp,!0),data.ackN-1?self._blobToBase64(self._dataTransfers[transferId].enforceBSInfo.chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING?self._blobToBase64(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER?self._blobToArrayBuffer(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):uploadFn(self._dataTransfers[transferId].chunks[data.ackN])}else self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.REJECTED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as Peer has rejected data transfer request"),transferType:self.DATA_TRANSFER_TYPE.UPLOAD})},Skylink.prototype._MESSAGEProtocolHandler=function(peerId,data,channelProp){var senderPeerId=data.sender||peerId;log.log([senderPeerId,"RTCDataChannel",channelProp,"Received P2P message from peer:"],data),this._trigger("incomingMessage",{content:data.data,isPrivate:data.isPrivate,isDataChannel:!0,targetPeerId:this._user.sid,senderPeerId:senderPeerId},senderPeerId,this.getPeerInfo(senderPeerId),!1)},Skylink.prototype._ERRORProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ERROR event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,evtPeerId,self._getTransferInfo(transferId,peerID,!0,!1,!1),{message:new Error(data.content),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._CANCELProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of CANCEL event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(peerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.CANCEL,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error(data.content||"Peer has terminated data transfer."),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._DATAProtocolHandler=function(peerId,chunk,chunkType,chunkSize,channelProp){var self=this,transferId=channelProp,senderPeerId=peerId;if(self._dataChannels[peerId]&&self._dataChannels[peerId][channelProp]){var streamId=self._dataChannels[peerId][channelProp].streamId;if(streamId&&self._dataStreams[streamId]&&("string"==typeof chunk&&"string"===self._dataStreams[streamId].sessionChunkType||chunk instanceof Blob&&"binary"===self._dataStreams[streamId].sessionChunkType))return senderPeerId=self._dataStreams[streamId].senderPeerId||peerId,self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVED,streamId,senderPeerId,{chunk:chunk,chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},null),void self._trigger("incomingDataStream",chunk,transferId,senderPeerId,{chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},!1);if("main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._dataTransfers[transferId].senderPeerId&&(senderPeerId=self._dataTransfers[transferId].senderPeerId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1),self._dataTransfers[transferId].chunkType=chunkType,self._dataTransfers[transferId].sessions[peerId].receivedSize+=chunkSize,self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN]=chunk,self._dataTransfers[transferId].sessions[peerId].receivedSize>=self._dataTransfers[transferId].size)return log.log([peerId,"RTCDataChannel",channelProp,"Data transfer has been completed. Computed size ->"],self._dataTransfers[transferId].sessions[peerId].receivedSize),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN+1},channelProp),self._trigger("incomingData",self._getTransferData(transferId),transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),null),void self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null);self._dataTransfers[transferId].sessions[peerId].ackN+=1,self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN},channelProp),self._handleDataTransferTimeoutForPeer(transferId,peerId,!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOADING,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)}},Skylink.prototype._onIceCandidate=function(targetMid,candidate){var self=this,pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCIceCandidate",null,"Ignoring of ICE candidate event as Peer connection does not exists ->"],candidate);if(candidate.candidate){pc.gathering||(log.log([targetMid,"RTCIceCandidate",null,"ICE gathering has started."]),pc.gathering=!0,pc.gathered=!1,self._trigger("candidateGenerationState",self.CANDIDATE_GENERATION_STATE.GATHERING,targetMid));var candidateType=candidate.candidate.split(" ")[7];if(log.debug([targetMid,"RTCIceCandidate",candidateType,"Generated ICE candidate ->"],candidate),"endOfCandidates"===candidateType||!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].localDescription&&self._peerConnections[targetMid].localDescription.sdp&&self._peerConnections[targetMid].localDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return void log.warn([targetMid,"RTCIceCandidate",candidateType,"Dropping of sending ICE candidate end-of-candidates signal or unused ICE candidates to prevent errors ->"],candidate);if(self._initOptions.filterCandidatesType[candidateType]){if(!self._hasMCU||!self._initOptions.forceTURN)return void log.warn([targetMid,"RTCIceCandidate",candidateType,"Dropping of sending ICE candidate as it matches ICE candidate filtering flag ->"],candidate);log.warn([targetMid,"RTCIceCandidate",candidateType,"Not dropping of sending ICE candidate as TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate flags are not honoured ->"],candidate)}if(self._gatheredCandidates[targetMid]||(self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),self._gatheredCandidates[targetMid].sending[candidateType].push({sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate}),!self._initOptions.enableIceTrickle)return void log.warn([targetMid,"RTCIceCandidate",candidateType,"Dropping of sending ICE candidate as trickle ICE is disabled ->"],candidate);log.debug([targetMid,"RTCIceCandidate",candidateType,"Sending ICE candidate ->"],candidate),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.CANDIDATE,label:candidate.sdpMLineIndex,id:candidate.sdpMid,candidate:candidate.candidate,mid:self._user.sid,target:targetMid,rid:self._room.id})}else{if(log.log([targetMid,"RTCIceCandidate",null,"ICE gathering has completed."]),pc.gathered)return;if(pc.gathering=!1,pc.gathered=!0,self._trigger("candidateGenerationState",self.CANDIDATE_GENERATION_STATE.COMPLETED,targetMid),self._initOptions.enableIceTrickle)self._gatheredCandidates[targetMid]&&self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.END_OF_CANDIDATES,noOfExpectedCandidates:self._gatheredCandidates[targetMid].sending.srflx.length+self._gatheredCandidates[targetMid].sending.host.length+self._gatheredCandidates[targetMid].sending.relay.length,mid:self._user.sid,target:targetMid,rid:self._room.id});else{var sessionDescription=self._peerConnections[targetMid].localDescription;if(!(sessionDescription&&sessionDescription.type&&sessionDescription.sdp))return void log.warn([targetMid,"RTCSessionDescription",null,"Not sending any session description after ICE gathering completed as it is not present."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,userInfo:self._getUserInfo(targetMid),target:targetMid,rid:self._room.id})}}},Skylink.prototype._addIceCandidateToQueue=function(targetMid,canId,candidate){var candidateType=candidate.candidate.split(" ")[7];log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Buffering ICE candidate."]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.BUFFERED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[],this._peerCandidatesQueue[targetMid].push([canId,candidate])},Skylink.prototype._addIceCandidateFromQueue=function(targetMid){this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[];for(var i=0;i"],error),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},error)};if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Adding ICE candidate."]),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESSING,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[targetMid].remoteDescription&&self._peerConnections[targetMid].remoteDescription.sdp&&self._peerConnections[targetMid].remoteDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),void self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed."));try{self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)}catch(error){onErrorCbFn(error)}},Skylink.prototype._setIceServers=function(passedIceServers){var self=this,iceServerName=null,iceServerProtocol="stun",iceServerPorts={udp:[3478,19302,19303,19304],tcp:[80,443],both:[19305,19306,19307,19308]},iceServers=[{urls:[]},{urls:[]}];return passedIceServers.forEach(function(server){if(0===server.url.indexOf("stun:"))server.url.indexOf("temasys")>0?iceServerName=(server.url.split(":")[1]||"").split("?")[0]||null:iceServers[0].urls.push(server.url);else if(0===server.url.indexOf("turn:")&&server.url.indexOf("@")>0&&server.credential&&!iceServers[1].username&&!iceServers[1].credential){var parts=server.url.split(":"),urlParts=(parts[1]||"").split("@");iceServerName=(urlParts[1]||"").split("?")[0],iceServers[1].username=urlParts[0],iceServers[1].credential=server.credential,iceServerProtocol="turn"}}),self._initOptions.iceServer?iceServers=[{urls:self._initOptions.iceServer.urls,username:iceServers[1].username||null,credential:iceServers[1].credential||null}]:(iceServerName=iceServerName||"turn.temasys.io","turn"!==iceServerProtocol||self._initOptions.enableTURNServer||self._initOptions.forceTURNSSL?"edge"===AdapterJS.webrtcDetectedBrowser?(iceServerPorts.udp=[3478],iceServerPorts.tcp=[],iceServerPorts.both=[],iceServerProtocol="turn"):self._initOptions.forceTURNSSL?"firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion<53?(iceServerPorts.udp=[],iceServerPorts.tcp=[443],iceServerPorts.both=[],iceServerProtocol="turn"):(iceServerPorts.udp=[],iceServerProtocol="turns"):"firefox"===AdapterJS.webrtcDetectedBrowser&&(iceServerPorts.udp=[3478],iceServerPorts.tcp=[443,80]):iceServerProtocol="stun",self._initOptions.TURNServerTransport!==self.TURN_TRANSPORT.UDP||self._initOptions.forceTURNSSL?self._initOptions.TURNServerTransport===self.TURN_TRANSPORT.TCP?(iceServerPorts.tcp=iceServerPorts.tcp.concat(iceServerPorts.both),iceServerPorts.udp=[],iceServerPorts.both=[]):self._initOptions.TURNServerTransport===self.TURN_TRANSPORT.NONE&&(iceServerPorts.tcp=[],iceServerPorts.udp=[]):(iceServerPorts.udp=iceServerPorts.udp.concat(iceServerPorts.both),iceServerPorts.tcp=[],iceServerPorts.both=[]),"stun"===iceServerProtocol&&(iceServerPorts.tcp=[]),"stun"!==iceServerProtocol||self._initOptions.enableSTUNServer?(iceServerPorts.tcp.forEach(function(tcpPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+tcpPort+"?transport=tcp")}),iceServerPorts.udp.forEach(function(udpPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+udpPort+"?transport=udp")}),iceServerPorts.both.forEach(function(bothPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+bothPort)}),self._initOptions.usePublicSTUN||iceServers.splice(0,1)):iceServers=[]),log.log("Output iceServers configuration:",iceServers),{iceServers:iceServers}},Skylink.prototype.refreshConnection=function(targetPeerId,iceRestart,options,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),doIceRestart=!1,bwOptions={}
+;Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:"boolean"==typeof targetPeerId?doIceRestart=targetPeerId:targetPeerId&&"object"==typeof targetPeerId?bwOptions=targetPeerId:"function"==typeof targetPeerId&&(callback=targetPeerId),"boolean"==typeof iceRestart?doIceRestart=iceRestart:iceRestart&&"object"==typeof iceRestart?bwOptions=iceRestart:"function"==typeof iceRestart&&(callback=iceRestart),options&&"object"==typeof options?bwOptions=options:"function"==typeof options&&(callback=options);var emitErrorForPeersFn=function(error){if(log.error(error),"function"==typeof callback){var listOfPeerErrors={};if(0===listOfPeers.length)listOfPeerErrors.self=new Error(error);else for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}},refreshSinglePeer=function(peerId,peerCallback){if(!self._peerConnections[peerId])return error="There is currently no existing peer connection made with the peer. Unable to restart connection",log.error([peerId,null,null,error]),void peerCallback(error);log.log([peerId,"PeerConnection",null,"Restarting peer connection"]),self._restartPeerConnection(peerId,doIceRestart,bwOptions,peerCallback)};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?refreshSinglePeer(peerId,refreshSinglePeerCallback(peerId)):(error="Peer connection with peer does not exists. Unable to restart",log.error([peerId,"PeerConnection",null,error]),refreshSinglePeerCallback(peerId)(error))}}},Skylink.prototype.getConnectionStatus=function(targetPeerId,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),listOfPeerStats={},listOfPeerErrors={};if(Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId&&targetPeerId?listOfPeers=[targetPeerId]:"function"==typeof targetPeerId&&(callback=targetPeerId,targetPeerId=void 0),0===listOfPeers.length)return listOfPeerErrors.self=new Error("There is currently no peer connections to retrieve connection status"),log.error([null,"RTCStatsReport",null,"Retrieving request failure ->"],listOfPeerErrors.self),void("function"==typeof callback&&callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null));"edge"===AdapterJS.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){-1===completedTaskCounter.indexOf(peerId)&&completedTaskCounter.push(peerId),completedTaskCounter.length===listOfPeers.length&&"function"==typeof callback&&(Object.keys(listOfPeerErrors).length>0?callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null):callback(null,{listOfPeers:listOfPeers,connectionStats:listOfPeerStats}))},statsFn=function(peerId){var retrieveFn=function(firstRetrieval,nextCb){return function(err,result){if(err)return log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],error),listOfPeerErrors[peerId]=error,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,error),checkCompletedFn(peerId),void(firstRetrieval&&delete self._peerStats[peerId]);firstRetrieval?nextCb():(listOfPeerStats[peerId]=result,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_SUCCESS,peerId,listOfPeerStats[peerId],null),checkCompletedFn(peerId))}};if(!self._peerStats[peerId])return self._peerStats[peerId]={},log.debug([peerId,"RTCStatsReport",null,"Retrieving first report to tabulate results"]),void self._retrieveStats(peerId,retrieveFn(!0,function(){self._retrieveStats(peerId,retrieveFn())}),!0);self._retrieveStats(peerId,retrieveFn())},i=0;i"],listOfPeerErrors[peerId]),self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,listOfPeerErrors[peerId]),checkCompletedFn(peerId))}},Skylink.prototype._retrieveStats=function(peerId,callback,beSilentOnLogs,isAutoBwStats){var self=this,pc=self._peerConnections[peerId],output={raw:{},connection:{},audio:{sending:{},receiving:{}},video:{sending:{},receiving:{}},selectedCandidate:{local:{},remote:{},consentResponses:{},consentRequests:{},responses:{},requests:{}},certificate:{}};if(!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));if(!pc)return callback(new Error("Peer connection is not initialised"));"edge"!==AdapterJS.webrtcDetectedBrowser&&"AppleWebKit"!==AdapterJS.webrtcDetectedType||log.warn("Current connection stats may not be complete as it is in beta"),output.connection.iceConnectionState=pc.iceConnectionState,output.connection.iceGatheringState=pc.iceGatheringState,output.connection.signalingState=pc.signalingState,output.connection.remoteDescription={type:pc.remoteDescription&&pc.remoteDescription.type||"",sdp:pc.remoteDescription&&pc.remoteDescription.sdp||""},output.connection.localDescription={type:pc.localDescription&&pc.localDescription.type||"",sdp:pc.localDescription&&pc.localDescription.sdp||""},output.connection.candidates={sending:self._getSDPICECandidates(peerId,pc.localDescription,beSilentOnLogs),receiving:self._getSDPICECandidates(peerId,pc.remoteDescription,beSilentOnLogs)},output.connection.dataChannels={},output.connection.constraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,output.connection.optional=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,output.connection.sdpConstraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null,output.audio.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),output.video.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),output.audio.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"audio",beSilentOnLogs),output.video.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"video",beSilentOnLogs),output.certificate.local=self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),output.certificate.remote=self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs);var inboundSSRCs=self._getSDPMediaSSRC(peerId,pc.remoteDescription,beSilentOnLogs);output.audio.receiving.ssrc=inboundSSRCs.audio,output.video.receiving.ssrc=inboundSSRCs.video;var outboundSSRCs=self._getSDPMediaSSRC(peerId,pc.localDescription,beSilentOnLogs);output.audio.sending.ssrc=outboundSSRCs.audio,output.video.sending.ssrc=outboundSSRCs.video,Object.keys(self._dataChannels[peerId]||{}).forEach(function(prop){var channel=self._dataChannels[peerId][prop];output.connection.dataChannels[channel.channel.label]={label:channel.channel.label,readyState:channel.channel.readyState,channelType:self.DATA_CHANNEL_TYPE["main"===prop?"MESSAGING":"DATA"],currentTransferId:channel.transferId||null,currentStreamId:channel.streamId||null}});var certificateFn=function(item,prop){if(0===prop.indexOf("RTCCertificate_"))item.fingerprint===output.certificate.local.fingerprint?(output.certificate.local.derBase64=item.base64Certificate,output.certificate.local.fingerprintAlgorithm=item.fingerprintAlgorithm):item.fingerprint===output.certificate.remote.fingerprint&&(output.certificate.remote.derBase64=item.base64Certificate,output.certificate.remote.fingerprintAlgorithm=item.fingerprintAlgorithm);else if(0===prop.indexOf("ssrc_")&&item.transportId){var pairItem=output.raw[item.transportId]||{};output.certificate.srtpCipher=pairItem.srtpCipher,output.certificate.dtlsCipher=pairItem.dtlsCipher;var localCertItem=output.raw[pairItem.localCertificateId||""]||{};output.certificate.local.fingerprint=localCertItem.googFingerprint,output.certificate.local.fingerprintAlgorithm=localCertItem.googFingerprintAlgorithm,output.certificate.local.derBase64=localCertItem.googDerBase64;var remoteCertItem=output.raw[pairItem.remoteCertificateId||""]||{};output.certificate.remote.fingerprint=remoteCertItem.googFingerprint,output.certificate.remote.fingerprintAlgorithm=remoteCertItem.googFingerprintAlgorithm,output.certificate.remote.derBase64=remoteCertItem.googDerBase64}},candidatePairFn=function(item,prop){if(0===prop.indexOf("RTCIceCandidatePair_")){if("succeeded"!==item.state||output.selectedCandidate.nominated||item.prioirty<(output.selectedCandidate.priority||0))return;for(var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],sending=pc.localDescription&&pc.localDescription.sdp&&pc.localDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],receiving=pc.remoteDescription&&pc.remoteDescription&&pc.remoteDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],computePrioirtyFn=function(controller,controlled){return Math.pow(2,32)*Math.min(controller,controlled)+2*Math.max(controller,controlled)+(controller>controlled?1:0)},computeCanTypeFn=function(type){return"relay"===type?"relayed":"host"===type?"local":"srflx"===type?"serverreflexive":type},s=0;s0?"sending":"receiving";item.codecImplementationName="unknown"===item.codecImplementationName?null:item.codecImplementationName,output[item.mediaType][direction].codec.implementation=item.codecImplementationName||null,item.googCodecName="unknown"===item.googCodecName?null:item.googCodecName,output[item.mediaType][direction].codec.name=item.googCodecName||output[item.mediaType][direction].codec.name}},audioStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPAudioStream")){if(output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.audio.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),"function"!=typeof pc.getReceivers)return}else if(0===prop.indexOf("RTCMediaStreamTrack_remote_audio_"))output.audio.receiving.audioOutputLevel=item.audioLevel;else if(0===prop.indexOf("RTCOutboundRTPAudioStream"))output.audio.sending.targetBitrate=item.targetBitrate||0,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"audio"===item.mediaType&&item.isRemote)output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"audio"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"audio"===item.mediaType)if(prop.indexOf("_recv")>0){output.audio.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.audio.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.audio.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.audio.receiving.totalBytes=bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.audio.receiving.totalPackets=packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.audio.receiving.totalPacketsLost=packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost")}else{output.audio.sending.rtt=parseInt(item.googRtt||"0",10),output.audio.sending.audioInputLevel=parseInt(item.audioInputLevel||"0",10),output.audio.sending.echoReturnLoss=parseInt(item.googEchoCancellationReturnLoss||"0",10),output.audio.sending.echoReturnLossEnhancement=parseInt(item.googEchoCancellationReturnLossEnhancement||"0",10);var bytesSent=parseInt(item.bytesSent||"0",10);output.audio.sending.totalBytes=bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.audio.sending.totalPackets=packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent")}else if(0===prop.indexOf("inbound_rtp_audio"))output.audio.receiving.jitter=item.jitter||0,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if(0===prop.indexOf("outbound_rtp_audio")){output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.audio.sending.rtt=rtcpItem.roundTripTime||0}}else{output.audio.sending.targetBitrate=item.targetBitrate,output.audio.sending.rtt=item.roundTripTime,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.audio.sending.audioInputLevel=trackItem.audioLevel,output.audio.sending.echoReturnLoss=trackItem.echoReturnLoss,output.audio.sending.echoReturnLossEnhancement=trackItem.echoReturnLossEnhancement}},videoStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPVideoStream"))output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.framesDecoded=item.framesDecoded,output.video.receiving.qpSum=item.qpSum,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.video.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if(0===prop.indexOf("RTCMediaStreamTrack_remote_video_"))output.video.receiving.frameHeight=item.frameHeight,output.video.receiving.frameWidth=item.frameWidth,output.video.receiving.framesCorrupted=item.framesCorrupted,output.video.receiving.framesPerSecond=item.framesPerSecond,output.video.receiving.framesDropped=item.framesDropped,output.video.receiving.totalFrames=item.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,item,"framesReceived");else if(0===prop.indexOf("RTCOutboundRTPVideoStream"))output.video.sending.qpSum=item.qpSum,output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"video"===item.mediaType&&item.isRemote){output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.receiving.framesCorrupted=trackItem.framesCorrupted,output.video.receiving.framesDropped=trackItem.framesDropped,output.video.receiving.framesDecoded=trackItem.framesDecoded,output.video.receiving.totalFrames=trackItem.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,trackItem,"framesReceived")}else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"video"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType)if(prop.indexOf("_recv")>0){output.video.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.video.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.video.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10),output.video.receiving.renderDelayMs=parseInt(item.googRenderDelayMs||"0",10),output.video.receiving.frameWidth=parseInt(item.googFrameWidthReceived||"0",10),output.video.receiving.frameHeight=parseInt(item.googFrameHeightReceived||"0",10),output.video.receiving.framesDecoded=parseInt(item.framesDecoded||"0",10),output.video.receiving.frameRateOutput=parseInt(item.googFrameRateOutput||"0",10),output.video.receiving.frameRateDecoded=parseInt(item.googFrameRateDecoded||"0",10),output.video.receiving.frameRateReceived=parseInt(item.googFrameRateReceived||"0",10),output.video.receiving.qpSum=parseInt(item.qpSum||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.video.receiving.totalBytes=bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.video.receiving.totalPackets=packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.video.receiving.totalPacketsLost=packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost");var nacksSent=parseInt(item.googNacksSent||"0",10);output.video.receiving.totalNacks=nacksSent,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"googNacksSent");var plisSent=parseInt(item.googPlisSent||"0",10);output.video.receiving.totalPlis=plisSent,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"googPlisSent");var firsSent=parseInt(item.googFirsSent||"0",10);output.video.receiving.totalFirs=firsSent,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"googFirsSent")}else{output.video.sending.rtt=parseInt(item.googRtt||"0",10),output.video.sending.frameWidth=parseInt(item.googFrameWidthSent||"0",10),output.video.sending.frameHeight=parseInt(item.googFrameHeightSent||"0",10),output.video.sending.framesEncoded=parseInt(item.framesEncoded||"0",10),output.video.sending.frameRateInput=parseInt(item.googFrameRateInput||"0",10),output.video.sending.frameRateEncoded=parseInt(item.googFrameRateEncoded||"0",10),output.video.sending.frameRateSent=parseInt(item.googFrameRateSent||"0",10),output.video.sending.cpuLimitedResolution="true"===item.googCpuLimitedResolution,output.video.sending.bandwidthLimitedResolution="true"===item.googBandwidthLimitedResolution;var bytesSent=parseInt(item.bytesSent||"0",10);output.video.sending.totalBytes=bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.video.sending.totalPackets=packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent");var nacksReceived=parseInt(item.googNacksReceived||"0",10);output.video.sending.totalNacks=nacksReceived,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"googNacksReceived");var plisReceived=parseInt(item.googPlisReceived||"0",10);output.video.sending.totalPlis=plisReceived,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"googPlisReceived");var firsReceived=parseInt(item.googFirsReceived||"0",10);output.video.sending.totalFirs=firsReceived,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"googFirsReceived")
+}else if(0===prop.indexOf("inbound_rtp_video"))output.video.receiving.jitter=item.jitter||0,output.video.receiving.framesDecoded=item.framesDecoded||0,output.video.receiving.frameRateMean=item.framerateMean||0,output.video.receiving.frameRateStdDev=item.framerateStdDev||0,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount");else if(0===prop.indexOf("outbound_rtp_video")){output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.frameRateMean=item.framerateMean||0,output.video.sending.frameRateStdDev=item.framerateStdDev||0,output.video.sending.framesDropped=item.droppedFrames||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.video.sending.rtt=rtcpItem.roundTripTime||0}}else{output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.roundTripTime=item.roundTripTime||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.sending.frameHeight=trackItem.frameHeight,output.video.sending.frameWidth=trackItem.frameWidth,output.video.sending.framesPerSecond=trackItem.framesPerSecond,output.video.sending.totalFrames=trackItem.framesSent,output.video.sending.frames=self._parseConnectionStats(prevStats,trackItem,"framesSent")}},videoE2EStatsFn=function(item,prop){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType){var captureStartNtpTimeMs=parseInt(item.googCaptureStartNtpTimeMs||"0",10),remoteStream=pc.getRemoteStreams()[0];if(!(captureStartNtpTimeMs>0&&prop.indexOf("_recv")>0&&remoteStream&&document&&"function"==typeof document.getElementsByTagName))return;try{var elements=document.getElementsByTagName("plugin"===AdapterJS.webrtcDetectedType?"object":"video");"plugin"!==AdapterJS.webrtcDetectedType&&0===elements.length&&(elements=document.getElementsByTagName("audio"));for(var e=0;e0))break;for(var ec=0;ec"],error)}}},successCbFn=function(stats){"function"==typeof stats.forEach?stats.forEach(function(item,prop){output.raw[prop]=item}):output.raw=stats;var edgeTracksKind={remote:{},local:{}};"edge"===AdapterJS.webrtcDetectedBrowser&&(pc.remoteStream&&pc.remoteStream.getTracks().forEach(function(track){edgeTracksKind.remote[track.id]=track.kind}),pc.localStream&&pc.localStream.getTracks().forEach(function(track){edgeTracksKind.local[track.id]=track.kind})),Object.keys(output.raw).forEach(function(prop){if(0!==prop.indexOf("ssrc_")||output.raw[prop].mediaType){if("edge"===AdapterJS.webrtcDetectedBrowser&&!output.raw[prop].mediaType&&["inboundrtp","outboundrtp"].indexOf(output.raw[prop].type)>-1){var trackItem=output.raw[output.raw[prop].mediaTrackId]||{};output.raw[prop].mediaType=edgeTracksKind[output.raw[prop].isRemote?"remote":"local"][trackItem.trackIdentifier]||""}}else output.raw[prop].mediaType=output.raw[prop].audioInputLevel||output.raw[prop].audioOutputLevel?"audio":"video";certificateFn(output.raw[prop],prop),candidatePairFn(output.raw[prop],prop),codecsFn(output.raw[prop],prop),audioStatsFn(output.raw[prop],prop),videoStatsFn(output.raw[prop],prop),videoE2EStatsFn(output.raw[prop],prop),isAutoBwStats&&!self._peerBandwidth[peerId][prop]?self._peerBandwidth[peerId][prop]=output.raw[prop]:isAutoBwStats||self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=output.raw[prop])}),output.audio.sending.bytes=output.audio.sending.bytes||0,output.audio.sending.packets=output.audio.sending.packets||0,output.audio.sending.totalBytes=output.audio.sending.totalBytes||0,output.audio.sending.totalPackets=output.audio.sending.totalPackets||0,output.video.sending.bytes=output.video.sending.bytes||0,output.video.sending.packets=output.video.sending.packets||0,output.video.sending.totalBytes=output.video.sending.totalBytes||0,output.video.sending.totalPackets=output.video.sending.totalPackets||0,output.audio.receiving.bytes=output.audio.receiving.bytes||0,output.audio.receiving.packets=output.audio.receiving.packets||0,output.audio.receiving.totalBytes=output.audio.receiving.totalBytes||0,output.audio.receiving.totalPackets=output.audio.receiving.totalPackets||0,output.video.receiving.bytes=output.video.receiving.bytes||0,output.video.receiving.packets=output.video.receiving.packets||0,output.video.receiving.totalBytes=output.video.receiving.totalBytes||0,output.video.receiving.totalPackets=output.video.receiving.totalPackets||0,callback(null,output)},errorCbFn=function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)};if("function"!=typeof pc.getStats)return errorCbFn(new Error("getStats() API is not available."));"plugin"===AdapterJS.webrtcDetectedType?pc.getStats(null,successCbFn,errorCbFn):pc.getStats(null).then(successCbFn).catch(errorCbFn)},Skylink.prototype._addPeer=function(targetMid,cert,peerBrowser,receiveOnly,isSS){var self=this;return self._peerConnections[targetMid]?void log.error([targetMid,null,null,"Connection to peer has already been made"]):(self._peerConnStatus[targetMid]={connected:!1,init:!1},log.log([targetMid,null,null,"Starting the connection to peer. Options provided:"],{peerBrowser:peerBrowser,receiveOnly:receiveOnly,enableDataChannel:self._initOptions.enableDataChannel}),log.info("Adding peer",isSS),self._peerConnections[targetMid]=self._createPeerConnection(targetMid,!!isSS,cert),self._peerConnections[targetMid]?(self._peerConnStatus[targetMid].init=!0,void(self._peerConnections[targetMid].hasScreen=!!isSS)):void log.error([targetMid,null,null,"Failed creating the connection to peer."]))},Skylink.prototype._restartPeerConnection=function(peerId,doIceRestart,bwOptions,callback){var self=this;if(!self._peerConnections[peerId])return void log.error([peerId,null,null,"Peer does not have an existing connection. Unable to restart"]);var pc=self._peerConnections[peerId],agent=(self.getPeerInfo(peerId)||{}).agent||{};if(self._isLowerThanVersion(agent.SMProtocolVersion||"","0.1.2")){var notSupportedError=new Error("Failed restarting with other agents connecting from other SDKs as re-negotiation is not supported by other SDKs");return log.warn([peerId,"RTCPeerConnection",null,"Ignoring restart request as agent's SDK does not support it"],notSupportedError),void("function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(notSupportedError)))}if(pc.signalingState===self.PEER_CONNECTION_STATE.STABLE&&self._peerConnections[peerId]){log.log([peerId,null,null,"Sending restart message to signaling server ->"],{iceRestart:doIceRestart,options:bwOptions}),self._peerCustomConfigs[peerId]=self._peerCustomConfigs[peerId]||{},self._peerCustomConfigs[peerId].bandwidth=self._peerCustomConfigs[peerId].bandwidth||{},self._peerCustomConfigs[peerId].googleXBandwidth=self._peerCustomConfigs[peerId].googleXBandwidth||{},bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._peerCustomConfigs[peerId].bandwidth.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._peerCustomConfigs[peerId].bandwidth.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._peerCustomConfigs[peerId].bandwidth.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._peerCustomConfigs[peerId].googleXBandwidth.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._peerCustomConfigs[peerId].googleXBandwidth.max=bwOptions.googleXBandwidth.max));var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===doIceRestart&&self._enableIceRestart&&self._peerInformations[peerId]&&self._peerInformations[peerId].config.enableIceRestart,isRestartResend:!1,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._peerEndOfCandidatesCounter[peerId]=self._peerEndOfCandidatesCounter[peerId]||{},self._peerEndOfCandidatesCounter[peerId].len=0,self._sendChannelMessage(restartMsg),self._trigger("peerRestart",peerId,self.getPeerInfo(peerId),!0,!0===doIceRestart),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart callback"]),callback(null))}else if(pc.signalingState===self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER){var hasLocalDescription=pc.localDescription&&pc.localDescription.sdp;if(hasLocalDescription)self._sendChannelMessage({type:pc.localDescription.type,sdp:pc.localDescription.sdp,mid:self._user.sid,target:peerId,rid:self._room.id,restart:!0});else{var noLocalDescriptionError="Failed re-sending localDescription as there is no localDescription set to connection. There could be a handshaking step error";log.error([peerId,"RTCPeerConnection",null,noLocalDescriptionError],{localDescription:pc.localDescription,remoteDescription:pc.remoteDescription}),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(noLocalDescriptionError)))}}else{var unableToRestartError="Failed restarting as peer connection state is "+pc.signalingState;log.warn([peerId,"RTCPeerConnection",null,unableToRestartError]),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(unableToRestartError)))}},Skylink.prototype._removePeer=function(peerId){if(!this._peerConnections[peerId]&&!this._peerInformations[peerId])return void log.debug([peerId,"RTCPeerConnection",null,"Dropping the hangup from Peer as not connected to Peer at all."]);var peerInfo=clone(this.getPeerInfo(peerId))||{userData:"",settings:{audio:!1,video:!1,data:!1},mediaStatus:{audioMuted:!0,videoMuted:!0},agent:{name:"unknown",version:0,os:"",pluginVersion:null},config:{enableDataChannel:!0,enableIceRestart:!1,enableIceTrickle:!0,priorityWeight:0,publishOnly:!1,receiveOnly:!0},parentId:null,room:clone(this._selectedRoom)};"MCU"!==peerId?this._trigger("peerLeft",peerId,peerInfo,!1):(this._hasMCU=!1,log.log([peerId,null,null,"MCU has stopped listening and left"]),this._trigger("serverPeerLeft",peerId,this.SERVER_PEER_TYPE.MCU)),this._peerConnections[peerId]&&(this._peerConnections[peerId].signalingState!==this.PEER_CONNECTION_STATE.CLOSED&&(this._peerConnections[peerId].close(),"AppleWebKit"===AdapterJS.webrtcDetectedType&&(this._peerConnections[peerId].signalingStateClosed||(this._peerConnections[peerId].signalingStateClosed=!0,this._trigger("peerConnectionState",this.PEER_CONNECTION_STATE.CLOSED,peerId)),this._peerConnections[peerId].iceConnectionStateClosed||(this._peerConnections[peerId].iceConnectionStateClosed=!0,this._trigger("iceConnectionState",this.ICE_CONNECTION_STATE.CLOSED,peerId)))),"MCU"!==peerId&&this._handleEndedStreams(peerId),delete this._peerConnections[peerId]),this._peerInformations[peerId]&&delete this._peerInformations[peerId],this._peerMessagesStamps[peerId]&&delete this._peerMessagesStamps[peerId],this._streamsSession[peerId]&&delete this._streamsSession[peerId],this._peerEndOfCandidatesCounter[peerId]&&delete this._peerEndOfCandidatesCounter[peerId],this._peerCandidatesQueue[peerId]&&delete this._peerCandidatesQueue[peerId],this._sdpSessions[peerId]&&delete this._sdpSessions[peerId],this._peerStats[peerId]&&delete this._peerStats[peerId],this._peerBandwidth[peerId]&&delete this._peerBandwidth[peerId],this._gatheredCandidates[peerId]&&delete this._gatheredCandidates[peerId],this._peerCustomConfigs[peerId]&&delete this._peerCustomConfigs[peerId],this._peerConnStatus[peerId]&&delete this._peerConnStatus[peerId],this._dataChannels[peerId]&&this._closeDataChannel(peerId),log.log([peerId,"RTCPeerConnection",null,"Successfully removed peer"])},Skylink.prototype._createPeerConnection=function(targetMid,isScreenSharing,cert){var pc,self=this;if(self._inRoom&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)){var constraints={iceServers:self._room.connection.peerConfig.iceServers,iceTransportPolicy:self._initOptions.filterCandidatesType.host&&self._initOptions.filterCandidatesType.srflx&&!self._initOptions.filterCandidatesType.relay?"relay":"all",bundlePolicy:self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.NONE?self.BUNDLE_POLICY.BALANCED:self._peerConnectionConfig.bundlePolicy,rtcpMuxPolicy:self._peerConnectionConfig.rtcpMuxPolicy,iceCandidatePoolSize:self._peerConnectionConfig.iceCandidatePoolSize},optional={optional:[{DtlsSrtpKeyAgreement:!0},{googIPv6:!0}]};cert&&(constraints.certificates=[cert]),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].constraints=constraints,self._peerConnStatus[targetMid].optional=optional);try{log.debug([targetMid,"RTCPeerConnection",null,"Creating peer connection ->"],{constraints:constraints,optional:optional}),pc=new(self._initOptions.useEdgeWebRTC&&window.msRTCPeerConnection?window.msRTCPeerConnection:RTCPeerConnection)(constraints,optional)}catch(error){return log.error([targetMid,null,null,"Failed creating peer connection:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),null}pc.setOffer="",pc.setAnswer="",pc.hasStream=!1,pc.hasScreen=!!isScreenSharing,pc.hasMainChannel=!1,pc.firefoxStreamId="",pc.processingLocalSDP=!1,pc.processingRemoteSDP=!1,pc.gathered=!1,pc.gathering=!1,pc.localStream=null,pc.localStreamId=null,pc.remoteStream=null,pc.remoteStreamId=null,pc.iceConnectionStateClosed=!1,pc.signalingStateClosed=!1,self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}},self._streamsSession[targetMid]=self._streamsSession[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._sdpSessions[targetMid]={local:{},remote:{}},self._peerBandwidth[targetMid]={};var bandwidth=null;return pc.ondatachannel=function(event){var dc=event.channel||event;if(log.debug([targetMid,"RTCDataChannel",dc.label,"Received datachannel ->"],dc),self._initOptions.enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel){self.DATA_CHANNEL_TYPE.DATA,dc.label;pc.hasMainChannel||(self.DATA_CHANNEL_TYPE.MESSAGING,"main",pc.hasMainChannel=!0),self._createDataChannel(targetMid,dc)}else log.warn([targetMid,"RTCDataChannel",dc.label,"Not adding datachannel as enable datachannel is set to false"])},pc.onaddstream=function(evt){if(self._peerConnections[targetMid]){var stream=evt.stream||evt;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received empty remote stream ->"],stream);pc.remoteStream=stream,pc.remoteStreamId=pc.remoteStreamId||stream.id||stream.label;var peerSettings=clone(self.getPeerInfo(targetMid).settings);self._streamsSession[targetMid][pc.remoteStreamId]=peerSettings,0===stream.getAudioTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].audio=!1),0===stream.getVideoTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].video=!1),pc.hasStream=!0,pc.hasScreen=peerSettings.video&&"object"==typeof peerSettings.video&&peerSettings.video.screenshare,self._onRemoteStreamAdded(targetMid,stream,!!pc.hasScreen)}},pc.onicecandidate=function(event){self._onIceCandidate(targetMid,event.candidate||event)},pc.oniceconnectionstatechange=function(evt){var iceConnectionState=pc.iceConnectionState;if(log.debug([targetMid,"RTCIceConnectionState",null,"Ice connection state changed ->"],iceConnectionState),"edge"===AdapterJS.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),"AppleWebKit"===AdapterJS.webrtcDetectedType&&iceConnectionState===self.ICE_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.iceConnectionStateClosed||self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.CLOSED,targetMid)},10);if(self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._initOptions.enableIceTrickle&&self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.TRICKLE_FAILED,targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].connected=[self.ICE_CONNECTION_STATE.COMPLETED,self.ICE_CONNECTION_STATE.CONNECTED].indexOf(iceConnectionState)>-1),!self._hasMCU&&[self.ICE_CONNECTION_STATE.CONNECTED,self.ICE_CONNECTION_STATE.COMPLETED].indexOf(iceConnectionState)>-1&&self._bandwidthAdjuster&&!bandwidth&&"edge"!==AdapterJS.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),"AppleWebKit"===AdapterJS.webrtcDetectedType&&pc.signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.signalingStateClosed||self._trigger("peerConnectionState",self.PEER_CONNECTION_STATE.CLOSED,targetMid)},10);self._trigger("peerConnectionState",pc.signalingState,targetMid)},pc.onicegatheringstatechange=function(){log.log([targetMid,"RTCIceGatheringState",null,"Ice gathering state changed ->"],pc.iceGatheringState),self._trigger("candidateGenerationState",pc.iceGatheringState,targetMid)},"firefox"===AdapterJS.webrtcDetectedBrowser&&(pc.removeStream=function(stream){for(var senders=pc.getSenders(),s=0;s"],restartMsg),self._sendChannelMessage(restartMsg)};bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=bwOptions.googleXBandwidth.max));for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers},null):callback(null,{listOfPeers:listOfPeers}))};self.once("peerJoined",peerJoinedFn,function(peerId,peerInfo,isSelf){return isSelf}),self.leaveRoom(!1,function(error,success){if(error){if("function"==typeof callback){for(var i=0;i=self._peerEndOfCandidatesCounter[targetMid].expectedLen&&(!self._peerCandidatesQueue[targetMid]||0===self._peerCandidatesQueue[targetMid].length)&&!self._peerEndOfCandidatesCounter[targetMid].hasSet){log.debug([targetMid,"RTCPeerConnection",null,"Signaling of end-of-candidates remote ICE gathering."]),self._peerEndOfCandidatesCounter[targetMid].hasSet=!0;try{if("edge"===AdapterJS.webrtcDetectedBrowser){for(var mLineCounter=-1,addedMids=[],sdpLines=self._peerConnections[targetMid].remoteDescription.sdp.split("\r\n"),rejected=!1,i=0;i"],error)}}},Skylink.prototype.setUserData=function(userData){var self=this,updatedUserData="";void 0!==userData&&null!==userData&&(updatedUserData=userData),this._userData=updatedUserData,self._inRoom?(log.log("Updated userData -> ",updatedUserData),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.UPDATE_USER,mid:self._user.sid,rid:self._room.id,userData:updatedUserData,stamp:(new Date).getTime()}),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0)):log.warn("User is not in the room. Broadcast of updated information will be dropped")},Skylink.prototype.getUserData=function(peerId){if(peerId&&this._peerInformations[peerId]){var userData=this._peerInformations[peerId].userData;return null!==userData&&void 0===userData||(userData=""),userData}return this._userData},Skylink.prototype.getPeerInfo=function(peerId){var peerInfo=null;return"string"==typeof peerId&&"object"==typeof this._peerInformations[peerId]?(peerInfo=clone(this._peerInformations[peerId]),peerInfo.room=clone(this._selectedRoom),peerInfo.settings.bandwidth=peerInfo.settings.bandwidth||{},peerInfo.settings.googleXBandwidth=peerInfo.settings.googleXBandwidth||{},"boolean"==typeof peerInfo.settings.video||peerInfo.settings.video&&"object"==typeof peerInfo.settings.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"==typeof peerInfo.settings.audio||peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.audioMuted&&(peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.videoMuted&&(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.maxBandwidth&&(peerInfo.settings.bandwidth=clone(peerInfo.settings.maxBandwidth),delete peerInfo.settings.maxBandwidth),peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&peerInfo.settings.video.customSettings&&"object"==typeof peerInfo.settings.video.customSettings&&(peerInfo.settings.video.customSettings.frameRate&&(peerInfo.settings.video.frameRate=clone(peerInfo.settings.video.customSettings.frameRate)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode)),peerInfo.settings.video.customSettings.width&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.width=clone(peerInfo.settings.video.customSettings.width)),
+peerInfo.settings.video.customSettings.height&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.height=clone(peerInfo.settings.video.customSettings.height)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode))),peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&(peerInfo.settings.audio.stereo=!0===peerInfo.settings.audio.stereo),null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),peerInfo.parentId=peerInfo.parentId||null,"MCU"===peerId?(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1):this._hasMCU&&(peerInfo.config.receiveOnly=!1,peerInfo.config.publishOnly=!0),this._sdpSettings.direction.audio.receive||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.direction.video.receive||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.data=!!(this._dataChannels[peerId]&&this._dataChannels[peerId].main&&this._dataChannels[peerId].main.channel&&this._dataChannels[peerId].main.channel.readyState===this.DATA_CHANNEL_STATE.OPEN),peerInfo.connected=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].connected,peerInfo.init=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].init,this._sdpSessions[peerId]&&this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&"object"==typeof this._sdpSessions[peerId].remote.connection&&(this._sdpSessions[peerId].remote.connection.audio&&this._sdpSessions[peerId].remote.connection.audio.indexOf("send")>-1||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSessions[peerId].remote.connection.video&&this._sdpSessions[peerId].remote.connection.video.indexOf("send")>-1||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSessions[peerId].remote.connection.data&&this._sdpSessions[peerId].remote.connection.data.indexOf("send")>-1||(peerInfo.settings.data=!1))):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,os:window.navigator.platform,pluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:this.SMProtocolVersion,DTProtocolVersion:this.DTProtocolVersion},room:clone(this._selectedRoom),config:{enableDataChannel:this._initOptions.enableDataChannel,enableIceTrickle:this._initOptions.enableIceTrickle,enableIceRestart:this._enableIceRestart,priorityWeight:this._peerPriorityWeight,receiveOnly:!1,publishOnly:!!this._publishOnly},connected:null,init:null},null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),this._streams.screenshare?peerInfo.settings=clone(this._streams.screenshare.settings):this._streams.userMedia&&(peerInfo.settings=clone(this._streams.userMedia.settings)),peerInfo.settings.bandwidth=clone(this._streamsBandwidthSettings.bAS),peerInfo.settings.googleXBandwidth=clone(this._streamsBandwidthSettings.googleX),peerInfo.parentId=this._parentId?this._parentId:null,peerInfo.config.receiveOnly=!peerInfo.settings.video&&!peerInfo.settings.audio,peerInfo.settings.data=this._initOptions.enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._initOptions.codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._initOptions.codecParams.audio.opus.stereo),"boolean"==typeof this._initOptions.codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._initOptions.codecParams.audio.opus.usedtx),"number"==typeof this._initOptions.codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._initOptions.codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._initOptions.codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._initOptions.codecParams.audio.opus.useinbandfec))),peerInfo.settings.audio||(peerInfo.mediaStatus.audioMuted=!0),peerInfo.settings.video||(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.audio||peerInfo.settings.video||(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1),peerInfo},Skylink.prototype.getPeersInRoom=function(){for(var listOfPeersInfo={},listOfPeers=Object.keys(this._peerInformations),i=0;i-1||(customSettings.settings.audio=!1,customSettings.mediaStatus.audioMuted=!0),self._sdpSessions[usePeerId].local.connection.video&&self._sdpSessions[usePeerId].local.connection.video.indexOf("send")>-1||(customSettings.settings.video=!1,customSettings.mediaStatus.videoMuted=!0),self._sdpSessions[usePeerId].local.connection.data&&self._sdpSessions[usePeerId].local.connection.data.indexOf("send")>-1||(customSettings.settings.data=!1)),customSettings},Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo()),userCustomInfoForPeer=peerId?this._getPeerCustomSettings(peerId):null;return userCustomInfoForPeer&&"object"==typeof userCustomInfoForPeer&&(userInfo.settings=userCustomInfoForPeer.settings,userInfo.mediaStatus=userCustomInfoForPeer.mediaStatus),userInfo.settings.video&&"object"==typeof userInfo.settings.video&&(userInfo.settings.video.customSettings={},userInfo.settings.video.frameRate&&"object"==typeof userInfo.settings.video.frameRate&&(userInfo.settings.video.customSettings.frameRate=clone(userInfo.settings.video.frameRate),userInfo.settings.video.frameRate=-1),userInfo.settings.video.facingMode&&"object"==typeof userInfo.settings.video.facingMode&&(userInfo.settings.video.customSettings.facingMode=clone(userInfo.settings.video.facingMode),userInfo.settings.video.facingMode="-1"),userInfo.settings.video.resolution&&"object"==typeof userInfo.settings.video.resolution&&(userInfo.settings.video.resolution.width&&"object"==typeof userInfo.settings.video.resolution.width&&(userInfo.settings.video.customSettings.width=clone(userInfo.settings.video.width),userInfo.settings.video.resolution.width=-1),userInfo.settings.video.resolution.height&&"object"==typeof userInfo.settings.video.resolution.height&&(userInfo.settings.video.customSettings.height=clone(userInfo.settings.video.height),userInfo.settings.video.resolution.height=-1))),userInfo.settings.bandwidth&&(userInfo.settings.maxBandwidth=clone(userInfo.settings.bandwidth),delete userInfo.settings.bandwidth),this._getSDPCommonSupports(peerId).video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._getSDPCommonSupports(peerId).audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype._doOffer=function(targetMid,iceRestart){var self=this,pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of creating of offer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription","offer",'Dropping of creating of offer as signalingState is not "'+self.PEER_CONNECTION_STATE.STABLE+'" ->'],pc.signalingState);var offerConstraints={offerToReceiveAudio:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).video,offerToReceiveVideo:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).audio,iceRestart:!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,voiceActivityDetection:self._voiceActivityDetection};self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._initOptions.enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._dataChannels[targetMid]&&self._dataChannels[targetMid].main||(self._createDataChannel(targetMid),self._peerConnections[targetMid].hasMainChannel=!0)),log.debug([targetMid,null,null,"Creating offer with config:"],offerConstraints),pc.endOfCandidates=!1,self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=offerConstraints);var onSuccessCbFn=function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)};pc.createOffer(onSuccessCbFn,onErrorCbFn,"plugin"===AdapterJS.webrtcDetectedType?{mandatory:{OfferToReceiveAudio:offerConstraints.offerToReceiveAudio,OfferToReceiveVideo:offerConstraints.offerToReceiveVideo,iceRestart:offerConstraints.iceRestart,voiceActivityDetection:offerConstraints.voiceActivityDetection}}:offerConstraints)},Skylink.prototype._doAnswer=function(targetMid){var self=this;log.log([targetMid,null,null,"Creating answer with config:"],self._room.connection.sdpConstraints);var pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of creating of answer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription","answer",'Dropping of creating of answer as signalingState is not "'+self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER+'" ->'],pc.signalingState);var answerConstraints="edge"===AdapterJS.webrtcDetectedBrowser?{offerToReceiveVideo:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).video,offerToReceiveAudio:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).audio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints);var onSuccessCbFn=function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},onErrorCbFn=function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.createAnswer(onSuccessCbFn,onErrorCbFn,answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,_sessionDescription){var self=this,pc=self._peerConnections[targetMid];if(!_sessionDescription||!_sessionDescription.sdp)return void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],_sessionDescription);if(!pc)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as connection does not exists ->"],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(pc.processingLocalSDP)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as another is being processed ->"],_sessionDescription);pc.processingLocalSDP=!0;var sessionDescription={type:_sessionDescription.type,sdp:_sessionDescription.sdp};sessionDescription.sdp=self._removeSDPFirefoxH264Pref(targetMid,sessionDescription),sessionDescription.sdp=self._setSDPCodecParams(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPUnknownAptRtx(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPCodecs(targetMid,sessionDescription),sessionDescription.sdp=self._handleSDPConnectionSettings(targetMid,sessionDescription,"local"),sessionDescription.sdp=self._removeSDPREMBPackets(targetMid,sessionDescription),self._peerConnectionConfig.disableBundle&&(sessionDescription.sdp=sessionDescription.sdp.replace(/a=group:BUNDLE.*\r\n/gi,"")),log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description updated ->"],sessionDescription.sdp);var onSuccessCbFn=function(){if(log.debug([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description has been set ->"],sessionDescription),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",sessionDescription.type,targetMid),sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER?pc.setAnswer="local":pc.setOffer="local",!self._initOptions.enableIceTrickle&&!pc.gathered)return void log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description sending is halted to complete ICE gathering."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},onErrorCbFn=function(error){log.error([targetMid,"RTCSessionDescription",sessionDescription.type,"Local description failed setting ->"],error),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.setLocalDescription(new RTCSessionDescription(sessionDescription),onSuccessCbFn,onErrorCbFn)},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._initOptions.appKey?("function"==typeof showAll&&(callback=showAll,showAll=!1),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.GET_PEERS,showAll:showAll||!1}),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.ENQUIRED,self._user.sid,null),log.log("Enquired server for peers within the realm"),void("function"==typeof callback&&self.once("getPeersStateChange",function(state,privilegedPeerId,peerList){callback(null,peerList)},function(state,privilegedPeerId,peerList){return state===self.GET_PEERS_STATE.RECEIVED}))):void log.warn("App key is not defined. Please authenticate again."):void log.warn("Please upgrade your key to privileged to use this function")},Skylink.prototype.introducePeer=function(sendingPeerId,receivingPeerId){var self=this;if(!self._isPrivileged)return log.warn("Please upgrade your key to privileged to use this function"),void self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,sendingPeerId,receivingPeerId,"notPrivileged");self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.INTRODUCE,sendingPeerId:sendingPeerId,receivingPeerId:receivingPeerId}),self._trigger("introduceStateChange",self.INTRODUCE_STATE.INTRODUCING,self._user.sid,sendingPeerId,receivingPeerId,null),log.log("Introducing",sendingPeerId,"to",receivingPeerId)},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._initOptions.defaultRoom,previousRoom=self._selectedRoom,mediaOptions={},timestamp=(new Date).getTime()+Math.floor(1e4*Math.random());self._joinRoomManager.timestamp=timestamp,room&&"string"==typeof room?selectedRoom=room:room&&"object"==typeof room?mediaOptions=room:"function"==typeof room&&(callback=room),options&&"object"==typeof options?mediaOptions=options:"function"==typeof options&&(callback=options);var resolveAsErrorFn=function(error,tryRoom,readyState){log.error(error),"function"==typeof callback&&callback({room:tryRoom,errorCode:readyState||null,error:error instanceof Error?error:new Error(JSON.stringify(error))})},joinRoomFn=function(){if(self._joinRoomManager.timestamp!==timestamp)return void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom);self._initSelectedRoom(selectedRoom,function(initError,initSuccess){return initError?void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState):self._joinRoomManager.timestamp!==timestamp?void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom):void self._waitForOpenChannel(mediaOptions||{},timestamp,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);if(self._joinRoomManager.timestamp!==timestamp)return void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom);if("AppleWebKit"===AdapterJS.webrtcDetectedType){var checkStream=self._streams.screenshare&&self._streams.screenshare.stream?self._streams.screenshare.stream:self._streams.userMedia&&self._streams.userMedia.stream?self._streams.userMedia.stream:null;checkStream&&0!==checkStream.getTracks().length?0===checkStream.getAudioTracks().length?log.warn("Note that receiving audio streams may fail as safari 11 needs stream with audio and video tracks and not just with video tracks"):0===checkStream.getVideoTracks().length&&log.warn("Note that receiving video streams may fail as safari 11 needs stream with audio and video tracks and not just with audio tracks"):log.warn("Note that receiving audio and video streams may fail as safari 11 needs stream with audio and video tracks")}if("function"==typeof callback){var peerOnJoin=function(peerId,peerInfo,isSelf){self.off("systemAction",peerFailedJoin),self.off("channelClose",peerSocketFailedJoin),log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo})},peerFailedJoin=function(action,message){self.off("peerJoined",peerOnJoin),self.off("channelClose",peerSocketFailedJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room ->"],message),resolveAsErrorFn(new Error(message),self._selectedRoom,self._readyState)},peerSocketFailedJoin=function(){self.off("systemAction",peerFailedJoin),self.off("peerJoined",peerOnJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room due to abrupt disconnection."]),resolveAsErrorFn(new Error("Channel closed abruptly before session was established"),self._selectedRoom,self._readyState)};self.once("peerJoined",peerOnJoin,function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),self.once("systemAction",peerFailedJoin,function(action){return action===self.SYSTEM_ACTION.REJECT}),self.once("channelClose",peerSocketFailedJoin)}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.JOIN_ROOM,uid:self._user.uid,cid:self._key,rid:self._room.id,userCred:self._user.token,timeStamp:self._user.timeStamp,apiOwner:self._appKeyOwner,roomCred:self._room.token,start:self._room.startDateTime,len:self._room.duration,isPrivileged:!0===self._isPrivileged,autoIntroduce:!1!==self._autoIntroduce,key:self._initOptions.appKey})})})};if(null===room||["number","boolean"].indexOf(typeof room)>-1)return void resolveAsErrorFn("Invalid room name is provided",room);if(null===options||["number","boolean"].indexOf(typeof options)>-1)return void resolveAsErrorFn("Invalid mediaOptions is provided",selectedRoom);self._joinRoomManager.socketsFn.forEach(function(fnItem){fnItem(timestamp)}),self._joinRoomManager.socketsFn=[];var stopStream=!1===mediaOptions.audio&&!1===mediaOptions.video;self._inRoom?self.leaveRoom({userMedia:stopStream},function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()}):(stopStream&&self.stopStream(),joinRoomFn())},Skylink.prototype.leaveRoom=function(stopMediaOptions,callback){var self=this,stopUserMedia=!0,stopScreenshare=!0,previousRoom=self._selectedRoom,previousUserPeerId=self._user?self._user.sid:null,peersThatLeft=[],isNotInRoom=!self._inRoom;"boolean"==typeof stopMediaOptions?!1===stopMediaOptions&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=!1!==stopMediaOptions.userMedia,stopScreenshare=!1!==stopMediaOptions.screenshare):"function"==typeof stopMediaOptions&&(callback=stopMediaOptions);for(var infoPeerId in self._peerInformations)self._peerInformations.hasOwnProperty(infoPeerId)&&self._peerInformations[infoPeerId]&&(peersThatLeft.push(infoPeerId),self._removePeer(infoPeerId));for(var connPeerId in self._peerConnections)self._peerConnections.hasOwnProperty(connPeerId)&&self._peerConnections[connPeerId]&&-1===peersThatLeft.indexOf(connPeerId)&&(peersThatLeft.push(connPeerId),self._removePeer(connPeerId));if(self._inRoom=!1,self._closeChannel(),isNotInRoom){var notInRoomError="Unable to leave room as user is not in any room";return log.error([null,"Room",previousRoom,notInRoomError]),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}self._stopStreams({userMedia:stopUserMedia,screenshare:stopScreenshare}),self._wait(function(){log.log([null,"Room",previousRoom,"User left the room"]),self._trigger("peerLeft",previousUserPeerId,self.getPeerInfo(),!0),"function"==typeof callback&&callback(null,{peerId:previousUserPeerId,previousRoom:previousRoom})},function(){return!self._channelOpen})},Skylink.prototype.lockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!0),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!0}),this._roomLocked=!0,this._trigger("roomLock",!0,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype.unlockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!1),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!1}),this._roomLocked=!1,this._trigger("roomLock",!1,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype._waitForOpenChannel=function(mediaOptions,joinRoomTimestamp,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){var onChannelOpen=function(){self.off("socketError",onChannelError),setTimeout(function(){if(mediaOptions=mediaOptions||{},self._userData=mediaOptions.userData||self._userData||"",self._streamsBandwidthSettings={googleX:{},bAS:{}},self._publishOnly=!1,self._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},self._voiceActivityDetection="boolean"!=typeof mediaOptions.voiceActivityDetection||mediaOptions.voiceActivityDetection,self._peerConnectionConfig={bundlePolicy:self.BUNDLE_POLICY.BALANCED,rtcpMuxPolicy:self.RTCP_MUX_POLICY.REQUIRE,iceCandidatePoolSize:0,certificate:self.PEER_CERTIFICATE.AUTO,disableBundle:!1},self._bandwidthAdjuster=null,mediaOptions.bandwidth&&("number"==typeof mediaOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=mediaOptions.bandwidth.audio),"number"==typeof mediaOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=mediaOptions.bandwidth.video),"number"==typeof mediaOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=mediaOptions.bandwidth.data)),mediaOptions.googleXBandwidth&&("number"==typeof mediaOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=mediaOptions.googleXBandwidth.min),"number"==typeof mediaOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=mediaOptions.googleXBandwidth.max)),mediaOptions.sdpSettings&&(mediaOptions.sdpSettings.direction&&(mediaOptions.sdpSettings.direction.audio&&(self._sdpSettings.direction.audio.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.receive||mediaOptions.sdpSettings.direction.audio.receive,self._sdpSettings.direction.audio.send="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.send||mediaOptions.sdpSettings.direction.audio.send),mediaOptions.sdpSettings.direction.video&&(self._sdpSettings.direction.video.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.video.receive||mediaOptions.sdpSettings.direction.video.receive,
+self._sdpSettings.direction.video.send="boolean"!=typeof mediaOptions.sdpSettings.direction.video.send||mediaOptions.sdpSettings.direction.video.send)),mediaOptions.sdpSettings.connection&&(self._sdpSettings.connection.audio="boolean"!=typeof mediaOptions.sdpSettings.connection.audio||mediaOptions.sdpSettings.connection.audio,self._sdpSettings.connection.video="boolean"!=typeof mediaOptions.sdpSettings.connection.video||mediaOptions.sdpSettings.connection.video,self._sdpSettings.connection.data="boolean"!=typeof mediaOptions.sdpSettings.connection.data||mediaOptions.sdpSettings.connection.data)),mediaOptions.publishOnly&&(self._sdpSettings.direction.audio.send=!0,self._sdpSettings.direction.audio.receive=!1,self._sdpSettings.direction.video.send=!0,self._sdpSettings.direction.video.receive=!1,self._publishOnly=!0,"object"==typeof mediaOptions.publishOnly&&mediaOptions.publishOnly.parentId&&"string"==typeof mediaOptions.publishOnly.parentId&&(self._parentId=mediaOptions.publishOnly.parentId)),mediaOptions.parentId&&(self._parentId=mediaOptions.parentId),mediaOptions.peerConnection&&"object"==typeof mediaOptions.peerConnection){if("string"==typeof mediaOptions.peerConnection.bundlePolicy)for(var bpProp in self.BUNDLE_POLICY)self.BUNDLE_POLICY.hasOwnProperty(bpProp)&&self.BUNDLE_POLICY[bpProp]===mediaOptions.peerConnection.bundlePolicy&&(self._peerConnectionConfig.bundlePolicy=mediaOptions.peerConnection.bundlePolicy);if("string"==typeof mediaOptions.peerConnection.rtcpMuxPolicy)for(var rmpProp in self.RTCP_MUX_POLICY)self.RTCP_MUX_POLICY.hasOwnProperty(rmpProp)&&self.RTCP_MUX_POLICY[rmpProp]===mediaOptions.peerConnection.rtcpMuxPolicy&&(self._peerConnectionConfig.rtcpMuxPolicy=mediaOptions.peerConnection.rtcpMuxPolicy);if("number"==typeof mediaOptions.peerConnection.iceCandidatePoolSize&&mediaOptions.peerConnection.iceCandidatePoolSize>0&&(self._peerConnectionConfig.iceCandidatePoolSize=mediaOptions.peerConnection.iceCandidatePoolSize),"string"==typeof mediaOptions.peerConnection.certificate)for(var pcProp in self.PEER_CERTIFICATE)self.PEER_CERTIFICATE.hasOwnProperty(pcProp)&&self.PEER_CERTIFICATE[pcProp]===mediaOptions.peerConnection.certificate&&(self._peerConnectionConfig.certificate=mediaOptions.peerConnection.certificate);self._peerConnectionConfig.disableBundle=!0===mediaOptions.peerConnection.disableBundle}if(mediaOptions.autoBandwidthAdjustment&&(self._bandwidthAdjuster={interval:10,limitAtPercentage:100,useUploadBwOnly:!1},"object"==typeof mediaOptions.autoBandwidthAdjustment&&("number"==typeof mediaOptions.autoBandwidthAdjustment.interval&&mediaOptions.autoBandwidthAdjustment.interval>=10&&(self._bandwidthAdjuster.interval=mediaOptions.autoBandwidthAdjustment.interval),"number"==typeof mediaOptions.autoBandwidthAdjustment.limitAtPercentage&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage>=0&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage<=100&&(self._bandwidthAdjuster.limitAtPercentage=mediaOptions.autoBandwidthAdjustment.limitAtPercentage),"boolean"==typeof mediaOptions.autoBandwidthAdjustment.useUploadBwOnly&&(self._bandwidthAdjuster.useUploadBwOnly=mediaOptions.autoBandwidthAdjustment.useUploadBwOnly))),!0===mediaOptions.manualGetUserMedia){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){!0===mediaAccessRequiredFailure?self._onUserMediaError(new Error("Waiting for stream timeout"),!1,!1):callback(null,self._streams.userMedia.stream)},function(){return current50Block+=1,600===current50Block?(mediaAccessRequiredFailure=!0,!0):!(!self._streams.userMedia||!self._streams.userMedia.stream)||void 0},50)}if(mediaOptions.audio||mediaOptions.video)return void self.getUserMedia({useExactConstraints:!!mediaOptions.useExactConstraints,audio:mediaOptions.audio,video:mediaOptions.video},function(error,success){error?callback(error,null):callback(null,success)});callback(null,null)},1)},onChannelError=function(errorState,error){self.off("channelOpen",onChannelOpen),callback(error)};self._channelOpen?onChannelOpen():(self.once("channelOpen",onChannelOpen),self.once("socketError",onChannelError,function(errorState){return errorState===self.SOCKET_ERROR.RECONNECTION_ABORTED}),self._openChannel(joinRoomTimestamp))},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.generateUUID=function(){var d=(new Date).getTime();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"===c?r:r&&15).toString(16)})},Skylink.prototype.init=function(_options,_callback){var self=this,options={},callback=function(){};if("function"==typeof _options?callback=_options:_options&&"object"==typeof _options?(options=clone(_options),options.appKey&&"string"==typeof options.appKey||!options.apiKey||"string"!=typeof options.apiKey||(options.appKey=options.apiKey)):_options&&"string"==typeof _options&&(options.appKey=_options),"function"==typeof _callback&&(callback=_callback),options.defaultRoom=options.defaultRoom&&"string"==typeof options.defaultRoom?options.defaultRoom:options.appKey,options.roomServer=options.roomServer&&"string"==typeof options.roomServer?options.roomServer:"//api.temasys.io",options.enableIceTrickle=!1!==options.enableIceTrickle,options.enableDataChannel=!1!==options.enableDataChannel,options.enableSTUNServer=!1!==options.enableSTUNServer,options.enableTURNServer=!1!==options.enableTURNServer,options.audioFallback=!0===options.audioFallback,options.forceSSL=!1!==options.forceSSL,options.socketTimeout="number"==typeof options.socketTimeout&&options.socketTimeout>=5e3?options.socketTimeout:7e3,options.apiTimeout="number"==typeof options.apiTimeout?options.apiTimeout:4e3,options.forceTURNSSL=!0===options.forceTURNSSL,options.forceTURN=!0===options.forceTURN,options.usePublicSTUN=!0===options.usePublicSTUN,options.disableVideoFecCodecs=!0===options.disableVideoFecCodecs,options.disableComfortNoiseCodec=!0===options.disableComfortNoiseCodec,options.disableREMB=!0===options.disableREMB,options.throttleShouldThrowError=!0===options.throttleShouldThrowError,options.mcuUseRenegoRestart=!0===options.mcuUseRenegoRestart,options.useEdgeWebRTC=!0===options.useEdgeWebRTC,options.enableSimultaneousTransfers=!1!==options.enableSimultaneousTransfers,options.priorityWeightScheme=self._containsInList("PRIORITY_WEIGHT_SCHEME",options.priorityWeightScheme,"AUTO"),options.TURNServerTransport=self._containsInList("TURN_TRANSPORT",options.TURNServerTransport,"ANY"),options.credentials=options.credentials&&"object"==typeof options.credentials&&options.credentials.startDateTime&&"string"==typeof options.credentials.startDateTime&&options.credentials.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration?options.credentials:null,options.filterCandidatesType=options.filterCandidatesType&&"object"==typeof options.filterCandidatesType?options.filterCandidatesType:{},options.filterCandidatesType.host=!0===options.filterCandidatesType.host,options.filterCandidatesType.srflx=!0===options.filterCandidatesType.srflx,options.filterCandidatesType.relay=!0===options.filterCandidatesType.relay,options.throttleIntervals=options.throttleIntervals&&"object"==typeof options.throttleIntervals?options.throttleIntervals:{},options.throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:1e4,options.throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:5e3,options.throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:0,options.iceServer&&"string"==typeof options.iceServer?options.iceServer={urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0?options.iceServer={urls:options.iceServer}:options.iceServer=null,options.socketServer&&"string"==typeof options.socketServer?options.socketServer=options.socketServer:options.socketServer&&"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url?options.socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)?options.socketServer.ports:[],protocol:options.socketServer.protocol?options.socketServer.protocol:null}:options.socketServer=null,options.audioCodec&&"object"==typeof options.audioCodec&&self._containsInList("AUDIO_CODEC",options.audioCodec.codec,"-")?options.audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels?options.audioCodec.channels:null}:options.audioCodec=self._containsInList("AUDIO_CODEC",options.audioCodec,"AUTO"),options.videoCodec&&"object"==typeof options.videoCodec&&self._containsInList("VIDEO_CODEC",options.videoCodec.codec,"-")?options.videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate?options.videoCodec.samplingRate:null}:options.videoCodec=self._containsInList("VIDEO_CODEC",options.videoCodec,"AUTO"),options.codecParams=options.codecParams&&"object"==typeof options.codecParams?options.codecParams:{},options.codecParams.audio=options.codecParams.audio&&"object"==typeof options.codecParams.audio?options.codecParams.audio:{},options.codecParams.video=options.codecParams.video&&"object"==typeof options.codecParams.video?options.codecParams.video:{},options.codecParams.audio.opus=options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus?options.codecParams.audio.opus:{},options.codecParams.audio.opus.stereo="boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,options.codecParams.audio.opus["sprop-stereo"]="boolean"==typeof options.codecParams.audio.opus["sprop-stereo"]?options.codecParams.audio.opus["sprop-stereo"]:null,options.codecParams.audio.opus.usedtx="boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,options.codecParams.audio.opus.useinbandfec="boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,options.codecParams.audio.opus.maxplaybackrate="number"==typeof options.codecParams.audio.opus.maxplaybackrate&&options.codecParams.audio.opus.maxplaybackrate>=8e3&&options.codecParams.audio.opus.maxplaybackrate<=48e3?options.codecParams.audio.opus.maxplaybackrate:null,options.codecParams.audio.opus.minptime="number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null,options.codecParams.video.h264=options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264?options.codecParams.video.h264:{},options.codecParams.video.h264.profileLevelId=options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,options.codecParams.video.h264.levelAsymmetryAllowed="boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,options.codecParams.video.h264.packetizationMode="boolean"==typeof options.codecParams.video.h264.packetizationMode?!0===options.codecParams.video.h264.packetizationMode?1:0:"number"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null,options.codecParams.video.vp8=options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8?options.codecParams.video.vp8:{},options.codecParams.video.vp8.maxFs="number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,options.codecParams.video.vp8.maxFr="number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null,options.codecParams.video.vp9=options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9?options.codecParams.video.vp9:{},options.codecParams.video.vp9.maxFs="number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,options.codecParams.video.vp9.maxFr="number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null,options.forceTURN&&(options.enableTURNServer=!0,options.enableSTUNServer=!1,options.filterCandidatesType.host=!0,options.filterCandidatesType.srflx=!0,options.filterCandidatesType.relay=!1),self.once("readyStateChange",function(){},function(state,error){if(state===self.READY_STATE_CHANGE.ERROR)return log.error("Failed init() process ->",error),callback({error:error.content,errorCode:error.errorCode,status:error.status},null),!0;if(state===self.READY_STATE_CHANGE.COMPLETED){log.info("Completed init() successfully ->",options);var success=clone(self._initOptions);return success.serverUrl=self._path,success.readyState=self._readyState,success.selectedRoom=self._selectedRoom,success.TURNTransport=success.TURNServerTransport,callback(null,success),!0}}),self._initOptions=options,self._readyState=self.READY_STATE_CHANGE.INIT,self._selectedRoom=self._initOptions.defaultRoom,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),!options||!options.appKey||"string"!=typeof options.appKey)return self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{content:new Error("Please provide an app key"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH,status:-2},self._selectedRoom);self._path=self._initOptions.roomServer+"/api/"+self._initOptions.appKey+"/"+self._selectedRoom+(self._initOptions.credentials?"/"+self._initOptions.credentials.startDateTime+"/"+self._initOptions.credentials.duration+"?cred="+self._initOptions.credentials.credentials:"")+(self._initOptions.credentials?"&":"?")+"rand="+Date.now(),self._loadInfo()},Skylink.prototype._containsInList=function(listName,value,defaultProperty){var self=this;for(var property in self[listName])if(self[listName].hasOwnProperty(property)&&self[listName][property]===value)return value;return self[listName][defaultProperty]},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,retries=0;self._socketUseXDR="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest,url=self._initOptions.forceSSL?"https:"+url:url,function requestFn(){var xhr=new XMLHttpRequest,completed=!1;self._socketUseXDR&&(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest for CORS authentication."]),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}),xhr.onload=function(){if(!completed){completed=!0;var response=JSON.parse(xhr.responseText||xhr.response||"{}"),status=xhr.status||(response.success?200:400);if(response.success)return log.debug([null,"XMLHttpRequest",method,"Received sessions parameters ->"],response),void callback(response);log.error([null,"XMLHttpRequest",method,"Failed retrieving sessions parameters ->"],response),self._readyState=self.READY_STATE_CHANGE.ERROR,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:new Error(response.info||"XMLHttpRequest status not OK\nStatus was: "+status),errorCode:response.error||status},self._selectedRoom)}},xhr.onerror=function(error){completed||(completed=!0,log.error([null,"XMLHttpRequest",method,"Failed retrieving information with status ->"],xhr.status),self._readyState=self.READY_STATE_CHANGE.ERROR,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||-1,content:new Error("Network error occurred. (Status: "+xhr.status+")"),errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom))},xhr.onprogress=function(){log.debug([null,"XMLHttpRequest",method,"Retrieving information and config from webserver ->"],{url:url,params:params})};try{xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()}catch(error){return completed=!0,self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||-1,content:new Error("Failed starting XHR process."),errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom)}setTimeout(function(){completed||(completed=!0,xhr.onload=null,xhr.onerror=null,xhr.onprogress=null,retries<2?(retries++,requestFn()):(self._readyState=self.READY_STATE_CHANGE.ERROR,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||-1,content:new Error("Response timed out from API server"),errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_NO_REPONSE_ERROR},self._selectedRoom)))},self._initOptions.apiTimeout)}()},Skylink.prototype._parseInfo=function(info){if(log.log("Parsing parameter from server",info),!info.pc_constraints&&!info.offer_constraints)return void this._trigger("readyStateChange",this.READY_STATE_CHANGE.ERROR,{status:200,content:info.info,errorCode:info.error},self._selectedRoom);log.debug("Peer connection constraints:",info.pc_constraints),log.debug("Offer constraints:",info.offer_constraints),this._key=info.cid,this._appKeyOwner=info.apiOwner,this._signalingServer=info.ipSigserver,this._isPrivileged=info.isPrivileged,this._autoIntroduce=info.autoIntroduce,this._user={uid:info.username,token:info.userCred,timeStamp:info.timeStamp,streams:[],info:{}},this._room={id:info.room_key,token:info.roomCred,startDateTime:info.start,duration:info.len,connection:{peerConstraints:JSON.parse(info.pc_constraints),peerConfig:null,offerConstraints:JSON.parse(info.offer_constraints),sdpConstraints:{mandatory:{OfferToReceiveAudio:!0,OfferToReceiveVideo:!0}},mediaConstraints:JSON.parse(info.media_constraints)}},this._socketPorts={"http:":Array.isArray(info.httpPortList)&&info.httpPortList.length>0?info.httpPortList:[80,3e3],"https:":Array.isArray(info.httpsPortList)&&info.httpsPortList.length>0?info.httpsPortList:[443,3443]},this._readyState=this.READY_STATE_CHANGE.COMPLETED,this._trigger("readyStateChange",this.READY_STATE_CHANGE.COMPLETED,null,this._selectedRoom),log.info("Parsed parameters from webserver. Ready for web-realtime communication")},Skylink.prototype._loadInfo=function(){var self=this;if("function"!=typeof(globals.AdapterJS||window.AdapterJS||{}).webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used"),errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return globals.io||window.io?window.XMLHttpRequest?self._path?void AdapterJS.webRTCReady(function(){if(self._enableIceRestart="firefox"!==AdapterJS.webrtcDetectedBrowser||AdapterJS.webrtcDetectedVersion>=48,self._binaryChunkType="firefox"===AdapterJS.webrtcDetectedBrowser?self.DATA_TRANSFER_DATA_TYPE.BLOB:self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&"plugin"===AdapterJS.webrtcDetectedType?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("plugin"===AdapterJS.webrtcDetectedType&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error(error.message||error.toString()),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):0===Object.keys(self._currentCodecSupport.audio).length&&0===Object.keys(self._currentCodecSupport.video).length?(log.error("No audio/video codecs available to start connection."),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("No audio/video codecs available to start connection"),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=self.READY_STATE_CHANGE.LOADING,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(response){self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("No API Path is found"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_PATH},self._selectedRoom)):(log.error("XMLHttpRequest not supported. Please upgrade your browser"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("XMLHttpRequest not available"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_XMLHTTPREQUEST_SUPPORT},self._selectedRoom)):(log.error("Socket.io not loaded. Please load socket.io"),self._readyState=self.READY_STATE_CHANGE.ERROR,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:-2,content:new Error("Socket.io not found"),errorCode:self.READY_STATE_CHANGE_ERROR.NO_SOCKET_IO},self._selectedRoom))},Skylink.prototype._initSelectedRoom=function(room,callback){var self=this;if("function"==typeof room||void 0===room)return log.error("Invalid room provided. Room:",room),void callback(new Error("Invalid room provided"),null);var defaultRoom=self._initOptions.defaultRoom,options=clone(self._initOptions);options.iceServer=options.iceServer?options.iceServer.urls:null,options.defaultRoom!==room&&(options.defaultRoom=room),self.init(options,function(error,success){self._initOptions.defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})};var _LOG_KEY="SkylinkJS",_LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!1,_printTimestamp=!1,_storedLogs=[],_getStoredLogsFn=function(logLevel){if(void 0===logLevel)return _storedLogs;for(var returnLogs=[],i=0;i<_storedLogs.length;i++)_storedLogs[i][1]===_LOG_LEVELS[logLevel]&&returnLogs.push(_storedLogs[i]);return returnLogs},_clearAllStoredLogsFn=function(){_storedLogs=[]},_printAllStoredLogsFn=function(){for(var i=0;i<_storedLogs.length;i++){var timestamp=_storedLogs[i][0],log="undefined"!==console[_storedLogs[i][1]]?_storedLogs[i][1]:"log",message=_storedLogs[i][2],debugObject=_storedLogs[i][3];void 0!==debugObject?console[log](message,debugObject,timestamp):console[log](message,timestamp)}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="",datetime=new Date;if("object"==typeof message){if(outputLog+=message[0]?" ["+message[0]+"] -":" -",outputLog+=message[1]?" <<"+message[1]+">>":"",message[2])if(outputLog+=" ","object"==typeof message[2])for(var i=0;i=logLevel)if(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace){void 0===console.trace&&logLevel[3];void 0!==debugObject?(console[_LOG_LEVELS[logLevel]](outputLog,debugObject),void 0!==console.trace&&console.trace("")):(console[_LOG_LEVELS[logLevel]](outputLog),void 0!==console.trace&&console.trace(""))}else void 0!==debugObject?console[_LOG_LEVELS[logLevel]](outputLog,debugObject):console[_LOG_LEVELS[logLevel]](outputLog)},log={debug:function(message,object){_logFn(4,message,object)},log:function(message,object){_logFn(3,message,object)},info:function(message,object){_logFn(2,message,object)},warn:function(message,object){_logFn(1,message,object)},error:function(message,object){_logFn(0,message,object)}};Skylink.prototype.setLogLevel=function(logLevel){for(var level in this.LOG_LEVEL)if(this.LOG_LEVEL[level]===logLevel)return _logLevel=logLevel,void log.log([null,"Log",level,"Log level exists. Level is set"]);log.error([null,"Log",level,"Log level does not exist. Level is not set"])},Skylink.prototype.setDebugMode=function(isDebugMode){isDebugMode&&"object"==typeof isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0===isDebugMode.trace,_enableDebugStack=!0===isDebugMode.storeLogs,_printTimestamp=!0===isDebugMode.printTimestamp):!0===isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0,_printTimestamp=!1):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1,_printTimestamp=!1)};Skylink.prototype.on=function(eventName,callback){"function"==typeof callback?(this._EVENTS[eventName]=this._EVENTS[eventName]||[],this._EVENTS[eventName].push(callback),log.log([null,"Event",eventName,"Event is subscribed"])):log.error([null,"Event",eventName,"Provided parameter is not a function"])},Skylink.prototype.once=function(eventName,callback,condition,fireAlways){"boolean"==typeof condition&&(fireAlways=condition,condition=null),fireAlways=void 0!==fireAlways&&fireAlways,condition="function"!=typeof condition?function(){return!0}:condition,"function"==typeof callback?(this._onceEvents[eventName]=this._onceEvents[eventName]||[],this._onceEvents[eventName].push([callback,condition,fireAlways]),log.log([null,"Event",eventName,"Event is subscribed on condition"])):log.error([null,"Event",eventName,"Provided callback is not a function"])},Skylink.prototype.off=function(eventName,callback){if(eventName&&"string"==typeof eventName){if(void 0===callback)return this._EVENTS[eventName]=[],this._onceEvents[eventName]=[],void log.log([null,"Event",eventName,"All events are unsubscribed"]);for(var arr=this._EVENTS[eventName]||[],once=this._onceEvents[eventName]||[],i=0;i"],message);self._user.sid&&!self._peerMessagesStamps[self._user.sid]&&(self._peerMessagesStamps[self._user.sid]={userData:0,audioMuted:0,videoMuted:0});var checkStampFn=function(statusMessage){return statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].userData:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].videoMuted:statusMessage.type!==self._SIG_MESSAGE_TYPE.MUTE_AUDIO||!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].audioMuted},setStampFn=function(statusMessage){statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?self._peerMessagesStamps[self._user.sid].userData=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?self._peerMessagesStamps[self._user.sid].videoMuted=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&(self._peerMessagesStamps[self._user.sid].audioMuted=statusMessage.stamp)},setQueueFn=function(){log.debug([null,"Socket",null,"Starting queue timeout"]),self._socketMessageTimeout=setTimeout(function(){if((new Date).getTime()-self._timestamp.socketMessage<=interval)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},interval-((new Date).getTime()-self._timestamp.socketMessage))},triggerEventFn=function(eventMessage){eventMessage.type===self._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE&&self._trigger("incomingMessage",{content:eventMessage.data,isPrivate:!1,targetPeerId:null,listOfPeers:Object.keys(self._peerInformations),isDataChannel:!1,senderPeerId:self._user.sid},self._user.sid,self.getPeerInfo(),!0)},sendGroupMessageFn=function(groupMessageList){if(self._socketMessageTimeout=null,!(self._channelOpen&&self._user&&self._user.sid&&self._socket))return void log.warn([message.target||"Server","Socket",null,"Dropping of group messages as Socket connection is not opened or is at incorrect step ->"],groupMessageList);for(var strGroupMessageList=[],stamps={userData:0,audioMuted:0,videoMuted:0
+},k=0;kself._peerMessagesStamps[self._user.sid].userData&&groupMessageList[k].stamp>stamps.userData?stamps.userData=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].audioMuted&&groupMessageList[k].stamp>stamps.audioMuted?stamps.audioMuted=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].videoMuted&&groupMessageList[k].stamp>stamps.videoMuted&&(stamps.videoMuted=groupMessageList[k].stamp));for(var i=0;i"],clone(groupMessageList[i])),groupMessageList.splice(i,1),i--):strGroupMessageList.push(JSON.stringify(groupMessageList[i]));if(strGroupMessageList.length>0){var groupMessage={type:self._SIG_MESSAGE_TYPE.GROUP,lists:strGroupMessageList,mid:self._user.sid,rid:self._room.id};log.log([message.target||"Server","Socket",groupMessage.type,"Sending queued grouped message (max: 16 per group) ->"],clone(groupMessage)),self._socket.send(JSON.stringify(groupMessage)),self._timestamp.socketMessage=(new Date).getTime();for(var j=0;j0&&(self._socketMessageQueue.length-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=interval)log.debug([message.target||"Server","Socket",message.type,"Queueing socket message to prevent message drop ->"],clone(message)),self._socketMessageQueue.push(message),self._socketMessageTimeout||setQueueFn();else{if(!checkStampFn(message))return void log.warn([message.target||"Server","Socket",message.type,"Dropping of outdated status message ->"],clone(message));self._socketMessageTimeout&&clearTimeout(self._socketMessageTimeout),log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),setStampFn(message),triggerEventFn(message),self._timestamp.socketMessage=(new Date).getTime()}else log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),message.type===self._SIG_MESSAGE_TYPE.BYE&&self._inRoom&&self._user&&self._user.sid&&message.mid===self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo()))},Skylink.prototype._createSocket=function(type,joinRoomTimestamp){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._initOptions.socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._initOptions.socketServer&&"object"==typeof self._initOptions.socketServer&&Array.isArray(self._initOptions.socketServer.ports)&&self._initOptions.socketServer.ports.length>0?self._initOptions.socketServer.ports:self._socketPorts[self._signalingServerProtocol],fallbackType=null;null===self._signalingServerPort?(self._signalingServerPort=ports[0],fallbackType=self.SOCKET_FALLBACK.NON_FALLBACK):ports.indexOf(self._signalingServerPort)===ports.length-1||"string"==typeof self._initOptions.socketServer?"WebSocket"===type?(type="Polling",self._signalingServerPort=ports[0]):self._socketSession.finalAttempts++:self._signalingServerPort=ports[ports.indexOf(self._signalingServerPort)+1],"Polling"===type&&(options.reconnectionDelayMax=1e3,options.reconnectionAttempts=4,options.transports=["xhr-polling","jsonp-polling","polling"]);var url=self._signalingServerProtocol+"//"+self._signalingServer+":"+self._signalingServerPort+"?rand="+Date.now(),retries=0;self._initOptions.socketServer&&(url="string"==typeof self._initOptions.socketServer?self._initOptions.socketServer:(self._initOptions.socketServer.protocol?self._initOptions.socketServer.protocol:self._signalingServerProtocol)+"//"+self._initOptions.socketServer.url+":"+self._signalingServerPort),self._socketSession.transportType=type,self._socketSession.socketOptions=options,self._socketSession.socketServer=url,null===fallbackType&&(fallbackType="http:"===self._signalingServerProtocol?"Polling"===type?self.SOCKET_FALLBACK.LONG_POLLING:self.SOCKET_FALLBACK.FALLBACK_PORT:"Polling"===type?self.SOCKET_FALLBACK.LONG_POLLING_SSL:self.SOCKET_FALLBACK.FALLBACK_SSL_PORT,self._socketSession.attempts++,self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ATTEMPT,null,fallbackType,clone(self._socketSession)),self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))),self._socket&&self._closeChannel(),self._channelOpen=!1,log.log("Opening channel with signaling server url:",clone(self._socketSession));var socket=null;try{socket=io.connect(url,options)}catch(error){return log.error("Failed creating socket connection object ->",error),fallbackType===self.SOCKET_FALLBACK.NON_FALLBACK?self._trigger("socketError",self.SOCKET_ERROR.CONNECTION_FAILED,error,fallbackType,clone(self._socketSession)):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_FAILED,error,fallbackType,clone(self._socketSession)),void self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ABORTED,new Error("Reconnection aborted as there no more available ports, transports and final attempts left."),fallbackType,clone(self._socketSession))}socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),socket.on("reconnect_failed",function(){fallbackType===self.SOCKET_FALLBACK.NON_FALLBACK?self._trigger("socketError",self.SOCKET_ERROR.CONNECTION_FAILED,new Error('Failed connection with transport "'+type+'" and port '+self._signalingServerPort+"."),fallbackType,clone(self._socketSession)):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_FAILED,new Error('Failed reconnection with transport "'+type+'" and port '+self._signalingServerPort+"."),fallbackType,clone(self._socketSession)),self._socketSession.finalAttempts<2?self._createSocket(type,joinRoomTimestamp):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ABORTED,new Error("Reconnection aborted as there no more available ports, transports and final attempts left."),fallbackType,clone(self._socketSession))}),socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),socket.on("error",function(error){if(error&&error.message.indexOf("xhr poll error")>-1)return log.error([null,"Socket",null,"XHR poll connection unstable. Disconnecting.. ->"],error),void self._closeChannel();log.error([null,"Socket",null,"Exception occurred ->"],error),self._trigger("channelError",error,clone(self._socketSession))}),socket.on("disconnect",function(){self._channelOpen&&(self._channelOpen=!1,self._trigger("channelClose",clone(self._socketSession)),log.log([null,"Socket",null,"Channel closed"]),self._inRoom&&self._user&&self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo())))}),socket.on("message",function(messageStr){var message=JSON.parse(messageStr);if(log.log([null,"Socket",null,"Received message ->"],message),message.type===self._SIG_MESSAGE_TYPE.GROUP){log.debug("Bundle of "+message.lists.length+" messages");for(var i=0;i",message);for(var i=0;i-1:state===self.RECORDING_STATE.STOP})}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.STOP_RECORDING,rid:self._room.id,target:"MCU"}),log.debug(["MCU","Recording",null,"Stopping recording"])},Skylink.prototype.getRecordings=function(){return clone(this._recordings)},Skylink.prototype._processSigMessage=function(message,session){var origin=message.mid;if(origin&&origin!==this._user.sid||(origin="Server"),log.debug([origin,"Socket",message.type,"Received from peer ->"],clone(message)),message.mid===this._user.sid&&message.type!==this._SIG_MESSAGE_TYPE.REDIRECT&&message.type!==this._SIG_MESSAGE_TYPE.IN_ROOM)return void log.debug([origin,"Socket",message.type,"Ignoring message ->"],clone(message));switch(message.type){case this._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE:this._publicMessageHandler(message);break;case this._SIG_MESSAGE_TYPE.PRIVATE_MESSAGE:this._privateMessageHandler(message);break;case this._SIG_MESSAGE_TYPE.IN_ROOM:this._inRoomHandler(message);break;case this._SIG_MESSAGE_TYPE.ENTER:this._enterHandler(message);break;case this._SIG_MESSAGE_TYPE.WELCOME:this._welcomeHandler(message);break;case this._SIG_MESSAGE_TYPE.RESTART:this._restartHandler(message);break;case this._SIG_MESSAGE_TYPE.OFFER:this._offerHandler(message);break;case this._SIG_MESSAGE_TYPE.ANSWER:this._answerHandler(message);break;case this._SIG_MESSAGE_TYPE.CANDIDATE:this._candidateHandler(message);break;case this._SIG_MESSAGE_TYPE.BYE:this._byeHandler(message);break;case this._SIG_MESSAGE_TYPE.REDIRECT:this._redirectHandler(message);break;case this._SIG_MESSAGE_TYPE.UPDATE_USER:this._updateUserEventHandler(message);break;case this._SIG_MESSAGE_TYPE.MUTE_VIDEO:this._muteVideoEventHandler(message);break;case this._SIG_MESSAGE_TYPE.MUTE_AUDIO:this._muteAudioEventHandler(message);break;case this._SIG_MESSAGE_TYPE.STREAM:this._streamEventHandler(message);break;case this._SIG_MESSAGE_TYPE.ROOM_LOCK:this._roomLockEventHandler(message);break;case this._SIG_MESSAGE_TYPE.PEER_LIST:this._peerListEventHandler(message);break;case this._SIG_MESSAGE_TYPE.INTRODUCE_ERROR:this._introduceErrorEventHandler(message);break;case this._SIG_MESSAGE_TYPE.APPROACH:this._approachEventHandler(message);break;case this._SIG_MESSAGE_TYPE.RECORDING:this._recordingEventHandler(message);break;case this._SIG_MESSAGE_TYPE.END_OF_CANDIDATES:this._endOfCandidatesHandler(message);break;default:log.error([message.mid,"Socket",message.type,"Unsupported message ->"],clone(message))}},Skylink.prototype._peerListEventHandler=function(message){var self=this;self._peerList=message.result,log.log(["Server",null,message.type,"Received list of peers"],self._peerList),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.RECEIVED,self._user.sid,self._peerList)},Skylink.prototype._endOfCandidatesHandler=function(message){var self=this,targetMid=message.mid;self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&(self._peerEndOfCandidatesCounter[targetMid].expectedLen=message.noOfExpectedCandidates||0,self._signalingEndOfCandidates(targetMid))},Skylink.prototype._introduceErrorEventHandler=function(message){var self=this;log.log(["Server",null,message.type,"Introduce failed. Reason: "+message.reason]),self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,message.sendingPeerId,message.receivingPeerId,message.reason)},Skylink.prototype._approachEventHandler=function(message){var self=this;log.log(["Server",null,message.type,"Approaching peer"],message.target),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._initOptions.enableIceTrickle,enableDataChannel:self._initOptions.enableDataChannel,enableIceRestart:self._enableIceRestart,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(enterMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(enterMsg.parentId=self._parentId),self._sendChannelMessage(enterMsg)},Skylink.prototype._redirectHandler=function(message){if(log.log(["Server",null,message.type,"System action warning:"],{message:message.info,reason:message.reason,action:message.action}),message.action===this.SYSTEM_ACTION.REJECT)for(var key in this._peerConnections)this._peerConnections.hasOwnProperty(key)&&this._removePeer(key);"toClose"===message.reason&&(message.reason="toclose"),this._trigger("systemAction",message.action,message.info,message.reason)},Skylink.prototype._updateUserEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer updated userData:"],message.userData),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].userData=message.stamp}this._peerInformations[targetMid].userData=message.userData||{},this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,null,message.type,"Peer does not have any user information"])},Skylink.prototype._roomLockEventHandler=function(message){var targetMid=message.mid;log.log([targetMid,message.type,"Room lock status:"],message.lock),this._trigger("roomLock",message.lock,targetMid,this.getPeerInfo(targetMid),!1)},Skylink.prototype._muteAudioEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's audio muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp"],message);this._peerMessagesStamps[targetMid].audioMuted=message.stamp}this._peerInformations[targetMid].mediaStatus.audioMuted=message.muted,this._trigger("streamMuted",targetMid,this.getPeerInfo(targetMid),!1,this._peerInformations[targetMid].settings.video&&this._peerInformations[targetMid].settings.video.screenshare),this._trigger("peerUpdated",targetMid,this.getPeerInfo(targetMid),!1)}else log.log([targetMid,message.type,"Peer does not have any user information"])},Skylink.prototype._muteVideoEventHandler=function(message){var targetMid=message.mid;if(log.log([targetMid,null,message.type,"Peer's video muted:"],message.muted),this._peerInformations[targetMid]){if(this._peerMessagesStamps[targetMid]&&"number"==typeof message.stamp){if(message.stamp