From ac9f1de698193be8c8a6454ff6cb81aff9df5d2a Mon Sep 17 00:00:00 2001 From: Leticia Choo Date: Mon, 10 Apr 2017 13:03:09 +0800 Subject: [PATCH 01/11] ESS-857 Fixes to prevent _getCodecsSupport() from re-retrieving codecs supports list if it has already been retrieved. --- publish/skylink.complete.js | 10 +++------- publish/skylink.complete.min.js | 12 ++++++------ publish/skylink.debug.js | 8 ++------ publish/skylink.min.js | 12 ++++++------ source/room-init.js | 5 ----- source/stream-sdp.js | 1 + 6 files changed, 18 insertions(+), 30 deletions(-) diff --git a/publish/skylink.complete.js b/publish/skylink.complete.js index c6830af10..da812e5fe 100644 --- a/publish/skylink.complete.js +++ b/publish/skylink.complete.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Fri Apr 07 2017 21:09:15 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Mon Apr 10 2017 12:58:20 GMT+0800 (SGT) */ (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;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:this.onevent(packet);break;case parser.BINARY_EVENT:this.onevent(packet);break;case parser.ACK:this.onack(packet);break;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}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:function(){try{return window.localStorage}catch(e){}}(),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||void 0).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&&this.transports.indexOf("websocket")!=-1)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(/\\n/g,"\\\n"),this.area.value=data.replace(/\n/g,"\\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="[object Function]"==getClass.call(object);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="[object Function]"==getClass.call(object);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="[object Function]"==getClass.call(object),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"},toPaddedString=function(width,value){return("000000"+(value||0)).slice(-width)},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("[object Boolean]"==(className=getClass.call(value)))return""+value;if("[object Number]"==className)return value>-1/0&&value<1/0?""+value:"null";if("[object String]"==className)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,"[object Array]"==className){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("[object Array]"==getClass.call(value))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&&"[object Function]"==getClass.call(callback)?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=[];(tmp=decodeSymbol())!==!1;)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;i"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]);var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost), isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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),("edge"!==window.webrtcDetectedBrowser&&"edge"===peerInfo.agent.name?["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&!this._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&"edge"!==peerInfo.agent.name&&!this._currentCodecSupport.video.h264)&&(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i-1&&!self._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&"edge"!==agent.name&&!self._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&!self._currentCodecSupport.video.h264)&&(customSettingsList[peerId].settings.video=!1,customSettingsList[peerId].mediaStatus.videoMuted=!0),customSettingsList[peerId].settings.audio=!!self._sdpSettings.connection.audio&&customSettingsList[peerId].settings.audio,customSettingsList[peerId].settings.video=!!self._sdpSettings.connection.video&&customSettingsList[peerId].settings.video,customSettingsList[peerId].mediaStatus.audioMuted=!self._sdpSettings.connection.audio||customSettingsList[peerId].mediaStatus.audioMuted,customSettingsList[peerId].mediaStatus.videoMuted=!self._sdpSettings.connection.video||customSettingsList[peerId].mediaStatus.videoMuted}return customSettingsList},Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo()),peerInfo=clone(this.getPeerInfo(peerId));return 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),(peerId?"edge"!==window.webrtcDetectedBrowser&&"edge"===peerInfo.agent.name?["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&!this._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&"edge"!==peerInfo.agent.name&&!this._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&!this._currentCodecSupport.video.h264)&&(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart,peerBrowser){var self=this,pc=self._peerConnections[targetMid];if(log.log([targetMid,null,null,"Checking caller status"],peerBrowser),!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 peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._sdpSettings.connection.data||"MCU"===targetMid)&&(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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,"edge"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=self._setSDPCodec(targetMid,sessionDescription,{audio:self.AUDIO_CODEC.OPUS,video:self.VIDEO_CODEC.H264})),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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);var getCodecsSupportCalled=!1;self._getCodecsSupport(function(error){if(!getCodecsSupportCalled){if(getCodecsSupportCalled=!0,error)return log.error(error),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:error.message||error.toString(),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom);if(0===Object.keys(self._currentCodecSupport.audio).length&&0===Object.keys(self._currentCodecSupport.video).length)return log.error("No audio/video codecs available to start connection."),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom);self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){ -var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)})}})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==peerId),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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;self._currentCodecSupport&&callback(null),self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i-1&&"edge"===peerAgent)||!!self._currentCodecSupport.video.h264),self._hasMCU&&(settings.direction.audio.receive="MCU"!==targetMid,settings.direction.audio.send="MCU"===targetMid,settings.direction.video.receive="MCU"!==targetMid,settings.direction.video.send="MCU"===targetMid),self._sdpSessions[targetMid][direction].mLines=[],self._sdpSessions[targetMid][direction].bundleLine="";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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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},"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 +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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0, +void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==peerId),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i-1&&"edge"===peerAgent)||!!self._currentCodecSupport.video.h264),self._hasMCU&&(settings.direction.audio.receive="MCU"!==targetMid,settings.direction.audio.send="MCU"===targetMid,settings.direction.video.receive="MCU"!==targetMid,settings.direction.video.send="MCU"===targetMid),self._sdpSessions[targetMid][direction].mLines=[],self._sdpSessions[targetMid][direction].bundleLine="";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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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},"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 1d5b35558..3dae2bacb 100644 --- a/publish/skylink.debug.js +++ b/publish/skylink.debug.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Fri Apr 07 2017 21:09:15 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Mon Apr 10 2017 12:58:20 GMT+0800 (SGT) */ (function(globals) { @@ -10943,12 +10943,7 @@ Skylink.prototype._loadInfo = function() { return; } - var getCodecsSupportCalled = false; self._getCodecsSupport(function (error) { - if (getCodecsSupportCalled) { - return; - } - getCodecsSupportCalled = true; if (error) { log.error(error); self._readyState = -1; @@ -18235,6 +18230,7 @@ Skylink.prototype._getCodecsSupport = function (callback) { if (self._currentCodecSupport) { callback(null); + return; } self._currentCodecSupport = { audio: {}, video: {} }; diff --git a/publish/skylink.min.js b/publish/skylink.min.js index 7fa90834c..4f0e5bc75 100644 --- a/publish/skylink.min.js +++ b/publish/skylink.min.js @@ -1,12 +1,12 @@ -/*! skylinkjs - v0.6.19 - 2017-04-07 */ +/*! skylinkjs - v0.6.19 - 2017-04-10 */ !function(globals){"use strict";function Skylink(){this._enableDataChannel=!0,this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._filterCandidatesType={host:!1,srflx:!1,relay:!1},this._enableIceTrickle=!0,this._enableSTUN=!0,this._enableTURN=!0,this._usePublicSTUN=!0,this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._isUsingPlugin=!1,this._TURNTransport="any",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._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,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._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,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._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,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._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={}}!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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],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&&(self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")===-1||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"===window.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){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.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,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.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},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";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){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.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].indexOf(state)>-1}),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)}else 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),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),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}),delete self._dataTransfers[transferId]},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._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._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.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},i=0;i-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}})}(peerId,channelProp)}if(0===listOfPeers.length)return void log.warn("There are no Peers to start data session with.");self._dataStreams[transferId]={sessions:sessions,chunkType:"string"===sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:sessionChunkType,isPrivate:isPrivate,isStringStream:"string"===sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null,isUpload:!0};var startDataSessionFn=function(peerId,channelProp,targetPeers){if(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+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===window.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;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]);var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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),("edge"!==window.webrtcDetectedBrowser&&"edge"===peerInfo.agent.name?["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&!this._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&"edge"!==peerInfo.agent.name&&!this._currentCodecSupport.video.h264)&&(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i-1&&!self._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&"edge"!==agent.name&&!self._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&!self._currentCodecSupport.video.h264)&&(customSettingsList[peerId].settings.video=!1,customSettingsList[peerId].mediaStatus.videoMuted=!0),customSettingsList[peerId].settings.audio=!!self._sdpSettings.connection.audio&&customSettingsList[peerId].settings.audio, customSettingsList[peerId].settings.video=!!self._sdpSettings.connection.video&&customSettingsList[peerId].settings.video,customSettingsList[peerId].mediaStatus.audioMuted=!self._sdpSettings.connection.audio||customSettingsList[peerId].mediaStatus.audioMuted,customSettingsList[peerId].mediaStatus.videoMuted=!self._sdpSettings.connection.video||customSettingsList[peerId].mediaStatus.videoMuted}return customSettingsList},Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo()),peerInfo=clone(this.getPeerInfo(peerId));return 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),(peerId?"edge"!==window.webrtcDetectedBrowser&&"edge"===peerInfo.agent.name?["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&!this._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&"edge"!==peerInfo.agent.name&&!this._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&!this._currentCodecSupport.video.h264)&&(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart,peerBrowser){var self=this,pc=self._peerConnections[targetMid];if(log.log([targetMid,null,null,"Checking caller status"],peerBrowser),!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 peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._sdpSettings.connection.data||"MCU"===targetMid)&&(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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,"edge"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=self._setSDPCodec(targetMid,sessionDescription,{audio:self.AUDIO_CODEC.OPUS,video:self.VIDEO_CODEC.H264})),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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}), -options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);var getCodecsSupportCalled=!1;self._getCodecsSupport(function(error){if(!getCodecsSupportCalled){if(getCodecsSupportCalled=!0,error)return log.error(error),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:error.message||error.toString(),errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom);if(0===Object.keys(self._currentCodecSupport.audio).length&&0===Object.keys(self._currentCodecSupport.video).length)return log.error("No audio/video codecs available to start connection."),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom);self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)})}})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==peerId),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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;self._currentCodecSupport&&callback(null),self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i-1&&"edge"===peerAgent)||!!self._currentCodecSupport.video.h264),self._hasMCU&&(settings.direction.audio.receive="MCU"!==targetMid,settings.direction.audio.send="MCU"===targetMid,settings.direction.video.receive="MCU"!==targetMid,settings.direction.video.send="MCU"===targetMid),self._sdpSessions[targetMid][direction].mLines=[],self._sdpSessions[targetMid][direction].bundleLine="";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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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},"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 +options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==peerId),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i-1&&"edge"===peerAgent)||!!self._currentCodecSupport.video.h264),self._hasMCU&&(settings.direction.audio.receive="MCU"!==targetMid,settings.direction.audio.send="MCU"===targetMid,settings.direction.video.receive="MCU"!==targetMid,settings.direction.video.send="MCU"===targetMid),self._sdpSessions[targetMid][direction].mLines=[],self._sdpSessions[targetMid][direction].bundleLine="";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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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},"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/source/room-init.js b/source/room-init.js index f30c7e79b..9062ab0f0 100644 --- a/source/room-init.js +++ b/source/room-init.js @@ -1281,12 +1281,7 @@ Skylink.prototype._loadInfo = function() { return; } - var getCodecsSupportCalled = false; self._getCodecsSupport(function (error) { - if (getCodecsSupportCalled) { - return; - } - getCodecsSupportCalled = true; if (error) { log.error(error); self._readyState = -1; diff --git a/source/stream-sdp.js b/source/stream-sdp.js index 8705be2e2..f3d14db76 100644 --- a/source/stream-sdp.js +++ b/source/stream-sdp.js @@ -804,6 +804,7 @@ Skylink.prototype._getCodecsSupport = function (callback) { if (self._currentCodecSupport) { callback(null); + return; } self._currentCodecSupport = { audio: {}, video: {} }; From 0eb7c912efbf5dcf032f5ebac269f35d1b156f57 Mon Sep 17 00:00:00 2001 From: Leticia Choo Date: Mon, 17 Apr 2017 18:54:06 +0800 Subject: [PATCH 02/11] ESS-864 Updates to ensure Edge 15.15019 version works. --- demo/edge-attachmediastream.js | 4 +- publish/skylink.complete.js | 86 +++++++++++++++++---------------- publish/skylink.complete.min.js | 14 +++--- publish/skylink.debug.js | 84 +++++++++++++++++--------------- publish/skylink.min.js | 16 +++--- source/peer-data.js | 23 ++------- source/peer-handshake.js | 12 +---- source/stream-media.js | 6 +-- source/stream-sdp.js | 29 +++++++++-- 9 files changed, 139 insertions(+), 135 deletions(-) diff --git a/demo/edge-attachmediastream.js b/demo/edge-attachmediastream.js index ad613c5ac..81e89eb0c 100644 --- a/demo/edge-attachmediastream.js +++ b/demo/edge-attachmediastream.js @@ -3,7 +3,7 @@ * And Edge current does not support re-negotiation for now in the SDK. */ (function () { - if (window.webrtcDetectedBrowser === 'edge') { + if (window.webrtcDetectedBrowser === 'edge' && window.webrtcDetectedBrowser < 15.15019) { var attachMediaStream_base = attachMediaStream; attachMediaStream = function (elm, stream) { @@ -29,7 +29,7 @@ audioElm.style.height = 0; audioElm.style.width = 0; audioElm.autoplay = true; - audioElm.muted = !!elm.getAttribute('muted'); + audioElm.muted = !!elm.muted; document.body.appendChild(audioElm); diff --git a/publish/skylink.complete.js b/publish/skylink.complete.js index da812e5fe..61d21be71 100644 --- a/publish/skylink.complete.js +++ b/publish/skylink.complete.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Mon Apr 10 2017 12:58:20 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Mon Apr 17 2017 18:46:36 GMT+0800 (SGT) */ (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;o -1 && !this._currentCodecSupport.video.h264 : - // If User is Edge and Peer is not and no H264 support, remove video support - window.webrtcDetectedBrowser === 'edge' && peerInfo.agent.name !== 'edge' && !this._currentCodecSupport.video.h264) { + if (!this._getSDPEdgeVideoSupports(peerId)) { peerInfo.settings.video = false; peerInfo.mediaStatus.videoMuted = true; } @@ -19840,14 +19836,7 @@ Skylink.prototype.getPeersCustomSettings = function () { var agent = ((self._peerInformations[peerId] || {}).agent || {}).name || ''; // If there is Peer ID (not broadcast ENTER message) and Peer is Edge browser and User is not - if (customSettingsList[peerId].settings.video && (peerId ? - (window.webrtcDetectedBrowser !== 'edge' && agent.name === 'edge' ? - // If User is IE/safari and does not have H264 support, remove video support - ['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && !self._currentCodecSupport.video.h264 : - // If User is Edge and Peer is not and no H264 support, remove video support - window.webrtcDetectedBrowser === 'edge' && agent.name !== 'edge' && !self._currentCodecSupport.video.h264) : - // If broadcast ENTER message and User is Edge and has no H264 support - window.webrtcDetectedBrowser === 'edge' && !self._currentCodecSupport.video.h264)) { + if (customSettingsList[peerId].settings.video && !self._getSDPEdgeVideoSupports(peerId)) { customSettingsList[peerId].settings.video = false; customSettingsList[peerId].mediaStatus.videoMuted = true; } @@ -19910,13 +19899,7 @@ Skylink.prototype._getUserInfo = function(peerId) { } // If there is Peer ID (not broadcast ENTER message) and Peer is Edge browser and User is not - if (peerId ? (window.webrtcDetectedBrowser !== 'edge' && peerInfo.agent.name === 'edge' ? - // If User is IE/safari and does not have H264 support, remove video support - ['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && !this._currentCodecSupport.video.h264 : - // If User is Edge and Peer is not and no H264 support, remove video support - window.webrtcDetectedBrowser === 'edge' && peerInfo.agent.name !== 'edge' && !this._currentCodecSupport.video.h264) : - // If broadcast ENTER message and User is Edge and has no H264 support - window.webrtcDetectedBrowser === 'edge' && !this._currentCodecSupport.video.h264) { + if (!this._getSDPEdgeVideoSupports(peerId)) { userInfo.settings.video = false; userInfo.mediaStatus.videoMuted = true; } @@ -19975,14 +19958,10 @@ Skylink.prototype._doOffer = function(targetMid, iceRestart, peerBrowser) { return; } - var peerAgent = ((self._peerInformations[targetMid] || {}).agent || {}).name || ''; var doIceRestart = !!((self._peerInformations[targetMid] || {}).config || {}).enableIceRestart && iceRestart && self._enableIceRestart; var offerToReceiveAudio = !(!self._sdpSettings.connection.audio && targetMid !== 'MCU'); - var offerToReceiveVideo = !(!self._sdpSettings.connection.video && targetMid !== 'MCU') && - ((window.webrtcDetectedBrowser === 'edge' && peerAgent !== 'edge') || - (['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && peerAgent === 'edge') ? - !!self._currentCodecSupport.video.h264 : true); + var offerToReceiveVideo = !(!self._sdpSettings.connection.video && targetMid !== 'MCU') && self._getSDPEdgeVideoSupports(targetMid); var offerConstraints = { offerToReceiveAudio: offerToReceiveAudio, @@ -20076,12 +20055,8 @@ Skylink.prototype._doAnswer = function(targetMid) { self._addLocalMediaStreams(targetMid); } - var peerAgent = ((self._peerInformations[targetMid] || {}).agent || {}).name || ''; var offerToReceiveAudio = !(!self._sdpSettings.connection.audio && targetMid !== 'MCU'); - var offerToReceiveVideo = !(!self._sdpSettings.connection.video && targetMid !== 'MCU') && - ((window.webrtcDetectedBrowser === 'edge' && peerAgent !== 'edge') || - (['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && peerAgent === 'edge') ? - !!self._currentCodecSupport.video.h264 : true); + var offerToReceiveVideo = !(!self._sdpSettings.connection.video && targetMid !== 'MCU') && self._getSDPEdgeVideoSupports(targetMid); var answerConstraints = window.webrtcDetectedBrowser === 'edge' ? { offerToReceiveVideo: offerToReceiveVideo, offerToReceiveAudio: offerToReceiveAudio, @@ -24636,8 +24611,6 @@ Skylink.prototype._throttle = function(func, prop, wait){ func(false); } }; - - Skylink.prototype.SOCKET_ERROR = { CONNECTION_FAILED: 0, RECONNECTION_FAILED: -1, @@ -28897,11 +28870,9 @@ Skylink.prototype._addLocalMediaStreams = function(peerId) { var pc = self._peerConnections[peerId]; var peerAgent = ((self._peerInformations[peerId] || {}).agent || {}).name || ''; + var peerVersion = ((self._peerInformations[peerId] || {}).agent || {}).version || 0; var offerToReceiveAudio = !(!self._sdpSettings.connection.audio && peerId !== 'MCU'); - var offerToReceiveVideo = !(!self._sdpSettings.connection.video && peerId !== 'MCU') && - ((window.webrtcDetectedBrowser === 'edge' && peerAgent !== 'edge') || - (['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && peerAgent === 'edge') ? - !!self._currentCodecSupport.video.h264 : true); + var offerToReceiveVideo = !(!self._sdpSettings.connection.video && peerId !== 'MCU') && self._getSDPEdgeVideoSupports(peerId); if (pc) { if (pc.signalingState !== self.PEER_CONNECTION_STATE.CLOSED) { @@ -29025,6 +28996,17 @@ Skylink.prototype._handleEndedStreams = function (peerId, checkStreamId) { } } }; + +/** + * Function that handles m= line audio and video support. + * @method _getMLineSupports + * @private + * @for Skylink + * @since 0.6.20 + */ +Skylink.prototype._getMLineSupports = function (peerId) { + +}; Skylink.prototype._setSDPCodecParams = function(targetMid, sessionDescription) { var self = this; @@ -29928,6 +29910,7 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes var sdpLines = sessionDescriptionStr.split('\r\n'); var peerAgent = ((self._peerInformations[targetMid] || {}).agent || {}).name || ''; + var peerVersion = ((self._peerInformations[targetMid] || {}).agent || {}).version || 0; var mediaType = ''; var bundleLineIndex = -1; var bundleLineMids = []; @@ -29941,9 +29924,7 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes } if (settings.connection.video) { - settings.connection.video = (window.webrtcDetectedBrowser === 'edge' && peerAgent !== 'edge') || - (['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && peerAgent === 'edge') ? - !!self._currentCodecSupport.video.h264 : true; + settings.connection.video = self._getSDPEdgeVideoSupports(peerId); } if (self._hasMCU) { @@ -30123,6 +30104,29 @@ Skylink.prototype._getSDPFingerprint = function (targetMid, sessionDescription, }; +/** + * Function that gets edge browser video supports. + * @method _getSDPEdgeVideoSupports + * @private + * @for Skylink + * @since 0.6.18 + */ +Skylink.prototype._getSDPEdgeVideoSupports = function (peerId) { + var self = this; + + if (peerId) { + var peerAgent = ((self._peerInformations[peerId] || {}).agent || {}).name || ''; + var peerVersion = ((self._peerInformations[peerId] || {}).agent || {}).version || 0; + + return window.webrtcDetectedBrowser === 'edge' && window.webrtcDetectedVersion < 15.15019 && + peerAgent !== 'edge' ? !!self._currentCodecSupport.video.h264 : (window.webrtcDetectedBrowser !== 'edge' && + peerAgent === 'edge' && peerVersion < 15.15019 ? !!self._currentCodecSupport.video.h264 : true); + } + + return window.webrtcDetectedBrowser === 'edge' && window.webrtcDetectedVersion < 15.15019 ? + !!self._currentCodecSupport.video.h264 : true; +}; + if(typeof exports !== 'undefined') { // Prevent breaking code module.exports = { diff --git a/publish/skylink.complete.min.js b/publish/skylink.complete.min.js index 6529eef1d..c25a23ed3 100644 --- a/publish/skylink.complete.min.js +++ b/publish/skylink.complete.min.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - 2017-04-10 */ +/*! skylinkjs - v0.6.19 - 2017-04-17 */ !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?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:this.onevent(packet);break;case parser.BINARY_EVENT:this.onevent(packet);break;case parser.ACK:this.onack(packet);break;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}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:function(){try{return window.localStorage}catch(e){}}(),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||void 0).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&&this.transports.indexOf("websocket")!=-1)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(/\\n/g,"\\\n"),this.area.value=data.replace(/\n/g,"\\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="[object Function]"==getClass.call(object);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="[object Function]"==getClass.call(object);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="[object Function]"==getClass.call(object),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"},toPaddedString=function(width,value){return("000000"+(value||0)).slice(-width)},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("[object Boolean]"==(className=getClass.call(value)))return""+value;if("[object Number]"==className)return value>-1/0&&value<1/0?""+value:"null";if("[object String]"==className)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,"[object Array]"==className){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("[object Array]"==getClass.call(value))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&&"[object Function]"==getClass.call(callback)?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=[];(tmp=decodeSymbol())!==!1;)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){var bsChunkSize="firefox"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]);var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost), isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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),("edge"!==window.webrtcDetectedBrowser&&"edge"===peerInfo.agent.name?["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&!this._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&"edge"!==peerInfo.agent.name&&!this._currentCodecSupport.video.h264)&&(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i-1&&!self._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&"edge"!==agent.name&&!self._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&!self._currentCodecSupport.video.h264)&&(customSettingsList[peerId].settings.video=!1,customSettingsList[peerId].mediaStatus.videoMuted=!0),customSettingsList[peerId].settings.audio=!!self._sdpSettings.connection.audio&&customSettingsList[peerId].settings.audio,customSettingsList[peerId].settings.video=!!self._sdpSettings.connection.video&&customSettingsList[peerId].settings.video,customSettingsList[peerId].mediaStatus.audioMuted=!self._sdpSettings.connection.audio||customSettingsList[peerId].mediaStatus.audioMuted,customSettingsList[peerId].mediaStatus.videoMuted=!self._sdpSettings.connection.video||customSettingsList[peerId].mediaStatus.videoMuted}return customSettingsList},Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo()),peerInfo=clone(this.getPeerInfo(peerId));return 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),(peerId?"edge"!==window.webrtcDetectedBrowser&&"edge"===peerInfo.agent.name?["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&!this._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&"edge"!==peerInfo.agent.name&&!this._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&!this._currentCodecSupport.video.h264)&&(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart,peerBrowser){var self=this,pc=self._peerConnections[targetMid];if(log.log([targetMid,null,null,"Checking caller status"],peerBrowser),!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 peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._sdpSettings.connection.data||"MCU"===targetMid)&&(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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,"edge"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=self._setSDPCodec(targetMid,sessionDescription,{audio:self.AUDIO_CODEC.OPUS,video:self.VIDEO_CODEC.H264})),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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0, -void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==peerId),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i-1&&"edge"===peerAgent)||!!self._currentCodecSupport.video.h264),self._hasMCU&&(settings.direction.audio.receive="MCU"!==targetMid,settings.direction.audio.send="MCU"===targetMid,settings.direction.video.receive="MCU"!==targetMid,settings.direction.video.send="MCU"===targetMid),self._sdpSessions[targetMid][direction].mLines=[],self._sdpSessions[targetMid][direction].bundleLine="";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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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},"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 +pc.onicegatheringstatechange=function(){log.log([targetMid,"RTCIceGatheringState",null,"Ice gathering state changed ->"],pc.iceGatheringState),self._trigger("candidateGenerationState",pc.iceGatheringState,targetMid)},"firefox"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._sdpSettings.connection.data||"MCU"===targetMid)&&(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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,"edge"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=self._setSDPCodec(targetMid,sessionDescription,{audio:self.AUDIO_CODEC.OPUS,video:self.VIDEO_CODEC.H264})),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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={ +appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 3dae2bacb..23228a1ab 100644 --- a/publish/skylink.debug.js +++ b/publish/skylink.debug.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Mon Apr 10 2017 12:58:20 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Mon Apr 17 2017 18:46:36 GMT+0800 (SGT) */ (function(globals) { @@ -7802,11 +7802,7 @@ Skylink.prototype.getPeerInfo = function(peerId) { } // If there is Peer ID (not broadcast ENTER message) and Peer is Edge browser and User is not - if (window.webrtcDetectedBrowser !== 'edge' && peerInfo.agent.name === 'edge' ? - // If User is IE/safari and does not have H264 support, remove video support - ['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && !this._currentCodecSupport.video.h264 : - // If User is Edge and Peer is not and no H264 support, remove video support - window.webrtcDetectedBrowser === 'edge' && peerInfo.agent.name !== 'edge' && !this._currentCodecSupport.video.h264) { + if (!this._getSDPEdgeVideoSupports(peerId)) { peerInfo.settings.video = false; peerInfo.mediaStatus.videoMuted = true; } @@ -8246,14 +8242,7 @@ Skylink.prototype.getPeersCustomSettings = function () { var agent = ((self._peerInformations[peerId] || {}).agent || {}).name || ''; // If there is Peer ID (not broadcast ENTER message) and Peer is Edge browser and User is not - if (customSettingsList[peerId].settings.video && (peerId ? - (window.webrtcDetectedBrowser !== 'edge' && agent.name === 'edge' ? - // If User is IE/safari and does not have H264 support, remove video support - ['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && !self._currentCodecSupport.video.h264 : - // If User is Edge and Peer is not and no H264 support, remove video support - window.webrtcDetectedBrowser === 'edge' && agent.name !== 'edge' && !self._currentCodecSupport.video.h264) : - // If broadcast ENTER message and User is Edge and has no H264 support - window.webrtcDetectedBrowser === 'edge' && !self._currentCodecSupport.video.h264)) { + if (customSettingsList[peerId].settings.video && !self._getSDPEdgeVideoSupports(peerId)) { customSettingsList[peerId].settings.video = false; customSettingsList[peerId].mediaStatus.videoMuted = true; } @@ -8316,13 +8305,7 @@ Skylink.prototype._getUserInfo = function(peerId) { } // If there is Peer ID (not broadcast ENTER message) and Peer is Edge browser and User is not - if (peerId ? (window.webrtcDetectedBrowser !== 'edge' && peerInfo.agent.name === 'edge' ? - // If User is IE/safari and does not have H264 support, remove video support - ['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && !this._currentCodecSupport.video.h264 : - // If User is Edge and Peer is not and no H264 support, remove video support - window.webrtcDetectedBrowser === 'edge' && peerInfo.agent.name !== 'edge' && !this._currentCodecSupport.video.h264) : - // If broadcast ENTER message and User is Edge and has no H264 support - window.webrtcDetectedBrowser === 'edge' && !this._currentCodecSupport.video.h264) { + if (!this._getSDPEdgeVideoSupports(peerId)) { userInfo.settings.video = false; userInfo.mediaStatus.videoMuted = true; } @@ -8381,14 +8364,10 @@ Skylink.prototype._doOffer = function(targetMid, iceRestart, peerBrowser) { return; } - var peerAgent = ((self._peerInformations[targetMid] || {}).agent || {}).name || ''; var doIceRestart = !!((self._peerInformations[targetMid] || {}).config || {}).enableIceRestart && iceRestart && self._enableIceRestart; var offerToReceiveAudio = !(!self._sdpSettings.connection.audio && targetMid !== 'MCU'); - var offerToReceiveVideo = !(!self._sdpSettings.connection.video && targetMid !== 'MCU') && - ((window.webrtcDetectedBrowser === 'edge' && peerAgent !== 'edge') || - (['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && peerAgent === 'edge') ? - !!self._currentCodecSupport.video.h264 : true); + var offerToReceiveVideo = !(!self._sdpSettings.connection.video && targetMid !== 'MCU') && self._getSDPEdgeVideoSupports(targetMid); var offerConstraints = { offerToReceiveAudio: offerToReceiveAudio, @@ -8482,12 +8461,8 @@ Skylink.prototype._doAnswer = function(targetMid) { self._addLocalMediaStreams(targetMid); } - var peerAgent = ((self._peerInformations[targetMid] || {}).agent || {}).name || ''; var offerToReceiveAudio = !(!self._sdpSettings.connection.audio && targetMid !== 'MCU'); - var offerToReceiveVideo = !(!self._sdpSettings.connection.video && targetMid !== 'MCU') && - ((window.webrtcDetectedBrowser === 'edge' && peerAgent !== 'edge') || - (['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && peerAgent === 'edge') ? - !!self._currentCodecSupport.video.h264 : true); + var offerToReceiveVideo = !(!self._sdpSettings.connection.video && targetMid !== 'MCU') && self._getSDPEdgeVideoSupports(targetMid); var answerConstraints = window.webrtcDetectedBrowser === 'edge' ? { offerToReceiveVideo: offerToReceiveVideo, offerToReceiveAudio: offerToReceiveAudio, @@ -13042,8 +13017,6 @@ Skylink.prototype._throttle = function(func, prop, wait){ func(false); } }; - - Skylink.prototype.SOCKET_ERROR = { CONNECTION_FAILED: 0, RECONNECTION_FAILED: -1, @@ -17303,11 +17276,9 @@ Skylink.prototype._addLocalMediaStreams = function(peerId) { var pc = self._peerConnections[peerId]; var peerAgent = ((self._peerInformations[peerId] || {}).agent || {}).name || ''; + var peerVersion = ((self._peerInformations[peerId] || {}).agent || {}).version || 0; var offerToReceiveAudio = !(!self._sdpSettings.connection.audio && peerId !== 'MCU'); - var offerToReceiveVideo = !(!self._sdpSettings.connection.video && peerId !== 'MCU') && - ((window.webrtcDetectedBrowser === 'edge' && peerAgent !== 'edge') || - (['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && peerAgent === 'edge') ? - !!self._currentCodecSupport.video.h264 : true); + var offerToReceiveVideo = !(!self._sdpSettings.connection.video && peerId !== 'MCU') && self._getSDPEdgeVideoSupports(peerId); if (pc) { if (pc.signalingState !== self.PEER_CONNECTION_STATE.CLOSED) { @@ -17431,6 +17402,17 @@ Skylink.prototype._handleEndedStreams = function (peerId, checkStreamId) { } } }; + +/** + * Function that handles m= line audio and video support. + * @method _getMLineSupports + * @private + * @for Skylink + * @since 0.6.20 + */ +Skylink.prototype._getMLineSupports = function (peerId) { + +}; Skylink.prototype._setSDPCodecParams = function(targetMid, sessionDescription) { var self = this; @@ -18334,6 +18316,7 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes var sdpLines = sessionDescriptionStr.split('\r\n'); var peerAgent = ((self._peerInformations[targetMid] || {}).agent || {}).name || ''; + var peerVersion = ((self._peerInformations[targetMid] || {}).agent || {}).version || 0; var mediaType = ''; var bundleLineIndex = -1; var bundleLineMids = []; @@ -18347,9 +18330,7 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes } if (settings.connection.video) { - settings.connection.video = (window.webrtcDetectedBrowser === 'edge' && peerAgent !== 'edge') || - (['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && peerAgent === 'edge') ? - !!self._currentCodecSupport.video.h264 : true; + settings.connection.video = self._getSDPEdgeVideoSupports(peerId); } if (self._hasMCU) { @@ -18529,6 +18510,29 @@ Skylink.prototype._getSDPFingerprint = function (targetMid, sessionDescription, }; +/** + * Function that gets edge browser video supports. + * @method _getSDPEdgeVideoSupports + * @private + * @for Skylink + * @since 0.6.18 + */ +Skylink.prototype._getSDPEdgeVideoSupports = function (peerId) { + var self = this; + + if (peerId) { + var peerAgent = ((self._peerInformations[peerId] || {}).agent || {}).name || ''; + var peerVersion = ((self._peerInformations[peerId] || {}).agent || {}).version || 0; + + return window.webrtcDetectedBrowser === 'edge' && window.webrtcDetectedVersion < 15.15019 && + peerAgent !== 'edge' ? !!self._currentCodecSupport.video.h264 : (window.webrtcDetectedBrowser !== 'edge' && + peerAgent === 'edge' && peerVersion < 15.15019 ? !!self._currentCodecSupport.video.h264 : true); + } + + return window.webrtcDetectedBrowser === 'edge' && window.webrtcDetectedVersion < 15.15019 ? + !!self._currentCodecSupport.video.h264 : true; +}; + if(typeof exports !== 'undefined') { // Prevent breaking code module.exports = { diff --git a/publish/skylink.min.js b/publish/skylink.min.js index 4f0e5bc75..265a2dfba 100644 --- a/publish/skylink.min.js +++ b/publish/skylink.min.js @@ -1,12 +1,12 @@ -/*! skylinkjs - v0.6.19 - 2017-04-10 */ +/*! skylinkjs - v0.6.19 - 2017-04-17 */ !function(globals){"use strict";function Skylink(){this._enableDataChannel=!0,this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._filterCandidatesType={host:!1,srflx:!1,relay:!1},this._enableIceTrickle=!0,this._enableSTUN=!0,this._enableTURN=!0,this._usePublicSTUN=!0,this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._isUsingPlugin=!1,this._TURNTransport="any",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._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,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._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,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._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,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._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={}}!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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],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&&(self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")===-1||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"===window.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){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.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,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.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},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";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){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.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].indexOf(state)>-1}),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)}else 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),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),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}),delete self._dataTransfers[transferId]},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._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._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.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},i=0;i-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}})}(peerId,channelProp)}if(0===listOfPeers.length)return void log.warn("There are no Peers to start data session with.");self._dataStreams[transferId]={sessions:sessions,chunkType:"string"===sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:sessionChunkType,isPrivate:isPrivate,isStringStream:"string"===sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null,isUpload:!0};var startDataSessionFn=function(peerId,channelProp,targetPeers){if(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+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===window.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;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]);var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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),("edge"!==window.webrtcDetectedBrowser&&"edge"===peerInfo.agent.name?["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&!this._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&"edge"!==peerInfo.agent.name&&!this._currentCodecSupport.video.h264)&&(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i-1&&!self._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&"edge"!==agent.name&&!self._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&!self._currentCodecSupport.video.h264)&&(customSettingsList[peerId].settings.video=!1,customSettingsList[peerId].mediaStatus.videoMuted=!0),customSettingsList[peerId].settings.audio=!!self._sdpSettings.connection.audio&&customSettingsList[peerId].settings.audio, -customSettingsList[peerId].settings.video=!!self._sdpSettings.connection.video&&customSettingsList[peerId].settings.video,customSettingsList[peerId].mediaStatus.audioMuted=!self._sdpSettings.connection.audio||customSettingsList[peerId].mediaStatus.audioMuted,customSettingsList[peerId].mediaStatus.videoMuted=!self._sdpSettings.connection.video||customSettingsList[peerId].mediaStatus.videoMuted}return customSettingsList},Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo()),peerInfo=clone(this.getPeerInfo(peerId));return 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),(peerId?"edge"!==window.webrtcDetectedBrowser&&"edge"===peerInfo.agent.name?["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&!this._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&"edge"!==peerInfo.agent.name&&!this._currentCodecSupport.video.h264:"edge"===window.webrtcDetectedBrowser&&!this._currentCodecSupport.video.h264)&&(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart,peerBrowser){var self=this,pc=self._peerConnections[targetMid];if(log.log([targetMid,null,null,"Checking caller status"],peerBrowser),!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 peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._sdpSettings.connection.data||"MCU"===targetMid)&&(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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,"edge"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=self._setSDPCodec(targetMid,sessionDescription,{audio:self.AUDIO_CODEC.OPUS,video:self.VIDEO_CODEC.H264})),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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}), -options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==peerId),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId||("edge"===window.webrtcDetectedBrowser&&"edge"!==peerAgent||["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&"edge"===peerAgent)&&!self._currentCodecSupport.video.h264);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",i=0;i-1&&"edge"===peerAgent)||!!self._currentCodecSupport.video.h264),self._hasMCU&&(settings.direction.audio.receive="MCU"!==targetMid,settings.direction.audio.send="MCU"===targetMid,settings.direction.video.receive="MCU"!==targetMid,settings.direction.video.send="MCU"===targetMid),self._sdpSessions[targetMid][direction].mLines=[],self._sdpSessions[targetMid][direction].bundleLine="";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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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},"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 +agent:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._sdpSettings.connection.data||"MCU"===targetMid)&&(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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,"edge"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=self._setSDPCodec(targetMid,sessionDescription,{audio:self.AUDIO_CODEC.OPUS,video:self.VIDEO_CODEC.H264})),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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom, +self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]), +self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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/source/peer-data.js b/source/peer-data.js index 4a28f99df..ff449bec3 100644 --- a/source/peer-data.js +++ b/source/peer-data.js @@ -177,11 +177,7 @@ Skylink.prototype.getPeerInfo = function(peerId) { } // If there is Peer ID (not broadcast ENTER message) and Peer is Edge browser and User is not - if (window.webrtcDetectedBrowser !== 'edge' && peerInfo.agent.name === 'edge' ? - // If User is IE/safari and does not have H264 support, remove video support - ['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && !this._currentCodecSupport.video.h264 : - // If User is Edge and Peer is not and no H264 support, remove video support - window.webrtcDetectedBrowser === 'edge' && peerInfo.agent.name !== 'edge' && !this._currentCodecSupport.video.h264) { + if (!this._getSDPEdgeVideoSupports(peerId)) { peerInfo.settings.video = false; peerInfo.mediaStatus.videoMuted = true; } @@ -621,14 +617,7 @@ Skylink.prototype.getPeersCustomSettings = function () { var agent = ((self._peerInformations[peerId] || {}).agent || {}).name || ''; // If there is Peer ID (not broadcast ENTER message) and Peer is Edge browser and User is not - if (customSettingsList[peerId].settings.video && (peerId ? - (window.webrtcDetectedBrowser !== 'edge' && agent.name === 'edge' ? - // If User is IE/safari and does not have H264 support, remove video support - ['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && !self._currentCodecSupport.video.h264 : - // If User is Edge and Peer is not and no H264 support, remove video support - window.webrtcDetectedBrowser === 'edge' && agent.name !== 'edge' && !self._currentCodecSupport.video.h264) : - // If broadcast ENTER message and User is Edge and has no H264 support - window.webrtcDetectedBrowser === 'edge' && !self._currentCodecSupport.video.h264)) { + if (customSettingsList[peerId].settings.video && !self._getSDPEdgeVideoSupports(peerId)) { customSettingsList[peerId].settings.video = false; customSettingsList[peerId].mediaStatus.videoMuted = true; } @@ -691,13 +680,7 @@ Skylink.prototype._getUserInfo = function(peerId) { } // If there is Peer ID (not broadcast ENTER message) and Peer is Edge browser and User is not - if (peerId ? (window.webrtcDetectedBrowser !== 'edge' && peerInfo.agent.name === 'edge' ? - // If User is IE/safari and does not have H264 support, remove video support - ['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && !this._currentCodecSupport.video.h264 : - // If User is Edge and Peer is not and no H264 support, remove video support - window.webrtcDetectedBrowser === 'edge' && peerInfo.agent.name !== 'edge' && !this._currentCodecSupport.video.h264) : - // If broadcast ENTER message and User is Edge and has no H264 support - window.webrtcDetectedBrowser === 'edge' && !this._currentCodecSupport.video.h264) { + if (!this._getSDPEdgeVideoSupports(peerId)) { userInfo.settings.video = false; userInfo.mediaStatus.videoMuted = true; } diff --git a/source/peer-handshake.js b/source/peer-handshake.js index af386ec72..86022f5f3 100644 --- a/source/peer-handshake.js +++ b/source/peer-handshake.js @@ -60,14 +60,10 @@ Skylink.prototype._doOffer = function(targetMid, iceRestart, peerBrowser) { return; } - var peerAgent = ((self._peerInformations[targetMid] || {}).agent || {}).name || ''; var doIceRestart = !!((self._peerInformations[targetMid] || {}).config || {}).enableIceRestart && iceRestart && self._enableIceRestart; var offerToReceiveAudio = !(!self._sdpSettings.connection.audio && targetMid !== 'MCU'); - var offerToReceiveVideo = !(!self._sdpSettings.connection.video && targetMid !== 'MCU') && - ((window.webrtcDetectedBrowser === 'edge' && peerAgent !== 'edge') || - (['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && peerAgent === 'edge') ? - !!self._currentCodecSupport.video.h264 : true); + var offerToReceiveVideo = !(!self._sdpSettings.connection.video && targetMid !== 'MCU') && self._getSDPEdgeVideoSupports(targetMid); var offerConstraints = { offerToReceiveAudio: offerToReceiveAudio, @@ -161,12 +157,8 @@ Skylink.prototype._doAnswer = function(targetMid) { self._addLocalMediaStreams(targetMid); } - var peerAgent = ((self._peerInformations[targetMid] || {}).agent || {}).name || ''; var offerToReceiveAudio = !(!self._sdpSettings.connection.audio && targetMid !== 'MCU'); - var offerToReceiveVideo = !(!self._sdpSettings.connection.video && targetMid !== 'MCU') && - ((window.webrtcDetectedBrowser === 'edge' && peerAgent !== 'edge') || - (['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && peerAgent === 'edge') ? - !!self._currentCodecSupport.video.h264 : true); + var offerToReceiveVideo = !(!self._sdpSettings.connection.video && targetMid !== 'MCU') && self._getSDPEdgeVideoSupports(targetMid); var answerConstraints = window.webrtcDetectedBrowser === 'edge' ? { offerToReceiveVideo: offerToReceiveVideo, offerToReceiveAudio: offerToReceiveAudio, diff --git a/source/stream-media.js b/source/stream-media.js index d25534708..96539bc41 100644 --- a/source/stream-media.js +++ b/source/stream-media.js @@ -1974,11 +1974,9 @@ Skylink.prototype._addLocalMediaStreams = function(peerId) { var pc = self._peerConnections[peerId]; var peerAgent = ((self._peerInformations[peerId] || {}).agent || {}).name || ''; + var peerVersion = ((self._peerInformations[peerId] || {}).agent || {}).version || 0; var offerToReceiveAudio = !(!self._sdpSettings.connection.audio && peerId !== 'MCU'); - var offerToReceiveVideo = !(!self._sdpSettings.connection.video && peerId !== 'MCU') && - ((window.webrtcDetectedBrowser === 'edge' && peerAgent !== 'edge') || - (['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && peerAgent === 'edge') ? - !!self._currentCodecSupport.video.h264 : true); + var offerToReceiveVideo = !(!self._sdpSettings.connection.video && peerId !== 'MCU') && self._getSDPEdgeVideoSupports(peerId); if (pc) { if (pc.signalingState !== self.PEER_CONNECTION_STATE.CLOSED) { diff --git a/source/stream-sdp.js b/source/stream-sdp.js index f3d14db76..52000a250 100644 --- a/source/stream-sdp.js +++ b/source/stream-sdp.js @@ -908,6 +908,7 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes var sdpLines = sessionDescriptionStr.split('\r\n'); var peerAgent = ((self._peerInformations[targetMid] || {}).agent || {}).name || ''; + var peerVersion = ((self._peerInformations[targetMid] || {}).agent || {}).version || 0; var mediaType = ''; var bundleLineIndex = -1; var bundleLineMids = []; @@ -921,9 +922,7 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes } if (settings.connection.video) { - settings.connection.video = (window.webrtcDetectedBrowser === 'edge' && peerAgent !== 'edge') || - (['IE', 'safari'].indexOf(window.webrtcDetectedBrowser) > -1 && peerAgent === 'edge') ? - !!self._currentCodecSupport.video.h264 : true; + settings.connection.video = self._getSDPEdgeVideoSupports(targetMid); } if (self._hasMCU) { @@ -1101,3 +1100,27 @@ Skylink.prototype._getSDPFingerprint = function (targetMid, sessionDescription, return fingerprint; }; + + +/** + * Function that gets edge browser video supports. + * @method _getSDPEdgeVideoSupports + * @private + * @for Skylink + * @since 0.6.18 + */ +Skylink.prototype._getSDPEdgeVideoSupports = function (peerId) { + var self = this; + + if (peerId) { + var peerAgent = ((self._peerInformations[peerId] || {}).agent || {}).name || ''; + var peerVersion = ((self._peerInformations[peerId] || {}).agent || {}).version || 0; + + return window.webrtcDetectedBrowser === 'edge' && window.webrtcDetectedVersion < 15.15019 && + peerAgent !== 'edge' ? !!self._currentCodecSupport.video.h264 : (window.webrtcDetectedBrowser !== 'edge' && + peerAgent === 'edge' && peerVersion < 15.15019 ? !!self._currentCodecSupport.video.h264 : true); + } + + return window.webrtcDetectedBrowser === 'edge' && window.webrtcDetectedVersion < 15.15019 ? + !!self._currentCodecSupport.video.h264 : true; +}; \ No newline at end of file From 07b390dbcd7639b0d1966f8068f18e3888dc6056 Mon Sep 17 00:00:00 2001 From: Leticia Choo Date: Mon, 17 Apr 2017 19:25:39 +0800 Subject: [PATCH 03/11] ESS-866 Fixes for getConnectionStatus() in edge. --- publish/skylink.complete.js | 31 +++++++++++++------------------ publish/skylink.complete.min.js | 16 ++++++++-------- publish/skylink.debug.js | 29 ++++++++++++----------------- publish/skylink.min.js | 16 ++++++++-------- source/peer-connection.js | 8 ++++++-- source/peer-handshake.js | 6 ++++-- 6 files changed, 51 insertions(+), 55 deletions(-) diff --git a/publish/skylink.complete.js b/publish/skylink.complete.js index 61d21be71..74d5a6783 100644 --- a/publish/skylink.complete.js +++ b/publish/skylink.complete.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Mon Apr 17 2017 18:46:36 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Mon Apr 17 2017 19:25:16 GMT+0800 (SGT) */ (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;o'], sessionDescription.sdp); @@ -28996,17 +29002,6 @@ Skylink.prototype._handleEndedStreams = function (peerId, checkStreamId) { } } }; - -/** - * Function that handles m= line audio and video support. - * @method _getMLineSupports - * @private - * @for Skylink - * @since 0.6.20 - */ -Skylink.prototype._getMLineSupports = function (peerId) { - -}; Skylink.prototype._setSDPCodecParams = function(targetMid, sessionDescription) { var self = this; @@ -29924,7 +29919,7 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes } if (settings.connection.video) { - settings.connection.video = self._getSDPEdgeVideoSupports(peerId); + settings.connection.video = self._getSDPEdgeVideoSupports(targetMid); } if (self._hasMCU) { diff --git a/publish/skylink.complete.min.js b/publish/skylink.complete.min.js index c25a23ed3..dfac45001 100644 --- a/publish/skylink.complete.min.js +++ b/publish/skylink.complete.min.js @@ -7,11 +7,11 @@ sdp+="a=ssrc-group:FID "+transceiver.sendEncodingParameters[0].ssrc+" "+transcei window.RTCPeerConnection.prototype.createAnswer=function(){var self=this,sdp=SDPUtils.writeSessionBoilerplate();this.usingBundle&&(sdp+="a=group:BUNDLE "+this.transceivers.map(function(t){return t.mid}).join(" ")+"\r\n"),this.transceivers.forEach(function(transceiver){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");var commonCapabilities=self._getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);sdp+=SDPUtils.writeMediaSection(transceiver,commonCapabilities,"answer",self.localStreams[0])});var desc=new RTCSessionDescription({type:"answer",sdp:sdp});return arguments.length&&"function"==typeof arguments[0]&&window.setTimeout(arguments[0],0,desc),Promise.resolve(desc)},window.RTCPeerConnection.prototype.addIceCandidate=function(candidate){if(null===candidate)this.transceivers.forEach(function(transceiver){transceiver.iceTransport.addRemoteCandidate({})});else{var mLineIndex=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;if("1"!==cand.component)return;"endOfCandidates"===cand.type&&(cand={}),transceiver.iceTransport.addRemoteCandidate(cand);var sections=SDPUtils.splitSections(this.remoteDescription.sdp);sections[mLineIndex+1]+=(cand.type?candidate.candidate.trim():"a=end-of-candidates")+"\r\n",this.remoteDescription.sdp=sections.join("")}}return arguments.length>1&&"function"==typeof arguments[1]&&window.setTimeout(arguments[1],0),Promise.resolve()},window.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];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){results.set(id,result[id]),results[id]=result[id]})}),cb&&window.setTimeout(cb,0,results),resolve(results)})})}}};module.exports={shimPeerConnection:edgeShim.shimPeerConnection,shimGetUserMedia:requirecopy("./getusermedia")}},{"../utils":10,"./getusermedia":6,sdp:1}],6:[function(requirecopy,module,exports){"use strict";module.exports=function(){var 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))})}}},{}],7:[function(requirecopy,module,exports){"use strict";var browserDetails=requirecopy("../utils").browserDetails,firefoxShim={shimOnTrack:function(){"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.streams=[e.stream],this.dispatchEvent(event)}.bind(this))}.bind(this))}})},shimSourceObject:function(){"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(){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;i=pos&&parseInt(match[pos],10)},detectBrowser:function(){var result={};if(result.browser=null,result.version=null,"undefined"==typeof window||!window.navigator)return result.browser="Not a browser.",result;if(navigator.mozGetUserMedia)result.browser="firefox",result.version=this.extractVersion(navigator.userAgent,/Firefox\/([0-9]+)\./,1);else if(navigator.webkitGetUserMedia)if(window.webkitRTCPeerConnection)result.browser="chrome",result.version=this.extractVersion(navigator.userAgent,/Chrom(e|ium)\/([0-9]+)\./,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\/([0-9]+)\./,1)}else{if(!navigator.mediaDevices||!navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))return result.browser="Not a supported browser.",result;result.browser="edge",result.version=this.extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2)}return result}};module.exports={log:utils.log,disableLog:utils.disableLog,browserDetails:utils.detectBrowser(),extractVersion:utils.extractVersion}},{}]},{},[2])(2)}),AdapterJS.parseWebrtcDetectedBrowser(),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){var iceServer=null,urlParts=url.split(":");if(0===urlParts[0].indexOf("stun"))iceServer={urls:[url]};else if(0===urlParts[0].indexOf("turn"))if(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){var iceServers=[];for(i=0;i=43?element.srcObject=stream:void 0!==element.src&&(element.src=URL.createObjectURL(stream)),element},reattachMediaStream=function(to,from){return webrtcDetectedVersion>=43?to.srcObject=from.srcObject:to.src=from.src,to},createIceServer=function(url,username,password){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){var iceServers=[];if(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"!==webrtcDetectedBrowser&&"opera"!==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()),"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.defineMediaSourcePolyfill=function(){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};if(window.navigator.mozGetUserMedia?(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(constraints&&constraints.video&&constraints.video.mediaSource){if("screen"!==constraints.video.mediaSource&&"window"!==constraints.video.mediaSource)return void failureCb(new Error('GetUserMedia: Only "screen" and "window" are supported as mediaSource constraints'));var updatedConstraints=clone(constraints);updatedConstraints.video.mozMediaSource=updatedConstraints.video.mediaSource;var checkIfReady=setInterval(function(){"complete"===document.readyState&&(clearInterval(checkIfReady),baseGetUserMedia(updatedConstraints,successCb,function(error){["NotAllowedError","PermissionDeniedError","SecurityError","NotAllowedError"].indexOf(error.name)>-1&&"https:"===window.parent.location.protocol?AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_FF,AdapterJS.TEXT.EXTENSION.BUTTON_FF,function(e){window.open("https://addons.mozilla.org/en-US/firefox/addon/skylink-webrtc-tools/","_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):window.navigator.webkitGetUserMedia&&"safari"!==window.webrtcDetectedBrowser?(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(constraints&&constraints.video&&constraints.video.mediaSource){if("chrome"!==window.webrtcDetectedBrowser)return void failureCb(new Error("Current browser does not support screensharing"));var updatedConstraints=clone(constraints),chromeCallback=function(error,sourceId){error?failureCb("permission-denied"===error?new Error("Permission denied for screen retrieval"):new Error("Failed retrieving selected screen")):(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,sourceId&&(updatedConstraints.video.mandatory.chromeMediaSourceId=sourceId),delete updatedConstraints.video.mediaSource,baseGetUserMedia(updatedConstraints,successCb,failureCb))},onIFrameCallback=function(event){event.data&&(event.data.chromeMediaSourceId&&("PermissionDeniedError"===event.data.chromeMediaSourceId?chromeCallback("permission-denied"):chromeCallback(null,event.data.chromeMediaSourceId)),event.data.chromeExtensionStatus&&("not-installed"===event.data.chromeExtensionStatus?AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_CHROME,AdapterJS.TEXT.EXTENSION.BUTTON_CHROME,function(e){window.open(event.data.data,"_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")})}):chromeCallback(event.data.chromeExtensionStatus,null)),window.removeEventListener("message",onIFrameCallback))};window.addEventListener("message",onIFrameCallback),postFrameMessage({captureSourceId:!0})}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=window.getUserMedia=navigator.getUserMedia,navigator.mediaDevices.getUserMedia=function(constraints){return new Promise(function(resolve,reject){window.getUserMedia(constraints,resolve,reject)})}):navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)||(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(constraints&&constraints.video&&constraints.video.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"));updatedConstraints.video.optional=updatedConstraints.video.optional||[],updatedConstraints.video.optional.push({sourceId:AdapterJS.WebRTCPlugin.plugin.screensharingKey||"Screensharing"}),delete 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)),"chrome"===window.webrtcDetectedBrowser){var iframe=document.createElement("iframe");iframe.onload=function(){iframe.isLoaded=!0},iframe.src="https://cdn.temasys.com.sg/skylink/extensions/detectRTC.html",iframe.style.display="none",(document.body||document.documentElement).appendChild(iframe);var postFrameMessage=function(object){if(object=object||{},!iframe.isLoaded)return void setTimeout(function(){iframe.contentWindow.postMessage(object,"*")},100);iframe.contentWindow.postMessage(object,"*")}}else window.webrtcDetectedBrowser},"function"!=typeof window.require&&AdapterJS.defineMediaSourcePolyfill(),function(globals){"use strict";function Skylink(){this._enableDataChannel=!0,this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._filterCandidatesType={host:!1,srflx:!1,relay:!1},this._enableIceTrickle=!0,this._enableSTUN=!0,this._enableTURN=!0,this._usePublicSTUN=!0,this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._isUsingPlugin=!1,this._TURNTransport="any",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._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,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._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,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._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,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._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={}}!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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],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&&(self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")===-1||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"===window.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){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.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,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.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},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";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){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.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].indexOf(state)>-1}),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)}else 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),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),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}),delete self._dataTransfers[transferId]},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._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._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.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},i=0;i-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}})}(peerId,channelProp)}if(0===listOfPeers.length)return void log.warn("There are no Peers to start data session with.");self._dataStreams[transferId]={sessions:sessions,chunkType:"string"===sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:sessionChunkType,isPrivate:isPrivate,isStringStream:"string"===sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null,isUpload:!0};var startDataSessionFn=function(peerId,channelProp,targetPeers){if(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+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===window.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;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]);var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost), -isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._sdpSettings.connection.data||"MCU"===targetMid)&&(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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,"edge"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=self._setSDPCodec(targetMid,sessionDescription,{audio:self.AUDIO_CODEC.OPUS,video:self.VIDEO_CODEC.H264})),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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={ -appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 +;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"), +result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,"edge"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=self._setSDPCodec(targetMid,sessionDescription,{audio:self.AUDIO_CODEC.OPUS,video:self.VIDEO_CODEC.H264})),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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={} +;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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 23228a1ab..160b8f4cf 100644 --- a/publish/skylink.debug.js +++ b/publish/skylink.debug.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Mon Apr 17 2017 18:46:36 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Mon Apr 17 2017 19:25:16 GMT+0800 (SGT) */ (function(globals) { @@ -6111,6 +6111,10 @@ Skylink.prototype._retrieveStats = function (peerId, callback, beSilentOnLogs, i log.debug([peerId, 'RTCStatsReport', null, 'Retrieivng connection status']); } + if (!self._peerStats[peerId] && !isAutoBwStats) { + return callback(new Error('No stats initiated yet.')); + } + var pc = self._peerConnections[peerId]; var result = { raw: null, @@ -6462,8 +6466,8 @@ Skylink.prototype._retrieveStats = function (peerId, callback, beSilentOnLogs, i } } else { result[mediaType][dirType].frames = self._parseConnectionStats( - isAutoBwStats ? self._peerBandwidth[peerId][subprop] : self._peerStats[peerId][subprop], - streamObj,dirType === 'sending' ? obj.framesSent : obj.framesReceived); + isAutoBwStats ? self._peerBandwidth[peerId][prop] : self._peerStats[peerId][prop], + obj,dirType === 'sending' ? obj.framesSent : obj.framesReceived); result[mediaType][dirType].framesDropped = obj.framesDropped; result[mediaType][dirType].framesDecoded = obj.framesDecoded; result[mediaType][dirType].framesCorrupted = obj.framesCorrupted; @@ -8397,8 +8401,8 @@ Skylink.prototype._doOffer = function(targetMid, iceRestart, peerBrowser) { } if (self._enableDataChannel && self._peerInformations[targetMid] && - self._peerInformations[targetMid].config.enableDataChannel && - !(!self._sdpSettings.connection.data && targetMid !== 'MCU')) { + self._peerInformations[targetMid].config.enableDataChannel/* && + !(!self._sdpSettings.connection.data && targetMid !== 'MCU')*/) { // Edge doesn't support datachannels yet if (!(self._dataChannels[targetMid] && self._dataChannels[targetMid].main)) { self._createDataChannel(targetMid); @@ -8546,6 +8550,8 @@ Skylink.prototype._setLocalAndSendMessage = function(targetMid, sessionDescripti sessionDescription.sdp = self._removeSDPCodecs(targetMid, sessionDescription); sessionDescription.sdp = self._handleSDPConnectionSettings(targetMid, sessionDescription, 'local'); sessionDescription.sdp = self._removeSDPREMBPackets(targetMid, sessionDescription); + //sessionDescription.sdp = sessionDescription.sdp.replace(/a=fmtp:100 packetization-mode=1;mst-mode=NI-TC;\r\n/gi, ''); + //sessionDescription.sdp = sessionDescription.sdp.replace(/a=rtcp-rsize\r\n/gi, ''); log.log([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description updated ->'], sessionDescription.sdp); @@ -17402,17 +17408,6 @@ Skylink.prototype._handleEndedStreams = function (peerId, checkStreamId) { } } }; - -/** - * Function that handles m= line audio and video support. - * @method _getMLineSupports - * @private - * @for Skylink - * @since 0.6.20 - */ -Skylink.prototype._getMLineSupports = function (peerId) { - -}; Skylink.prototype._setSDPCodecParams = function(targetMid, sessionDescription) { var self = this; @@ -18330,7 +18325,7 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes } if (settings.connection.video) { - settings.connection.video = self._getSDPEdgeVideoSupports(peerId); + settings.connection.video = self._getSDPEdgeVideoSupports(targetMid); } if (self._hasMCU) { diff --git a/publish/skylink.min.js b/publish/skylink.min.js index 265a2dfba..1b2fb516b 100644 --- a/publish/skylink.min.js +++ b/publish/skylink.min.js @@ -2,11 +2,11 @@ !function(globals){"use strict";function Skylink(){this._enableDataChannel=!0,this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._filterCandidatesType={host:!1,srflx:!1,relay:!1},this._enableIceTrickle=!0,this._enableSTUN=!0,this._enableTURN=!0,this._usePublicSTUN=!0,this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._isUsingPlugin=!1,this._TURNTransport="any",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._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,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._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,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._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,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._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={}}!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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],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&&(self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")===-1||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"===window.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){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.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,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.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},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";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){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.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].indexOf(state)>-1}),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)}else 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),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),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}),delete self._dataTransfers[transferId]},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._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._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.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},i=0;i-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}})}(peerId,channelProp)}if(0===listOfPeers.length)return void log.warn("There are no Peers to start data session with.");self._dataStreams[transferId]={sessions:sessions,chunkType:"string"===sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:sessionChunkType,isPrivate:isPrivate,isStringStream:"string"===sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null,isUpload:!0};var startDataSessionFn=function(peerId,channelProp,targetPeers){if(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+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===window.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;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]);var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._sdpSettings.connection.data||"MCU"===targetMid)&&(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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,"edge"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=self._setSDPCodec(targetMid,sessionDescription,{audio:self.AUDIO_CODEC.OPUS,video:self.VIDEO_CODEC.H264})),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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom, -self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]), -self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 +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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,"edge"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=self._setSDPCodec(targetMid,sessionDescription,{audio:self.AUDIO_CODEC.OPUS,video:self.VIDEO_CODEC.H264})),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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer, +self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream), +isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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/source/peer-connection.js b/source/peer-connection.js index a9de3aac4..3f6bc6b5a 100644 --- a/source/peer-connection.js +++ b/source/peer-connection.js @@ -746,6 +746,10 @@ Skylink.prototype._retrieveStats = function (peerId, callback, beSilentOnLogs, i log.debug([peerId, 'RTCStatsReport', null, 'Retrieivng connection status']); } + if (!self._peerStats[peerId] && !isAutoBwStats) { + return callback(new Error('No stats initiated yet.')); + } + var pc = self._peerConnections[peerId]; var result = { raw: null, @@ -1097,8 +1101,8 @@ Skylink.prototype._retrieveStats = function (peerId, callback, beSilentOnLogs, i } } else { result[mediaType][dirType].frames = self._parseConnectionStats( - isAutoBwStats ? self._peerBandwidth[peerId][subprop] : self._peerStats[peerId][subprop], - streamObj,dirType === 'sending' ? obj.framesSent : obj.framesReceived); + isAutoBwStats ? self._peerBandwidth[peerId][prop] : self._peerStats[peerId][prop], + obj,dirType === 'sending' ? obj.framesSent : obj.framesReceived); result[mediaType][dirType].framesDropped = obj.framesDropped; result[mediaType][dirType].framesDecoded = obj.framesDecoded; result[mediaType][dirType].framesCorrupted = obj.framesCorrupted; diff --git a/source/peer-handshake.js b/source/peer-handshake.js index 86022f5f3..30d6943f4 100644 --- a/source/peer-handshake.js +++ b/source/peer-handshake.js @@ -93,8 +93,8 @@ Skylink.prototype._doOffer = function(targetMid, iceRestart, peerBrowser) { } if (self._enableDataChannel && self._peerInformations[targetMid] && - self._peerInformations[targetMid].config.enableDataChannel && - !(!self._sdpSettings.connection.data && targetMid !== 'MCU')) { + self._peerInformations[targetMid].config.enableDataChannel/* && + !(!self._sdpSettings.connection.data && targetMid !== 'MCU')*/) { // Edge doesn't support datachannels yet if (!(self._dataChannels[targetMid] && self._dataChannels[targetMid].main)) { self._createDataChannel(targetMid); @@ -242,6 +242,8 @@ Skylink.prototype._setLocalAndSendMessage = function(targetMid, sessionDescripti sessionDescription.sdp = self._removeSDPCodecs(targetMid, sessionDescription); sessionDescription.sdp = self._handleSDPConnectionSettings(targetMid, sessionDescription, 'local'); sessionDescription.sdp = self._removeSDPREMBPackets(targetMid, sessionDescription); + //sessionDescription.sdp = sessionDescription.sdp.replace(/a=fmtp:100 packetization-mode=1;mst-mode=NI-TC;\r\n/gi, ''); + //sessionDescription.sdp = sessionDescription.sdp.replace(/a=rtcp-rsize\r\n/gi, ''); log.log([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description updated ->'], sessionDescription.sdp); From 8c4637015454cd142b9064c0d092f683245891a9 Mon Sep 17 00:00:00 2001 From: Leticia Choo Date: Tue, 18 Apr 2017 13:48:36 +0800 Subject: [PATCH 04/11] ESS-864 Remove unwanted lines. --- publish/skylink.complete.js | 14 ++------------ publish/skylink.complete.min.js | 14 +++++++------- publish/skylink.debug.js | 12 +----------- publish/skylink.min.js | 13 ++++++------- source/peer-handshake.js | 10 ---------- 5 files changed, 16 insertions(+), 47 deletions(-) diff --git a/publish/skylink.complete.js b/publish/skylink.complete.js index 74d5a6783..d9b3f35c3 100644 --- a/publish/skylink.complete.js +++ b/publish/skylink.complete.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Mon Apr 17 2017 19:25:16 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 13:47:54 GMT+0800 (SGT) */ (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;o'], sessionDescription.sdp); diff --git a/publish/skylink.complete.min.js b/publish/skylink.complete.min.js index dfac45001..484a5bb99 100644 --- a/publish/skylink.complete.min.js +++ b/publish/skylink.complete.min.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - 2017-04-17 */ +/*! skylinkjs - v0.6.19 - 2017-04-18 */ !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?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:this.onevent(packet);break;case parser.BINARY_EVENT:this.onevent(packet);break;case parser.ACK:this.onack(packet);break;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}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:function(){try{return window.localStorage}catch(e){}}(),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||void 0).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&&this.transports.indexOf("websocket")!=-1)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(/\\n/g,"\\\n"),this.area.value=data.replace(/\n/g,"\\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="[object Function]"==getClass.call(object);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="[object Function]"==getClass.call(object);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="[object Function]"==getClass.call(object),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"},toPaddedString=function(width,value){return("000000"+(value||0)).slice(-width)},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("[object Boolean]"==(className=getClass.call(value)))return""+value;if("[object Number]"==className)return value>-1/0&&value<1/0?""+value:"null";if("[object String]"==className)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,"[object Array]"==className){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("[object Array]"==getClass.call(value))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&&"[object Function]"==getClass.call(callback)?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=[];(tmp=decodeSymbol())!==!1;)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){var bsChunkSize="firefox"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"), result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,"edge"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=self._setSDPCodec(targetMid,sessionDescription,{audio:self.AUDIO_CODEC.OPUS,video:self.VIDEO_CODEC.H264})),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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={} -;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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 +log.debug([targetMid,"RTCSignalingState",null,"Peer connection state changed ->"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={ +appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 160b8f4cf..cc3bb569a 100644 --- a/publish/skylink.debug.js +++ b/publish/skylink.debug.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Mon Apr 17 2017 19:25:16 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 13:47:54 GMT+0800 (SGT) */ (function(globals) { @@ -8535,14 +8535,6 @@ Skylink.prototype._setLocalAndSendMessage = function(targetMid, sessionDescripti pc.processingLocalSDP = true; - // Set them as first - if (window.webrtcDetectedBrowser === 'edge') { - sessionDescription.sdp = self._setSDPCodec(targetMid, sessionDescription, { - audio: self.AUDIO_CODEC.OPUS, - video: self.VIDEO_CODEC.H264 - }); - } - // Sets and expected receiving codecs etc. sessionDescription.sdp = self._removeSDPFirefoxH264Pref(targetMid, sessionDescription); sessionDescription.sdp = self._setSDPCodecParams(targetMid, sessionDescription); @@ -8550,8 +8542,6 @@ Skylink.prototype._setLocalAndSendMessage = function(targetMid, sessionDescripti sessionDescription.sdp = self._removeSDPCodecs(targetMid, sessionDescription); sessionDescription.sdp = self._handleSDPConnectionSettings(targetMid, sessionDescription, 'local'); sessionDescription.sdp = self._removeSDPREMBPackets(targetMid, sessionDescription); - //sessionDescription.sdp = sessionDescription.sdp.replace(/a=fmtp:100 packetization-mode=1;mst-mode=NI-TC;\r\n/gi, ''); - //sessionDescription.sdp = sessionDescription.sdp.replace(/a=rtcp-rsize\r\n/gi, ''); log.log([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description updated ->'], sessionDescription.sdp); diff --git a/publish/skylink.min.js b/publish/skylink.min.js index 1b2fb516b..181d5eaeb 100644 --- a/publish/skylink.min.js +++ b/publish/skylink.min.js @@ -1,12 +1,11 @@ -/*! skylinkjs - v0.6.19 - 2017-04-17 */ +/*! skylinkjs - v0.6.19 - 2017-04-18 */ !function(globals){"use strict";function Skylink(){this._enableDataChannel=!0,this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._filterCandidatesType={host:!1,srflx:!1,relay:!1},this._enableIceTrickle=!0,this._enableSTUN=!0,this._enableTURN=!0,this._usePublicSTUN=!0,this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._isUsingPlugin=!1,this._TURNTransport="any",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._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,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._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,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._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,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._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={}}!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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],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&&(self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")===-1||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"===window.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){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.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,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.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},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";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){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.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].indexOf(state)>-1}),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)}else 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),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),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}),delete self._dataTransfers[transferId]},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._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._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.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},i=0;i-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}})}(peerId,channelProp)}if(0===listOfPeers.length)return void log.warn("There are no Peers to start data session with.");self._dataStreams[transferId]={sessions:sessions,chunkType:"string"===sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:sessionChunkType,isPrivate:isPrivate,isStringStream:"string"===sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null,isUpload:!0};var startDataSessionFn=function(peerId,channelProp,targetPeers){if(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+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===window.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;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,"edge"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=self._setSDPCodec(targetMid,sessionDescription,{audio:self.AUDIO_CODEC.OPUS,video:self.VIDEO_CODEC.H264})),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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer, -self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream), -isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 +var userInfo=clone(this.getPeerInfo());clone(this.getPeerInfo(peerId));return 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._getSDPEdgeVideoSupports(peerId)||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart,peerBrowser){var self=this,pc=self._peerConnections[targetMid];if(log.log([targetMid,null,null,"Checking caller status"],peerBrowser),!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 doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime, +self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer", +sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label), +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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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/source/peer-handshake.js b/source/peer-handshake.js index 30d6943f4..f7d70b06b 100644 --- a/source/peer-handshake.js +++ b/source/peer-handshake.js @@ -227,14 +227,6 @@ Skylink.prototype._setLocalAndSendMessage = function(targetMid, sessionDescripti pc.processingLocalSDP = true; - // Set them as first - if (window.webrtcDetectedBrowser === 'edge') { - sessionDescription.sdp = self._setSDPCodec(targetMid, sessionDescription, { - audio: self.AUDIO_CODEC.OPUS, - video: self.VIDEO_CODEC.H264 - }); - } - // Sets and expected receiving codecs etc. sessionDescription.sdp = self._removeSDPFirefoxH264Pref(targetMid, sessionDescription); sessionDescription.sdp = self._setSDPCodecParams(targetMid, sessionDescription); @@ -242,8 +234,6 @@ Skylink.prototype._setLocalAndSendMessage = function(targetMid, sessionDescripti sessionDescription.sdp = self._removeSDPCodecs(targetMid, sessionDescription); sessionDescription.sdp = self._handleSDPConnectionSettings(targetMid, sessionDescription, 'local'); sessionDescription.sdp = self._removeSDPREMBPackets(targetMid, sessionDescription); - //sessionDescription.sdp = sessionDescription.sdp.replace(/a=fmtp:100 packetization-mode=1;mst-mode=NI-TC;\r\n/gi, ''); - //sessionDescription.sdp = sessionDescription.sdp.replace(/a=rtcp-rsize\r\n/gi, ''); log.log([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description updated ->'], sessionDescription.sdp); From 63ead3a19a14d80e60294f3ae4414409d66e2d62 Mon Sep 17 00:00:00 2001 From: Leticia Choo Date: Tue, 18 Apr 2017 13:49:35 +0800 Subject: [PATCH 05/11] ESS-866 Fixes for getConnectionStatus() cannot read .timestamp of undefined. --- publish/skylink.complete.js | 8 ++++---- publish/skylink.complete.min.js | 2 +- publish/skylink.debug.js | 6 +++--- publish/skylink.min.js | 12 ++++++------ source/peer-connection.js | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/publish/skylink.complete.js b/publish/skylink.complete.js index d9b3f35c3..341db823d 100644 --- a/publish/skylink.complete.js +++ b/publish/skylink.complete.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 13:47:54 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 13:49:14 GMT+0800 (SGT) */ (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;o0){var bsChunkSize="firefox"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"), result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};room&&"string"==typeof room?selectedRoom=room:room&&"object"==typeof room?mediaOptions=room:"function"==typeof room&&(callback=room), +log.debug([targetMid,"RTCSignalingState",null,"Peer connection state changed ->"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={ appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=agentVer.split("."),partsB=requiredVer.split("."),i=0;i-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===window.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;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime, -self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer", -sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label), -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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 +type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room, +credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]), +self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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/source/peer-connection.js b/source/peer-connection.js index 3f6bc6b5a..cd992acf7 100644 --- a/source/peer-connection.js +++ b/source/peer-connection.js @@ -2210,9 +2210,9 @@ Skylink.prototype._restartMCUConnection = function(callback, doIceRestart, bwOpt */ Skylink.prototype._parseConnectionStats = function(prevStats, stats, prop) { var nTime = stats.timestamp; - var oTime = prevStats.timestamp; + var oTime = prevStats ? prevStats.timestamp || 0 : 0; var nVal = parseFloat(stats[prop] || '0', 10); - var oVal = parseFloat(prevStats[prop] || '0', 10); + var oVal = parseFloat(prevStats ? prevStats[prop] || '0' : '0', 10); if ((new Date(nTime).getTime()) === (new Date(oTime).getTime())) { return nVal; From ed28d4d42d5e8cb2a9f19177994c831d2a7d3bc9 Mon Sep 17 00:00:00 2001 From: Leticia Choo Date: Tue, 18 Apr 2017 17:58:31 +0800 Subject: [PATCH 06/11] ESS-865 Fixes to patch a=sendrecv from MCU remote answer when sending a=inactive as local offer. --- publish/skylink.complete.js | 66 +++++++++++++++++++++++---------- publish/skylink.complete.min.js | 2 +- publish/skylink.debug.js | 64 +++++++++++++++++++++++--------- publish/skylink.min.js | 3 +- source/stream-sdp.js | 62 ++++++++++++++++++++++--------- 5 files changed, 141 insertions(+), 56 deletions(-) diff --git a/publish/skylink.complete.js b/publish/skylink.complete.js index 341db823d..3349d02d4 100644 --- a/publish/skylink.complete.js +++ b/publish/skylink.complete.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 13:49:14 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 17:57:29 GMT+0800 (SGT) */ (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;o -1 && + } else if (mediaType && ['audio', 'video'].indexOf(mediaType) > -1 && ['a=sendrecv', 'a=sendonly', 'a=recvonly'].indexOf(sdpLines[i]) > -1) { - if (settings.direction[mediaType].send && !settings.direction[mediaType].receive) { - sdpLines[i] = sdpLines[i].indexOf('send') > -1 ? 'a=sendonly' : 'a=inactive'; - } else if (!settings.direction[mediaType].send && settings.direction[mediaType].receive) { - sdpLines[i] = sdpLines[i].indexOf('recv') > -1 ? 'a=recvonly' : 'a=inactive'; - } else if (!settings.direction[mediaType].send && !settings.direction[mediaType].receive) { - // MCU currently does not support a=inactive flag.. what do we do here? - sdpLines[i] = 'a=inactive'; - } + if (direction === 'local') { + if (settings.direction[mediaType].send && !settings.direction[mediaType].receive) { + sdpLines[i] = sdpLines[i].indexOf('send') > -1 ? 'a=sendonly' : 'a=inactive'; + } else if (!settings.direction[mediaType].send && settings.direction[mediaType].receive) { + sdpLines[i] = sdpLines[i].indexOf('recv') > -1 ? 'a=recvonly' : 'a=inactive'; + } else if (!settings.direction[mediaType].send && !settings.direction[mediaType].receive) { + // MCU currently does not support a=inactive flag.. what do we do here? + sdpLines[i] = 'a=inactive'; + } - // Handle Chrome bundle bug. - See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6280 - if (!self._hasMCU && window.webrtcDetectedBrowser !== 'firefox' && peerAgent === 'firefox' && - sessionDescription.type === self.HANDSHAKE_PROGRESS.OFFER && sdpLines[i] === 'a=recvonly') { - 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 = true; - settings.direction[mediaType].receive = true; + // Handle Chrome bundle bug. - See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6280 + if (!self._hasMCU && window.webrtcDetectedBrowser !== 'firefox' && peerAgent === 'firefox' && + sessionDescription.type === self.HANDSHAKE_PROGRESS.OFFER && sdpLines[i] === 'a=recvonly') { + 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 = true; + settings.direction[mediaType].receive = true; + } + // Patch for incorrect responses + } else if (sessionDescription.type === self.HANDSHAKE_PROGRESS.ANSWER) { + var localOfferRes = self._sdpSessions[targetMid].local.connection[mediaType]; + // Parse a=sendonly response + if (localOfferRes === 'a=sendonly') { + sdpLines[i] = ['a=inactive', 'a=recvonly'].indexOf(sdpLines[i]) === -1 ? + (sdpLines[i] === 'a=sendonly' ? 'a=inactive' : 'a=recvonly') : sdpLines[i]; + // Parse a=recvonly + } else if (localOfferRes === 'a=recvonly') { + sdpLines[i] = ['a=inactive', 'a=sendonly'].indexOf(sdpLines[i]) === -1 ? + (sdpLines[i] === 'a=recvonly' ? 'a=inactive' : 'a=sendonly') : sdpLines[i]; + // Parse a=sendrecv + } else if (localOfferRes === 'a=inactive') { + sdpLines[i] = 'a=inactive'; + } } + self._sdpSessions[targetMid][direction].connection[mediaType] = sdpLines[i]; } } diff --git a/publish/skylink.complete.min.js b/publish/skylink.complete.min.js index 682f4a411..4bbee1b8c 100644 --- a/publish/skylink.complete.min.js +++ b/publish/skylink.complete.min.js @@ -14,4 +14,4 @@ options&&"object"==typeof options?mediaOptions=options:"function"==typeof option appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 +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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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]||""),["audio","video"].indexOf(mediaType)===-1&&(self._sdpSessions[targetMid][direction].connection.data=!0);else if(mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){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]=["a=inactive","a=recvonly"].indexOf(sdpLines[i])===-1?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=["a=inactive","a=sendonly"].indexOf(sdpLines[i])===-1?"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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 2832a0b37..957d001d6 100644 --- a/publish/skylink.debug.js +++ b/publish/skylink.debug.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 13:49:14 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 17:57:29 GMT+0800 (SGT) */ (function(globals) { @@ -18295,6 +18295,7 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes var sessionDescriptionStr = sessionDescription.sdp; + // Handle a=end-of-candidates signaling for non-trickle ICE before setting remote session description if (direction === 'remote' && !self.getPeerInfo(targetMid).config.enableIceTrickle) { sessionDescriptionStr = sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g, ''); } @@ -18330,6 +18331,11 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes 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.length; i++) { // Cache the a=group:BUNDLE line used for remote answer from Edge later @@ -18401,28 +18407,50 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes } else if (sdpLines[i].indexOf('a=mid:') === 0) { bundleLineMids.push(sdpLines[i].split('a=mid:')[1] || ''); + if (['audio', 'video'].indexOf(mediaType) === -1) { + self._sdpSessions[targetMid][direction].connection.data = true; + } + // Configure direction a=sendonly etc for local sessiondescription - } else if (direction === 'local' && mediaType && ['audio', 'video'].indexOf(mediaType) > -1 && + } else if (mediaType && ['audio', 'video'].indexOf(mediaType) > -1 && ['a=sendrecv', 'a=sendonly', 'a=recvonly'].indexOf(sdpLines[i]) > -1) { - if (settings.direction[mediaType].send && !settings.direction[mediaType].receive) { - sdpLines[i] = sdpLines[i].indexOf('send') > -1 ? 'a=sendonly' : 'a=inactive'; - } else if (!settings.direction[mediaType].send && settings.direction[mediaType].receive) { - sdpLines[i] = sdpLines[i].indexOf('recv') > -1 ? 'a=recvonly' : 'a=inactive'; - } else if (!settings.direction[mediaType].send && !settings.direction[mediaType].receive) { - // MCU currently does not support a=inactive flag.. what do we do here? - sdpLines[i] = 'a=inactive'; - } + if (direction === 'local') { + if (settings.direction[mediaType].send && !settings.direction[mediaType].receive) { + sdpLines[i] = sdpLines[i].indexOf('send') > -1 ? 'a=sendonly' : 'a=inactive'; + } else if (!settings.direction[mediaType].send && settings.direction[mediaType].receive) { + sdpLines[i] = sdpLines[i].indexOf('recv') > -1 ? 'a=recvonly' : 'a=inactive'; + } else if (!settings.direction[mediaType].send && !settings.direction[mediaType].receive) { + // MCU currently does not support a=inactive flag.. what do we do here? + sdpLines[i] = 'a=inactive'; + } - // Handle Chrome bundle bug. - See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6280 - if (!self._hasMCU && window.webrtcDetectedBrowser !== 'firefox' && peerAgent === 'firefox' && - sessionDescription.type === self.HANDSHAKE_PROGRESS.OFFER && sdpLines[i] === 'a=recvonly') { - 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 = true; - settings.direction[mediaType].receive = true; + // Handle Chrome bundle bug. - See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6280 + if (!self._hasMCU && window.webrtcDetectedBrowser !== 'firefox' && peerAgent === 'firefox' && + sessionDescription.type === self.HANDSHAKE_PROGRESS.OFFER && sdpLines[i] === 'a=recvonly') { + 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 = true; + settings.direction[mediaType].receive = true; + } + // Patch for incorrect responses + } else if (sessionDescription.type === self.HANDSHAKE_PROGRESS.ANSWER) { + var localOfferRes = self._sdpSessions[targetMid].local.connection[mediaType]; + // Parse a=sendonly response + if (localOfferRes === 'a=sendonly') { + sdpLines[i] = ['a=inactive', 'a=recvonly'].indexOf(sdpLines[i]) === -1 ? + (sdpLines[i] === 'a=sendonly' ? 'a=inactive' : 'a=recvonly') : sdpLines[i]; + // Parse a=recvonly + } else if (localOfferRes === 'a=recvonly') { + sdpLines[i] = ['a=inactive', 'a=sendonly'].indexOf(sdpLines[i]) === -1 ? + (sdpLines[i] === 'a=recvonly' ? 'a=inactive' : 'a=sendonly') : sdpLines[i]; + // Parse a=sendrecv + } else if (localOfferRes === 'a=inactive') { + sdpLines[i] = 'a=inactive'; + } } + self._sdpSessions[targetMid][direction].connection[mediaType] = sdpLines[i]; } } diff --git a/publish/skylink.min.js b/publish/skylink.min.js index 6b06bc9dc..d8019ab11 100644 --- a/publish/skylink.min.js +++ b/publish/skylink.min.js @@ -8,4 +8,5 @@ Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerI credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]), -self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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}}"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&&(settings.connection[mediaType]?0===sdpLines[i].indexOf("a=mid:")?bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||""):"local"===direction&&mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1&&(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)):(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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 +self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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]||""),["audio","video"].indexOf(mediaType)===-1&&(self._sdpSessions[targetMid][direction].connection.data=!0);else if(mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){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]=["a=inactive","a=recvonly"].indexOf(sdpLines[i])===-1?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=["a=inactive","a=sendonly"].indexOf(sdpLines[i])===-1?"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._getSDPEdgeVideoSupports=function(peerId){var self=this +;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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/source/stream-sdp.js b/source/stream-sdp.js index 52000a250..450234417 100644 --- a/source/stream-sdp.js +++ b/source/stream-sdp.js @@ -902,6 +902,7 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes var sessionDescriptionStr = sessionDescription.sdp; + // Handle a=end-of-candidates signaling for non-trickle ICE before setting remote session description if (direction === 'remote' && !self.getPeerInfo(targetMid).config.enableIceTrickle) { sessionDescriptionStr = sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g, ''); } @@ -937,6 +938,11 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes 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.length; i++) { // Cache the a=group:BUNDLE line used for remote answer from Edge later @@ -1008,28 +1014,50 @@ Skylink.prototype._handleSDPConnectionSettings = function (targetMid, sessionDes } else if (sdpLines[i].indexOf('a=mid:') === 0) { bundleLineMids.push(sdpLines[i].split('a=mid:')[1] || ''); + if (['audio', 'video'].indexOf(mediaType) === -1) { + self._sdpSessions[targetMid][direction].connection.data = true; + } + // Configure direction a=sendonly etc for local sessiondescription - } else if (direction === 'local' && mediaType && ['audio', 'video'].indexOf(mediaType) > -1 && + } else if (mediaType && ['audio', 'video'].indexOf(mediaType) > -1 && ['a=sendrecv', 'a=sendonly', 'a=recvonly'].indexOf(sdpLines[i]) > -1) { - if (settings.direction[mediaType].send && !settings.direction[mediaType].receive) { - sdpLines[i] = sdpLines[i].indexOf('send') > -1 ? 'a=sendonly' : 'a=inactive'; - } else if (!settings.direction[mediaType].send && settings.direction[mediaType].receive) { - sdpLines[i] = sdpLines[i].indexOf('recv') > -1 ? 'a=recvonly' : 'a=inactive'; - } else if (!settings.direction[mediaType].send && !settings.direction[mediaType].receive) { - // MCU currently does not support a=inactive flag.. what do we do here? - sdpLines[i] = 'a=inactive'; - } + if (direction === 'local') { + if (settings.direction[mediaType].send && !settings.direction[mediaType].receive) { + sdpLines[i] = sdpLines[i].indexOf('send') > -1 ? 'a=sendonly' : 'a=inactive'; + } else if (!settings.direction[mediaType].send && settings.direction[mediaType].receive) { + sdpLines[i] = sdpLines[i].indexOf('recv') > -1 ? 'a=recvonly' : 'a=inactive'; + } else if (!settings.direction[mediaType].send && !settings.direction[mediaType].receive) { + // MCU currently does not support a=inactive flag.. what do we do here? + sdpLines[i] = 'a=inactive'; + } - // Handle Chrome bundle bug. - See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6280 - if (!self._hasMCU && window.webrtcDetectedBrowser !== 'firefox' && peerAgent === 'firefox' && - sessionDescription.type === self.HANDSHAKE_PROGRESS.OFFER && sdpLines[i] === 'a=recvonly') { - 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 = true; - settings.direction[mediaType].receive = true; + // Handle Chrome bundle bug. - See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6280 + if (!self._hasMCU && window.webrtcDetectedBrowser !== 'firefox' && peerAgent === 'firefox' && + sessionDescription.type === self.HANDSHAKE_PROGRESS.OFFER && sdpLines[i] === 'a=recvonly') { + 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 = true; + settings.direction[mediaType].receive = true; + } + // Patch for incorrect responses + } else if (sessionDescription.type === self.HANDSHAKE_PROGRESS.ANSWER) { + var localOfferRes = self._sdpSessions[targetMid].local.connection[mediaType]; + // Parse a=sendonly response + if (localOfferRes === 'a=sendonly') { + sdpLines[i] = ['a=inactive', 'a=recvonly'].indexOf(sdpLines[i]) === -1 ? + (sdpLines[i] === 'a=sendonly' ? 'a=inactive' : 'a=recvonly') : sdpLines[i]; + // Parse a=recvonly + } else if (localOfferRes === 'a=recvonly') { + sdpLines[i] = ['a=inactive', 'a=sendonly'].indexOf(sdpLines[i]) === -1 ? + (sdpLines[i] === 'a=recvonly' ? 'a=inactive' : 'a=sendonly') : sdpLines[i]; + // Parse a=sendrecv + } else if (localOfferRes === 'a=inactive') { + sdpLines[i] = 'a=inactive'; + } } + self._sdpSessions[targetMid][direction].connection[mediaType] = sdpLines[i]; } } From 7598b3dd7a295f8bce6dfc069151fa40a03501b0 Mon Sep 17 00:00:00 2001 From: Leticia Choo Date: Tue, 18 Apr 2017 18:32:24 +0800 Subject: [PATCH 07/11] ESS-868 Fixes for RTCSessionDescription .sdp property to be read-only. --- publish/skylink.complete.js | 49 ++++++++++++++++++--------------- publish/skylink.complete.min.js | 12 ++++---- publish/skylink.debug.js | 47 +++++++++++++++++-------------- publish/skylink.min.js | 12 ++++---- source/peer-handshake.js | 33 ++++++++++++---------- source/socket-message.js | 12 ++++---- 6 files changed, 90 insertions(+), 75 deletions(-) diff --git a/publish/skylink.complete.js b/publish/skylink.complete.js index 3349d02d4..0752a9182 100644 --- a/publish/skylink.complete.js +++ b/publish/skylink.complete.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 17:57:29 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 18:32:00 GMT+0800 (SGT) */ (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;o'], sessionDescription); + if (!(!!_sessionDescription && !!_sessionDescription.sdp)) { + log.warn([targetMid, 'RTCSessionDescription', null, 'Local session description is undefined ->'], _sessionDescription); return; } // Added checks to ensure that connection object is defined first if (!pc) { - log.warn([targetMid, 'RTCSessionDescription', sessionDescription.type, - 'Local session description will not be set as connection does not exists ->'], sessionDescription); + log.warn([targetMid, 'RTCSessionDescription', _sessionDescription.type, + 'Local session description will not be set as connection does not exists ->'], _sessionDescription); return; - } else if (sessionDescription.type === self.HANDSHAKE_PROGRESS.OFFER && + } else if (_sessionDescription.type === self.HANDSHAKE_PROGRESS.OFFER && pc.signalingState !== self.PEER_CONNECTION_STATE.STABLE) { - log.warn([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description ' + - 'will not be set as signaling state is "' + pc.signalingState + '" ->'], sessionDescription); + log.warn([targetMid, 'RTCSessionDescription', _sessionDescription.type, 'Local session description ' + + 'will not be set as signaling state is "' + pc.signalingState + '" ->'], _sessionDescription); return; // Added checks to ensure that state is "have-remote-offer" if setting local "answer" - } else if (sessionDescription.type === self.HANDSHAKE_PROGRESS.ANSWER && + } else if (_sessionDescription.type === self.HANDSHAKE_PROGRESS.ANSWER && pc.signalingState !== self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER) { - log.warn([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description ' + - 'will not be set as signaling state is "' + pc.signalingState + '" ->'], sessionDescription); + log.warn([targetMid, 'RTCSessionDescription', _sessionDescription.type, 'Local session description ' + + 'will not be set as signaling state is "' + pc.signalingState + '" ->'], _sessionDescription); return; // Added checks if there is a current local sessionDescription being processing before processing this one } else if (pc.processingLocalSDP) { - log.warn([targetMid, 'RTCSessionDescription', sessionDescription.type, - 'Local session description will not be set as another is being processed ->'], sessionDescription); + log.warn([targetMid, 'RTCSessionDescription', _sessionDescription.type, + 'Local session description will not be set as another is being processed ->'], _sessionDescription); return; } pc.processingLocalSDP = true; // Sets and expected receiving codecs etc. + 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); @@ -20140,7 +20145,7 @@ Skylink.prototype._setLocalAndSendMessage = function(targetMid, sessionDescripti log.log([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description updated ->'], sessionDescription.sdp); - pc.setLocalDescription(sessionDescription, function() { + pc.setLocalDescription(new RTCSessionDescription(sessionDescription), function() { log.debug([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description has been set ->'], sessionDescription); @@ -26621,10 +26626,10 @@ Skylink.prototype._offerHandler = function(message) { log.log([targetMid, null, message.type, 'Received offer from peer. ' + 'Session description:'], clone(message)); - var offer = new RTCSessionDescription({ + var offer = { type: 'offer', sdp: self._hasMCU ? message.sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : message.sdp - }); + }; log.log([targetMid, 'RTCSessionDescription', message.type, 'Session description object created'], offer); @@ -26663,7 +26668,7 @@ Skylink.prototype._offerHandler = function(message) { self._addLocalMediaStreams(targetMid); } - pc.setRemoteDescription(offer, function() { + pc.setRemoteDescription(new RTCSessionDescription(offer), function() { log.debug([targetMid, 'RTCSessionDescription', message.type, 'Remote description set']); pc.setOffer = 'remote'; pc.processingRemoteSDP = false; @@ -26812,10 +26817,10 @@ Skylink.prototype._answerHandler = function(message) { self._peerInformations[targetMid].userData = userInfo.userData; } - var answer = new RTCSessionDescription({ + var answer = { type: 'answer', sdp: self._hasMCU ? message.sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : message.sdp - }); + }; log.log([targetMid, 'RTCSessionDescription', message.type, 'Session description object created'], answer); @@ -26863,7 +26868,7 @@ Skylink.prototype._answerHandler = function(message) { pc.processingRemoteSDP = true; - pc.setRemoteDescription(answer, function() { + pc.setRemoteDescription(new RTCSessionDescription(answer), function() { log.debug([targetMid, null, message.type, 'Remote description set']); pc.setAnswer = 'remote'; pc.processingRemoteSDP = false; diff --git a/publish/skylink.complete.min.js b/publish/skylink.complete.min.js index 4bbee1b8c..e63191a95 100644 --- a/publish/skylink.complete.min.js +++ b/publish/skylink.complete.min.js @@ -9,9 +9,9 @@ bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?pe ;if("blob"===sessionType){self._hasMCU&&"binary"===sessionChunkType&&(log.warn("Binary data chunks transfer is not yet supported with MCU environment. Fallbacking to binary string data chunks transfer."),sessionChunkType="string");var chunkSize="string"===sessionChunkType?"firefox"===window.webrtcDetectedBrowser?self._MOZ_CHUNK_FILE_SIZE:self._CHUNK_FILE_SIZE:"firefox"===window.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE;if(transferInfo.dataType=self.DATA_TRANSFER_SESSION_TYPE.BLOB,transferInfo.chunkSize="string"===sessionChunkType?4*Math.ceil(chunkSize/3):chunkSize,transferInfo.chunkType="binary"===sessionChunkType?self._binaryChunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,!(data&&"object"==typeof data&&data instanceof Blob))return void emitErrorBeforeDataTransferFn("Provided data is not a Blob data");if(transferInfo.name=data.name||transferId,transferInfo.mimeType=data.type||null,data.size<1)return void emitErrorBeforeDataTransferFn("Provided data is not a valid Blob data.");transferInfo.originalSize=data.size,transferInfo.size="string"===sessionChunkType?4*Math.ceil(data.size/3):data.size,chunks=self._chunkBlobData(data,chunkSize)}else{if(transferInfo.dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,transferInfo.chunkSize=self._CHUNK_DATAURL_SIZE,transferInfo.chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING,!data||"string"!=typeof data)return void emitErrorBeforeDataTransferFn("Provided data is not a dataURL");transferInfo.originalSize=transferInfo.size=data.length||data.size,chunks=self._chunkDataURL(data,transferInfo.chunkSize)}if(!self._user||!self._user.sid)return void emitErrorBeforeDataTransferFn("Unable to send any "+sessionType.replace("data","dataURL")+" data. User is not in Room.");if(!self._enableDataChannel)return void emitErrorBeforeDataTransferFn("Unable to send any "+sessionType.replace("data","dataURL")+" data. Datachannel is disabled");if(0===listOfPeers.length)return void emitErrorBeforeDataTransferFn("Unable to send any "+sessionType.replace("data","dataURL")+" data. There are no Peers to start data transfer with");if(self._dataTransfers[transferId]=clone(transferInfo),self._dataTransfers[transferId].peers={},self._dataTransfers[transferId].peers.main={},self._dataTransfers[transferId].peers[transferId]={},self._dataTransfers[transferId].sessions={},self._dataTransfers[transferId].chunks=chunks,self._dataTransfers[transferId].enforceBSPeers=[],self._dataTransfers[transferId].enforcedBSInfo={},self._dataTransfers[transferId].sessionType=sessionType,self._dataTransfers[transferId].sessionChunkType=sessionChunkType,self._dataTransfers[transferId].senderPeerId=self._user.sid,"blob"===sessionType&&"binary"===sessionChunkType){for(var p=0;p0){var bsChunkSize="firefox"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"), result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={ -appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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]||""),["audio","video"].indexOf(mediaType)===-1&&(self._sdpSessions[targetMid][direction].connection.data=!0);else if(mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){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]=["a=inactive","a=recvonly"].indexOf(sdpLines[i])===-1?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=["a=inactive","a=sendonly"].indexOf(sdpLines[i])===-1?"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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 +log.debug([targetMid,"RTCSignalingState",null,"Peer connection state changed ->"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},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),pc.setLocalDescription(new RTCSessionDescription(sessionDescription),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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={} +;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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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};return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(new RTCSessionDescription(offer),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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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};return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(new RTCSessionDescription(answer),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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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]||""),["audio","video"].indexOf(mediaType)===-1&&(self._sdpSessions[targetMid][direction].connection.data=!0);else if(mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){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]=["a=inactive","a=recvonly"].indexOf(sdpLines[i])===-1?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=["a=inactive","a=sendonly"].indexOf(sdpLines[i])===-1?"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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 957d001d6..d403e8bd5 100644 --- a/publish/skylink.debug.js +++ b/publish/skylink.debug.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 17:57:29 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 18:32:00 GMT+0800 (SGT) */ (function(globals) { @@ -8497,45 +8497,50 @@ Skylink.prototype._doAnswer = function(targetMid) { * @for Skylink * @since 0.5.2 */ -Skylink.prototype._setLocalAndSendMessage = function(targetMid, sessionDescription) { +Skylink.prototype._setLocalAndSendMessage = function(targetMid, _sessionDescription) { var self = this; var pc = self._peerConnections[targetMid]; // Added checks to ensure that sessionDescription is defined first - if (!(!!sessionDescription && !!sessionDescription.sdp)) { - log.warn([targetMid, 'RTCSessionDescription', null, 'Local session description is undefined ->'], sessionDescription); + if (!(!!_sessionDescription && !!_sessionDescription.sdp)) { + log.warn([targetMid, 'RTCSessionDescription', null, 'Local session description is undefined ->'], _sessionDescription); return; } // Added checks to ensure that connection object is defined first if (!pc) { - log.warn([targetMid, 'RTCSessionDescription', sessionDescription.type, - 'Local session description will not be set as connection does not exists ->'], sessionDescription); + log.warn([targetMid, 'RTCSessionDescription', _sessionDescription.type, + 'Local session description will not be set as connection does not exists ->'], _sessionDescription); return; - } else if (sessionDescription.type === self.HANDSHAKE_PROGRESS.OFFER && + } else if (_sessionDescription.type === self.HANDSHAKE_PROGRESS.OFFER && pc.signalingState !== self.PEER_CONNECTION_STATE.STABLE) { - log.warn([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description ' + - 'will not be set as signaling state is "' + pc.signalingState + '" ->'], sessionDescription); + log.warn([targetMid, 'RTCSessionDescription', _sessionDescription.type, 'Local session description ' + + 'will not be set as signaling state is "' + pc.signalingState + '" ->'], _sessionDescription); return; // Added checks to ensure that state is "have-remote-offer" if setting local "answer" - } else if (sessionDescription.type === self.HANDSHAKE_PROGRESS.ANSWER && + } else if (_sessionDescription.type === self.HANDSHAKE_PROGRESS.ANSWER && pc.signalingState !== self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER) { - log.warn([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description ' + - 'will not be set as signaling state is "' + pc.signalingState + '" ->'], sessionDescription); + log.warn([targetMid, 'RTCSessionDescription', _sessionDescription.type, 'Local session description ' + + 'will not be set as signaling state is "' + pc.signalingState + '" ->'], _sessionDescription); return; // Added checks if there is a current local sessionDescription being processing before processing this one } else if (pc.processingLocalSDP) { - log.warn([targetMid, 'RTCSessionDescription', sessionDescription.type, - 'Local session description will not be set as another is being processed ->'], sessionDescription); + log.warn([targetMid, 'RTCSessionDescription', _sessionDescription.type, + 'Local session description will not be set as another is being processed ->'], _sessionDescription); return; } pc.processingLocalSDP = true; // Sets and expected receiving codecs etc. + 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); @@ -8546,7 +8551,7 @@ Skylink.prototype._setLocalAndSendMessage = function(targetMid, sessionDescripti log.log([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description updated ->'], sessionDescription.sdp); - pc.setLocalDescription(sessionDescription, function() { + pc.setLocalDescription(new RTCSessionDescription(sessionDescription), function() { log.debug([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description has been set ->'], sessionDescription); @@ -15027,10 +15032,10 @@ Skylink.prototype._offerHandler = function(message) { log.log([targetMid, null, message.type, 'Received offer from peer. ' + 'Session description:'], clone(message)); - var offer = new RTCSessionDescription({ + var offer = { type: 'offer', sdp: self._hasMCU ? message.sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : message.sdp - }); + }; log.log([targetMid, 'RTCSessionDescription', message.type, 'Session description object created'], offer); @@ -15069,7 +15074,7 @@ Skylink.prototype._offerHandler = function(message) { self._addLocalMediaStreams(targetMid); } - pc.setRemoteDescription(offer, function() { + pc.setRemoteDescription(new RTCSessionDescription(offer), function() { log.debug([targetMid, 'RTCSessionDescription', message.type, 'Remote description set']); pc.setOffer = 'remote'; pc.processingRemoteSDP = false; @@ -15218,10 +15223,10 @@ Skylink.prototype._answerHandler = function(message) { self._peerInformations[targetMid].userData = userInfo.userData; } - var answer = new RTCSessionDescription({ + var answer = { type: 'answer', sdp: self._hasMCU ? message.sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : message.sdp - }); + }; log.log([targetMid, 'RTCSessionDescription', message.type, 'Session description object created'], answer); @@ -15269,7 +15274,7 @@ Skylink.prototype._answerHandler = function(message) { pc.processingRemoteSDP = true; - pc.setRemoteDescription(answer, function() { + pc.setRemoteDescription(new RTCSessionDescription(answer), function() { log.debug([targetMid, null, message.type, 'Remote description set']); pc.setAnswer = 'remote'; pc.processingRemoteSDP = false; diff --git a/publish/skylink.min.js b/publish/skylink.min.js index d8019ab11..1c150e656 100644 --- a/publish/skylink.min.js +++ b/publish/skylink.min.js @@ -4,9 +4,9 @@ ;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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,sessionDescription){var self=this,pc=self._peerConnections[targetMid];return sessionDescription&&sessionDescription.sdp?pc?sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],sessionDescription):pc.processingLocalSDP?void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as another is being processed ->"],sessionDescription):(pc.processingLocalSDP=!0,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),void pc.setLocalDescription(sessionDescription,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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})):void log.warn([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description will not be set as connection does not exists ->"],sessionDescription):void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],sessionDescription)},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room, -credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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=new RTCSessionDescription({type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(offer,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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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=new RTCSessionDescription({type:"answer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp});return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(answer,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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]), -self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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]||""),["audio","video"].indexOf(mediaType)===-1&&(self._sdpSessions[targetMid][direction].connection.data=!0);else if(mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){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]=["a=inactive","a=recvonly"].indexOf(sdpLines[i])===-1?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=["a=inactive","a=sendonly"].indexOf(sdpLines[i])===-1?"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._getSDPEdgeVideoSupports=function(peerId){var self=this -;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 +Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo());clone(this.getPeerInfo(peerId));return 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._getSDPEdgeVideoSupports(peerId)||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart,peerBrowser){var self=this,pc=self._peerConnections[targetMid];if(log.log([targetMid,null,null,"Checking caller status"],peerBrowser),!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 doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},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),pc.setLocalDescription(new RTCSessionDescription(sessionDescription),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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey, +self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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};return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(new RTCSessionDescription(offer),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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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};return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(new RTCSessionDescription(answer),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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream), +isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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]||""),["audio","video"].indexOf(mediaType)===-1&&(self._sdpSessions[targetMid][direction].connection.data=!0);else if(mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){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]=["a=inactive","a=recvonly"].indexOf(sdpLines[i])===-1?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=["a=inactive","a=sendonly"].indexOf(sdpLines[i])===-1?"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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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/source/peer-handshake.js b/source/peer-handshake.js index f7d70b06b..5d878f031 100644 --- a/source/peer-handshake.js +++ b/source/peer-handshake.js @@ -189,45 +189,50 @@ Skylink.prototype._doAnswer = function(targetMid) { * @for Skylink * @since 0.5.2 */ -Skylink.prototype._setLocalAndSendMessage = function(targetMid, sessionDescription) { +Skylink.prototype._setLocalAndSendMessage = function(targetMid, _sessionDescription) { var self = this; var pc = self._peerConnections[targetMid]; // Added checks to ensure that sessionDescription is defined first - if (!(!!sessionDescription && !!sessionDescription.sdp)) { - log.warn([targetMid, 'RTCSessionDescription', null, 'Local session description is undefined ->'], sessionDescription); + if (!(!!_sessionDescription && !!_sessionDescription.sdp)) { + log.warn([targetMid, 'RTCSessionDescription', null, 'Local session description is undefined ->'], _sessionDescription); return; } // Added checks to ensure that connection object is defined first if (!pc) { - log.warn([targetMid, 'RTCSessionDescription', sessionDescription.type, - 'Local session description will not be set as connection does not exists ->'], sessionDescription); + log.warn([targetMid, 'RTCSessionDescription', _sessionDescription.type, + 'Local session description will not be set as connection does not exists ->'], _sessionDescription); return; - } else if (sessionDescription.type === self.HANDSHAKE_PROGRESS.OFFER && + } else if (_sessionDescription.type === self.HANDSHAKE_PROGRESS.OFFER && pc.signalingState !== self.PEER_CONNECTION_STATE.STABLE) { - log.warn([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description ' + - 'will not be set as signaling state is "' + pc.signalingState + '" ->'], sessionDescription); + log.warn([targetMid, 'RTCSessionDescription', _sessionDescription.type, 'Local session description ' + + 'will not be set as signaling state is "' + pc.signalingState + '" ->'], _sessionDescription); return; // Added checks to ensure that state is "have-remote-offer" if setting local "answer" - } else if (sessionDescription.type === self.HANDSHAKE_PROGRESS.ANSWER && + } else if (_sessionDescription.type === self.HANDSHAKE_PROGRESS.ANSWER && pc.signalingState !== self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER) { - log.warn([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description ' + - 'will not be set as signaling state is "' + pc.signalingState + '" ->'], sessionDescription); + log.warn([targetMid, 'RTCSessionDescription', _sessionDescription.type, 'Local session description ' + + 'will not be set as signaling state is "' + pc.signalingState + '" ->'], _sessionDescription); return; // Added checks if there is a current local sessionDescription being processing before processing this one } else if (pc.processingLocalSDP) { - log.warn([targetMid, 'RTCSessionDescription', sessionDescription.type, - 'Local session description will not be set as another is being processed ->'], sessionDescription); + log.warn([targetMid, 'RTCSessionDescription', _sessionDescription.type, + 'Local session description will not be set as another is being processed ->'], _sessionDescription); return; } pc.processingLocalSDP = true; // Sets and expected receiving codecs etc. + 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); @@ -238,7 +243,7 @@ Skylink.prototype._setLocalAndSendMessage = function(targetMid, sessionDescripti log.log([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description updated ->'], sessionDescription.sdp); - pc.setLocalDescription(sessionDescription, function() { + pc.setLocalDescription(new RTCSessionDescription(sessionDescription), function() { log.debug([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description has been set ->'], sessionDescription); diff --git a/source/socket-message.js b/source/socket-message.js index ee08d6c05..bff71737a 100644 --- a/source/socket-message.js +++ b/source/socket-message.js @@ -1524,10 +1524,10 @@ Skylink.prototype._offerHandler = function(message) { log.log([targetMid, null, message.type, 'Received offer from peer. ' + 'Session description:'], clone(message)); - var offer = new RTCSessionDescription({ + var offer = { type: 'offer', sdp: self._hasMCU ? message.sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : message.sdp - }); + }; log.log([targetMid, 'RTCSessionDescription', message.type, 'Session description object created'], offer); @@ -1566,7 +1566,7 @@ Skylink.prototype._offerHandler = function(message) { self._addLocalMediaStreams(targetMid); } - pc.setRemoteDescription(offer, function() { + pc.setRemoteDescription(new RTCSessionDescription(offer), function() { log.debug([targetMid, 'RTCSessionDescription', message.type, 'Remote description set']); pc.setOffer = 'remote'; pc.processingRemoteSDP = false; @@ -1715,10 +1715,10 @@ Skylink.prototype._answerHandler = function(message) { self._peerInformations[targetMid].userData = userInfo.userData; } - var answer = new RTCSessionDescription({ + var answer = { type: 'answer', sdp: self._hasMCU ? message.sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : message.sdp - }); + }; log.log([targetMid, 'RTCSessionDescription', message.type, 'Session description object created'], answer); @@ -1766,7 +1766,7 @@ Skylink.prototype._answerHandler = function(message) { pc.processingRemoteSDP = true; - pc.setRemoteDescription(answer, function() { + pc.setRemoteDescription(new RTCSessionDescription(answer), function() { log.debug([targetMid, null, message.type, 'Remote description set']); pc.setAnswer = 'remote'; pc.processingRemoteSDP = false; From ebaa0e86927dd4cc27383b0ea7161c8ba1fa4a7c Mon Sep 17 00:00:00 2001 From: Leticia Choo Date: Tue, 18 Apr 2017 18:34:30 +0800 Subject: [PATCH 08/11] ESS-867 Fixes to prevent .min.js files from dropping console. --- Gruntfile.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 10c5fb21d..e607974ea 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -81,10 +81,7 @@ module.exports = function(grunt) { uglify: { options: { mangle: false, - drop_console: true, - compress: { - drop_console: true - }, + compress: {}, banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + '<%= grunt.template.today("yyyy-mm-dd") %> */\n' }, From 0fedbe45193b0fabec91e5df9f62a7829b472dd3 Mon Sep 17 00:00:00 2001 From: Leticia Choo Date: Tue, 18 Apr 2017 19:00:29 +0800 Subject: [PATCH 09/11] ESS-870 Fixes for peerInfo.settings not being updated for SDP lines changes or received .userInfo in offer or answer message. --- publish/skylink.complete.js | 35 +++++++++++++++++++++++++++++++-- publish/skylink.complete.min.js | 32 +++++++++++++++--------------- publish/skylink.debug.js | 33 ++++++++++++++++++++++++++++++- publish/skylink.min.js | 18 ++++++++--------- source/peer-data.js | 23 ++++++++++++++++++++++ source/socket-message.js | 8 ++++++++ 6 files changed, 121 insertions(+), 28 deletions(-) diff --git a/publish/skylink.complete.js b/publish/skylink.complete.js index 0752a9182..9bd337827 100644 --- a/publish/skylink.complete.js +++ b/publish/skylink.complete.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 18:32:00 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 18:58:56 GMT+0800 (SGT) */ (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;o -1 : true) && + (this._sdpSessions[peerId].remote && this._sdpSessions[peerId].remote.connection ? + (this._sdpSessions[peerId].remote.connection.audio || '').indexOf('send') > -1 : true))) { + peerInfo.settings.audio = false; + } + // Set video to false if SDP m= line and direction is not available + if (peerInfo.settings.video && !((this._sdpSessions[peerId].local && this._sdpSessions[peerId].local.connection ? + (this._sdpSessions[peerId].local.connection.video || '').indexOf('recv') > -1 : true) && + (this._sdpSessions[peerId].remote && this._sdpSessions[peerId].remote.connection ? + (this._sdpSessions[peerId].remote.connection.video || '').indexOf('send') > -1 : true))) { + peerInfo.settings.video = false; + } + // Set data to false if SDP m= line and direction is not available + if (peerInfo.settings.data && !((this._sdpSessions[peerId].local && this._sdpSessions[peerId].local.connection ? + this._sdpSessions[peerId].local.connection.data : true) && (this._sdpSessions[peerId].remote && + this._sdpSessions[peerId].remote.connection ? this._sdpSessions[peerId].remote.connection.data : true))) { + peerInfo.settings.data = false; + } + } + } else { peerInfo = { userData: clone(this._userData), @@ -26668,6 +26691,10 @@ Skylink.prototype._offerHandler = function(message) { self._addLocalMediaStreams(targetMid); } + if (message.userInfo) { + self._trigger('peerUpdated', targetMid, self.getPeerInfo(targetMid), false); + } + pc.setRemoteDescription(new RTCSessionDescription(offer), function() { log.debug([targetMid, 'RTCSessionDescription', message.type, 'Remote description set']); pc.setOffer = 'remote'; @@ -26868,6 +26895,10 @@ Skylink.prototype._answerHandler = function(message) { pc.processingRemoteSDP = true; + if (message.userInfo) { + self._trigger('peerUpdated', targetMid, self.getPeerInfo(targetMid), false); + } + pc.setRemoteDescription(new RTCSessionDescription(answer), function() { log.debug([targetMid, null, message.type, 'Remote description set']); pc.setAnswer = 'remote'; diff --git a/publish/skylink.complete.min.js b/publish/skylink.complete.min.js index e63191a95..5456320cb 100644 --- a/publish/skylink.complete.min.js +++ b/publish/skylink.complete.min.js @@ -1,17 +1,17 @@ /*! skylinkjs - v0.6.19 - 2017-04-18 */ -!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?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:this.onevent(packet);break;case parser.BINARY_EVENT:this.onevent(packet);break;case parser.ACK:this.onack(packet);break;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}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:function(){try{return window.localStorage}catch(e){}}(),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||void 0).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&&this.transports.indexOf("websocket")!=-1)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(/\\n/g,"\\\n"),this.area.value=data.replace(/\n/g,"\\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="[object Function]"==getClass.call(object);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="[object Function]"==getClass.call(object);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="[object Function]"==getClass.call(object),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"},toPaddedString=function(width,value){return("000000"+(value||0)).slice(-width)},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("[object Boolean]"==(className=getClass.call(value)))return""+value;if("[object Number]"==className)return value>-1/0&&value<1/0?""+value:"null";if("[object String]"==className)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,"[object Array]"==className){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("[object Array]"==getClass.call(value))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&&"[object Function]"==getClass.call(callback)?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=[];(tmp=decodeSymbol())!==!1;)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;i=0)hasMatch=navigator.userAgent.match(/OPR\/(\d+)/i)||[],webrtcDetectedBrowser="opera",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=26,webrtcDetectedType="webkit",webrtcDetectedDCSupport="SCTP";else if(navigator.userAgent.match(/Bowser\/[0-9.]*/g)){hasMatch=navigator.userAgent.match(/Bowser\/[0-9.]*/g)||[];var chromiumVersion=parseInt((navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./i)||[])[2]||"0",10);webrtcDetectedBrowser="bowser",webrtcDetectedVersion=parseFloat((hasMatch[0]||"0/0").split("/")[1],10),webrtcMinimumVersion=0,webrtcDetectedType="webkit",webrtcDetectedDCSupport=chromiumVersion>30?"SCTP":"RTP"}else if(navigator.userAgent.indexOf("OPiOS")>0)hasMatch=navigator.userAgent.match(/OPiOS\/([0-9]+)\./),webrtcDetectedBrowser="opera",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=0,webrtcDetectedType=null,webrtcDetectedDCSupport=null;else if(navigator.userAgent.indexOf("CriOS")>0)hasMatch=navigator.userAgent.match(/CriOS\/([0-9]+)\./)||[],webrtcDetectedBrowser="chrome",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=0,webrtcDetectedType=null,webrtcDetectedDCSupport=null;else if(navigator.userAgent.indexOf("FxiOS")>0)hasMatch=navigator.userAgent.match(/FxiOS\/([0-9]+)\./)||[],webrtcDetectedBrowser="firefox",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=0,webrtcDetectedType=null,webrtcDetectedDCSupport=null;else if(document.documentMode)hasMatch=/\brv[ :]+(\d+)/g.exec(navigator.userAgent)||[],webrtcDetectedBrowser="IE",webrtcDetectedVersion=parseInt(hasMatch[1],10),webrtcMinimumVersion=9,webrtcDetectedType="plugin",webrtcDetectedDCSupport="SCTP",webrtcDetectedVersion||(hasMatch=/\bMSIE[ :]+(\d+)/g.exec(navigator.userAgent)||[],webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10));else if(window.StyleMedia||navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))hasMatch=navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)||[],webrtcDetectedBrowser="edge",webrtcDetectedVersion=parseFloat((hasMatch[0]||"0/0").split("/")[1],10),webrtcMinimumVersion=13.10547,webrtcDetectedType="ms",webrtcDetectedDCSupport=null;else if("undefined"!=typeof InstallTrigger||navigator.userAgent.indexOf("irefox")>0)hasMatch=navigator.userAgent.match(/Firefox\/([0-9]+)\./)||[],webrtcDetectedBrowser="firefox",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=33,webrtcDetectedType="moz",webrtcDetectedDCSupport="SCTP";else if(window.chrome&&window.chrome.webstore||navigator.userAgent.indexOf("Chrom")>0)hasMatch=navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./i)||[],webrtcDetectedBrowser="chrome",webrtcDetectedVersion=parseInt(hasMatch[2]||"0",10),webrtcMinimumVersion=38,webrtcDetectedType="webkit",webrtcDetectedDCSupport=webrtcDetectedVersion>30?"SCTP":"RTP";else if(/^((?!chrome|android).)*safari/i.test(navigator.userAgent)){hasMatch=navigator.userAgent.match(/version\/(\d+)/i)||[];var isMobile=navigator.userAgent.match(/(iPhone|iPad)/gi)||[];webrtcDetectedBrowser="safari",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=7,webrtcDetectedType=0===isMobile.length?"plugin":null,webrtcDetectedDCSupport=0===isMobile.length?"SCTP":null}window.webrtcDetectedBrowser=webrtcDetectedBrowser,window.webrtcDetectedVersion=webrtcDetectedVersion,window.webrtcMinimumVersion=webrtcMinimumVersion,window.webrtcDetectedType=webrtcDetectedType,window.webrtcDetectedDCSupport=webrtcDetectedDCSupport},AdapterJS.addEvent=function(elem,evnt,func){elem.addEventListener?elem.addEventListener(evnt,func,!1):elem.attachEvent?elem.attachEvent("on"+evnt,func):elem[evnt]=func},AdapterJS.renderNotificationBar=function(message,buttonText,buttonCallback){if("complete"===document.readyState){var w=window,i=document.createElement("iframe");i.name="adapterjs-alert",i.style.position="fixed",i.style.top="-41px",i.style.left=0,i.style.right=0,i.style.width="100%",i.style.height="40px",i.style.backgroundColor="#ffffe1",i.style.border="none",i.style.borderBottom="1px solid #888888",i.style.zIndex="9999999","string"==typeof i.style.webkitTransition?i.style.webkitTransition="all .5s ease-out":"string"==typeof i.style.transition&&(i.style.transition="all .5s ease-out"),document.body.appendChild(i);var c=i.contentWindow?i.contentWindow:i.contentDocument.document?i.contentDocument.document:i.contentDocument;c.document.open(),c.document.write(''+message+""),buttonText&&"function"==typeof buttonCallback?(c.document.write(''),c.document.close(),AdapterJS.addEvent(c.document.getElementById("okay"),"click",function(e){e.preventDefault();try{e.cancelBubble=!0}catch(error){}buttonCallback(e)}),AdapterJS.addEvent(c.document.getElementById("cancel"),"click",function(e){w.document.body.removeChild(i)})):c.document.close(),setTimeout(function(){"string"==typeof i.style.webkitTransform?i.style.webkitTransform="translateY(40px)":"string"==typeof i.style.transform?i.style.transform="translateY(40px)":i.style.top="0px"},300)}},webrtcDetectedType=null,checkMediaDataChannelSettings=function(peerBrowserAgent,peerBrowserVersion,callback,constraints){if("function"==typeof callback){var beOfferer=!0,isLocalFirefox="firefox"===webrtcDetectedBrowser,isLocalFirefoxInterop="moz"===webrtcDetectedType&&webrtcDetectedVersion>30,isPeerFirefox="firefox"===peerBrowserAgent;if(isLocalFirefox&&isPeerFirefox||isLocalFirefoxInterop)try{delete constraints.mandatory.MozDontOfferDataChannel}catch(error){}else isLocalFirefox&&!isPeerFirefox&&(constraints.mandatory.MozDontOfferDataChannel=!0);if(!isLocalFirefox)for(var prop in constraints.mandatory)constraints.mandatory.hasOwnProperty(prop)&&prop.indexOf("Moz")!==-1&&delete constraints.mandatory[prop];!isLocalFirefox||isPeerFirefox||isLocalFirefoxInterop||(beOfferer=!1),callback(beOfferer,constraints)}},checkIceConnectionState=function(peerId,iceConnectionState,callback){"function"==typeof callback&&(peerId=peerId?peerId:"peer",AdapterJS._iceConnectionFiredStates[peerId]&&iceConnectionState!==AdapterJS._iceConnectionStates.disconnected&&iceConnectionState!==AdapterJS._iceConnectionStates.failed&&iceConnectionState!==AdapterJS._iceConnectionStates.closed||(AdapterJS._iceConnectionFiredStates[peerId]=[]),iceConnectionState=AdapterJS._iceConnectionStates[iceConnectionState],AdapterJS._iceConnectionFiredStates[peerId].indexOf(iceConnectionState)<0&&(AdapterJS._iceConnectionFiredStates[peerId].push(iceConnectionState),iceConnectionState===AdapterJS._iceConnectionStates.connected&&setTimeout(function(){AdapterJS._iceConnectionFiredStates[peerId].push(AdapterJS._iceConnectionStates.done),callback(AdapterJS._iceConnectionStates.done)},1e3),callback(iceConnectionState)))},createIceServer=null,createIceServers=null,RTCPeerConnection="function"==typeof RTCPeerConnection?RTCPeerConnection:null,RTCSessionDescription="function"==typeof RTCSessionDescription?RTCSessionDescription:null,RTCIceCandidate="function"==typeof RTCIceCandidate?RTCIceCandidate:null,getUserMedia=null,attachMediaStream=null,reattachMediaStream=null,webrtcDetectedBrowser=null,webrtcDetectedVersion=null,webrtcMinimumVersion=null,!(navigator.mozGetUserMedia||navigator.webkitGetUserMedia||navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))||0===(navigator.userAgent.match(/android/gi)||[]).length&&0===(navigator.userAgent.match(/chrome/gi)||[]).length&&navigator.userAgent.indexOf("Safari/")>0?("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.parseWebrtcDetectedBrowser(),isIE="IE"===webrtcDetectedBrowser,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("complete"===document.readyState&&AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING){if(AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTING,"IE"===webrtcDetectedBrowser&&webrtcDetectedVersion<=10){var frag=document.createDocumentFragment();for(AdapterJS.WebRTCPlugin.plugin=document.createElement("div"),AdapterJS.WebRTCPlugin.plugin.innerHTML=' '+(AdapterJS.options.getAllCams?'':"")+"";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,isIE?(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(isIE){try{new ActiveXObject(comName+"."+plugName)}catch(e){return void notInstalledCb()}installedCb()}else{for(var pluginArray=navigator.mimeTypes,i=0;i=0)return void installedCb();notInstalledCb()}},AdapterJS.WebRTCPlugin.defineWebRTCInterface=function(){if(AdapterJS.WebRTCPlugin.pluginState!==AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY){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&&"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};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,navigator.mediaDevices||"undefined"==typeof Promise||(requestUserMedia=function(constraints){return new Promise(function(resolve,reject){getUserMedia(constraints,resolve,reject)})},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)},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(){isIE||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)):(!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.adapter=f()}}(function(){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?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o-1?(parts.attribute=line.substr(sp+1,colon-sp-1),parts.value=line.substr(colon+1)):parts.attribute=line.substr(sp+1),parts},SDPUtils.getDtlsParameters=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);lines=lines.concat(SDPUtils.splitLines(sessionpart));var fpLine=lines.filter(function(line){return 0===line.indexOf("a=fingerprint:")})[0].substr(14);return{role:"auto",fingerprints:[{algorithm:fpLine.split(" ")[0],value:fpLine.split(" ")[1]}]}},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=description.fecMechanisms.indexOf("RED")!==-1,hasUlpfec=description.fecMechanisms.indexOf("ULPFEC")!==-1,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&&(0===bandwidth[0].indexOf("b=TIAS:")?bandwidth=parseInt(bandwidth[0].substr(7),10):0===bandwidth[0].indexOf("b=AS:")&&(bandwidth=parseInt(bandwidth[0].substr(5),10)),encodingParameters.forEach(function(params){params.maxBitrate=bandwidth})),encodingParameters},SDPUtils.writeSessionBoilerplate=function(){return"v=0\r\no=thisisadapterortc 8169639915646943137 2 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",sdp+=transceiver.rtpSender&&transceiver.rtpReceiver?"a=sendrecv\r\n":transceiver.rtpSender?"a=sendonly\r\n":transceiver.rtpReceiver?"a=recvonly\r\n":"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(selector,successCallback);var fixChromeStats_=function(response){var standardReport={};return response.result().forEach(function(report){var standardStats={id:report.id,timestamp:report.timestamp,type:report.type};report.names().forEach(function(name){standardStats[name]=report.stat(name)}),standardReport[standardStats.id]=standardStats}),standardReport},makeMapStats=function(stats,legacyStats){var map=new Map(Object.keys(stats).map(function(key){return[key,stats[key]]}));return legacyStats=legacyStats||stats,Object.keys(legacyStats).forEach(function(key){map[key]=legacyStats[key]}),map};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){1===args.length&&"object"==typeof selector?origGetStats.apply(self,[function(response){resolve(makeMapStats(fixChromeStats_(response)))},reject]):origGetStats.apply(self,[function(response){resolve(makeMapStats(fixChromeStats_(response),response.result()))},reject])}).then(successCallback,errorCallback)},pc},window.RTCPeerConnection.prototype=webkitRTCPeerConnection.prototype,webkitRTCPeerConnection.generateCertificate&&Object.defineProperty(window.RTCPeerConnection,"generateCertificate",{get:function(){return webkitRTCPeerConnection.generateCertificate}}),["createOffer","createAnswer"].forEach(function(method){var nativeMethod=webkitRTCPeerConnection.prototype[method];webkitRTCPeerConnection.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)}}),browserDetails.version<51&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(method){var nativeMethod=webkitRTCPeerConnection.prototype[method];webkitRTCPeerConnection.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])})}}),["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(method){var nativeMethod=webkitRTCPeerConnection.prototype[method];webkitRTCPeerConnection.prototype[method]=function(){return arguments[0]=new("addIceCandidate"===method?RTCIceCandidate:RTCSessionDescription)(arguments[0]),nativeMethod.apply(this,arguments)}});var nativeAddIceCandidate=RTCPeerConnection.prototype.addIceCandidate;RTCPeerConnection.prototype.addIceCandidate=function(){return null===arguments[0]?Promise.resolve():nativeAddIceCandidate.apply(this,arguments)}}};module.exports={shimMediaStream:chromeShim.shimMediaStream,shimOnTrack:chromeShim.shimOnTrack,shimSourceObject:chromeShim.shimSourceObject,shimPeerConnection:chromeShim.shimPeerConnection,shimGetUserMedia:requirecopy("./getusermedia")}},{"../utils.js":10,"./getusermedia":4}],4:[function(requirecopy,module,exports){"use strict";var logging=requirecopy("../utils.js").log;module.exports=function(){var 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)),constraints&&constraints.audio&&(constraints.audio=constraintsToChrome_(constraints.audio)),constraints&&"object"==typeof constraints.video){var face=constraints.video.facingMode;if((face=face&&("object"==typeof face?face:{ideal:face}))&&("user"===face.exact||"environment"===face.exact||"user"===face.ideal||"environment"===face.ideal)&&(!navigator.mediaDevices.getSupportedConstraints||!navigator.mediaDevices.getSupportedConstraints().facingMode)&&(delete constraints.video.facingMode,"environment"===face.exact||"environment"===face.ideal))return navigator.mediaDevices.enumerateDevices().then(function(devices){devices=devices.filter(function(d){return"videoinput"===d.kind});var back=devices.find(function(d){return d.label.toLowerCase().indexOf("back")!==-1})||devices.length&&devices[devices.length-1];return back&&(constraints.video.deviceId=face.exact?{exact:back.deviceId}:{ideal:back.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",ConstraintNotSatisfiedError:"OverconstrainedError"}[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(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 MediaStreamTrack.getSources(function(devices){resolve(devices.map(function(device){return{label:device.label,kind:kinds[device.kind],deviceId:device.id,groupId:""}}))})})}}),navigator.mediaDevices.getUserMedia){var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(cs){return shimConstraints_(cs,function(c){return origGetUserMedia(c).catch(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":10}],5:[function(requirecopy,module,exports){"use strict";var SDPUtils=requirecopy("sdp"),browserDetails=requirecopy("../utils").browserDetails,edgeShim={shimPeerConnection:function(){window.RTCIceGatherer&&(window.RTCIceCandidate||(window.RTCIceCandidate=function(args){return args}),window.RTCSessionDescription||(window.RTCSessionDescription=function(args){return args})),window.RTCPeerConnection=function(config){var self=this,_eventTarget=document.createDocumentFragment();if(["addEventListener","removeEventListener","dispatchEvent"].forEach(function(method){self[method]=_eventTarget[method].bind(_eventTarget)}),this.onicecandidate=null,this.onaddstream=null,this.ontrack=null,this.onremovestream=null,this.onsignalingstatechange=null,this.oniceconnectionstatechange=null,this.onnegotiationneeded=null,this.ondatachannel=null,this.localStreams=[],this.remoteStreams=[],this.getLocalStreams=function(){return self.localStreams},this.getRemoteStreams=function(){return self.remoteStreams},this.localDescription=new RTCSessionDescription({type:"",sdp:""}),this.remoteDescription=new RTCSessionDescription({type:"",sdp:""}),this.signalingState="stable",this.iceConnectionState="new",this.iceGatheringState="new",this.iceOptions={gatherPolicy:"all",iceServers:[]},config&&config.iceTransportPolicy)switch(config.iceTransportPolicy){case"all":case"relay":this.iceOptions.gatherPolicy=config.iceTransportPolicy;break;case"none":throw new TypeError('iceTransportPolicy "none" not supported')}if(this.usingBundle=config&&"max-bundle"===config.bundlePolicy,config&&config.iceServers){var iceServers=JSON.parse(JSON.stringify(config.iceServers));this.iceOptions.iceServers=iceServers.filter(function(server){if(server&&server.urls){var urls=server.urls;return"string"==typeof urls&&(urls=[urls]),!!(urls=urls.filter(function(url){return 0===url.indexOf("turn:")&&url.indexOf("transport=udp")!==-1&&url.indexOf("turn:[")===-1||0===url.indexOf("stun:")&&browserDetails.version>=14393})[0])}return!1})}this.transceivers=[],this._localIceCandidatesBuffer=[]},window.RTCPeerConnection.prototype._emitBufferedCandidates=function(){var self=this,sections=SDPUtils.splitSections(self.localDescription.sdp);this._localIceCandidatesBuffer.forEach(function(event){if(event.candidate&&0!==Object.keys(event.candidate).length)event.candidate.candidate.indexOf("typ endOfCandidates")===-1&&(sections[event.candidate.sdpMLineIndex+1]+="a="+event.candidate.candidate+"\r\n");else for(var j=1;j-1&&(this.localStreams.splice(idx,1),this._maybeFireNegotiationNeeded())},window.RTCPeerConnection.prototype.getSenders=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpSender}).map(function(transceiver){return transceiver.rtpSender})},window.RTCPeerConnection.prototype.getReceivers=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpReceiver}).map(function(transceiver){return transceiver.rtpReceiver})},window.RTCPeerConnection.prototype._getCommonCapabilities=function(localCapabilities,remoteCapabilities){var commonCapabilities={codecs:[],headerExtensions:[],fecMechanisms:[]};return localCapabilities.codecs.forEach(function(lCodec){for(var i=0;i0;sections.forEach(function(mediaSection,sdpMLineIndex){var transceiver=self.transceivers[sdpMLineIndex],iceGatherer=transceiver.iceGatherer,iceTransport=transceiver.iceTransport,dtlsTransport=transceiver.dtlsTransport,localCapabilities=transceiver.localCapabilities,remoteCapabilities=transceiver.remoteCapabilities;if("0"!==mediaSection.split("\n",1)[0].split(" ",2)[1]&&!transceiver.isDatachannel){var remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);if(isIceLite){var cands=SDPUtils.matchPrefix(mediaSection,"a=candidate:").map(function(cand){return SDPUtils.parseCandidate(cand)}).filter(function(cand){return"1"===cand.component});cands.length&&iceTransport.setRemoteCandidates(cands)}var remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);isIceLite&&(remoteDtlsParameters.role="server"),self.usingBundle&&0!==sdpMLineIndex||(iceTransport.start(iceGatherer,remoteIceParameters,isIceLite?"controlling":"controlled"),dtlsTransport.start(remoteDtlsParameters));var params=self._getCommonCapabilities(localCapabilities,remoteCapabilities);self._transceive(transceiver,params.codecs.length>0,!1)}})}switch(this.localDescription={type:description.type,sdp:description.sdp},description.type){case"offer":this._updateSignalingState("have-local-offer");break;case"answer":this._updateSignalingState("stable");break;default:throw new TypeError('unsupported type "'+description.type+'"')}var hasCallback=arguments.length>1&&"function"==typeof arguments[1];if(hasCallback){var cb=arguments[1];window.setTimeout(function(){cb(),"new"===self.iceGatheringState&&(self.iceGatheringState="gathering"),self._emitBufferedCandidates()},0)}var p=Promise.resolve();return p.then(function(){hasCallback||("new"===self.iceGatheringState&&(self.iceGatheringState="gathering"),window.setTimeout(self._emitBufferedCandidates.bind(self),500))}),p},window.RTCPeerConnection.prototype.setRemoteDescription=function(description){var self=this,stream=new MediaStream,receiverList=[],sections=SDPUtils.splitSections(description.sdp),sessionpart=sections.shift(),isIceLite=SDPUtils.matchPrefix(sessionpart,"a=ice-lite").length>0;switch(this.usingBundle=SDPUtils.matchPrefix(sessionpart,"a=group:BUNDLE ").length>0,sections.forEach(function(mediaSection,sdpMLineIndex){var lines=SDPUtils.splitLines(mediaSection),mline=lines[0].substr(2).split(" "),kind=mline[0],rejected="0"===mline[1],direction=SDPUtils.getDirection(mediaSection,sessionpart),mid=SDPUtils.matchPrefix(mediaSection,"a=mid:");if(mid=mid.length?mid[0].substr(6):SDPUtils.generateIdentifier(),"application"===kind&&"DTLS/SCTP"===mline[2])return void(self.transceivers[sdpMLineIndex]={mid:mid,isDatachannel:!0});var transceiver,iceGatherer,iceTransport,dtlsTransport,rtpSender,rtpReceiver,sendEncodingParameters,recvEncodingParameters,localCapabilities,track,remoteIceParameters,remoteDtlsParameters,remoteCapabilities=SDPUtils.parseRtpParameters(mediaSection);rejected||(remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart),remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart),remoteDtlsParameters.role="client"),recvEncodingParameters=SDPUtils.parseRtpEncodingParameters(mediaSection);var cname,remoteSsrc=SDPUtils.matchPrefix(mediaSection,"a=ssrc:").map(function(line){return SDPUtils.parseSsrcMedia(line)}).filter(function(obj){return"cname"===obj.attribute})[0];remoteSsrc&&(cname=remoteSsrc.value);var isComplete=SDPUtils.matchPrefix(mediaSection,"a=end-of-candidates",sessionpart).length>0,cands=SDPUtils.matchPrefix(mediaSection,"a=candidate:").map(function(cand){return SDPUtils.parseCandidate(cand)}).filter(function(cand){return"1"===cand.component});if("offer"!==description.type||rejected)"answer"!==description.type||rejected||(transceiver=self.transceivers[sdpMLineIndex],iceGatherer=transceiver.iceGatherer,iceTransport=transceiver.iceTransport,dtlsTransport=transceiver.dtlsTransport,rtpSender=transceiver.rtpSender,rtpReceiver=transceiver.rtpReceiver,sendEncodingParameters=transceiver.sendEncodingParameters,localCapabilities=transceiver.localCapabilities,self.transceivers[sdpMLineIndex].recvEncodingParameters=recvEncodingParameters,self.transceivers[sdpMLineIndex].remoteCapabilities=remoteCapabilities,self.transceivers[sdpMLineIndex].cname=cname,(isIceLite||isComplete)&&cands.length&&iceTransport.setRemoteCandidates(cands),self.usingBundle&&0!==sdpMLineIndex||(iceTransport.start(iceGatherer,remoteIceParameters,"controlling"),dtlsTransport.start(remoteDtlsParameters)),self._transceive(transceiver,"sendrecv"===direction||"recvonly"===direction,"sendrecv"===direction||"sendonly"===direction),!rtpReceiver||"sendrecv"!==direction&&"sendonly"!==direction?delete transceiver.rtpReceiver:(track=rtpReceiver.track,receiverList.push([track,rtpReceiver]),stream.addTrack(track)));else{var transports=self.usingBundle&&sdpMLineIndex>0?{iceGatherer:self.transceivers[0].iceGatherer,iceTransport:self.transceivers[0].iceTransport,dtlsTransport:self.transceivers[0].dtlsTransport}:self._createIceAndDtlsTransports(mid,sdpMLineIndex);if(isComplete&&transports.iceTransport.setRemoteCandidates(cands),localCapabilities=RTCRtpReceiver.getCapabilities(kind),sendEncodingParameters=[{ssrc:1001*(2*sdpMLineIndex+2)}],rtpReceiver=new RTCRtpReceiver(transports.dtlsTransport,kind),track=rtpReceiver.track,receiverList.push([track,rtpReceiver]),stream.addTrack(track),self.localStreams.length>0&&self.localStreams[0].getTracks().length>=sdpMLineIndex){var localTrack;"audio"===kind?localTrack=self.localStreams[0].getAudioTracks()[0]:"video"===kind&&(localTrack=self.localStreams[0].getVideoTracks()[0]),localTrack&&(rtpSender=new RTCRtpSender(localTrack,transports.dtlsTransport))}self.transceivers[sdpMLineIndex]={iceGatherer:transports.iceGatherer,iceTransport:transports.iceTransport,dtlsTransport:transports.dtlsTransport,localCapabilities:localCapabilities,remoteCapabilities:remoteCapabilities,rtpSender:rtpSender,rtpReceiver:rtpReceiver,kind:kind,mid:mid,cname:cname,sendEncodingParameters:sendEncodingParameters,recvEncodingParameters:recvEncodingParameters},self._transceive(self.transceivers[sdpMLineIndex],!1,"sendrecv"===direction||"sendonly"===direction)}}),this.remoteDescription={type:description.type,sdp:description.sdp},description.type){case"offer":this._updateSignalingState("have-remote-offer");break;case"answer":this._updateSignalingState("stable");break;default:throw new TypeError('unsupported type "'+description.type+'"')}return stream.getTracks().length&&(self.remoteStreams.push(stream),window.setTimeout(function(){var event=new Event("addstream");event.stream=stream,self.dispatchEvent(event),null!==self.onaddstream&&window.setTimeout(function(){self.onaddstream(event)},0),receiverList.forEach(function(item){var track=item[0],receiver=item[1],trackEvent=new Event("track");trackEvent.track=track,trackEvent.receiver=receiver,trackEvent.streams=[stream],self.dispatchEvent(event),null!==self.ontrack&&window.setTimeout(function(){self.ontrack(trackEvent)},0)})},0)),arguments.length>1&&"function"==typeof arguments[1]&&window.setTimeout(arguments[1],0),Promise.resolve()},window.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")},window.RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event("signalingstatechange");this.dispatchEvent(event),null!==this.onsignalingstatechange&&this.onsignalingstatechange(event)},window.RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var event=new Event("negotiationneeded");this.dispatchEvent(event),null!==this.onnegotiationneeded&&this.onnegotiationneeded(event)},window.RTCPeerConnection.prototype._updateConnectionState=function(){var newState,self=this,states={new:0,closed:0,connecting:0,checking:0,connected:0,completed: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)}},window.RTCPeerConnection.prototype.createOffer=function(){var self=this;if(this._pendingOffer)throw new Error("createOffer called while there is a pending offer.");var offerOptions;1===arguments.length&&"function"!=typeof arguments[0]?offerOptions=arguments[0]:3===arguments.length&&(offerOptions=arguments[2]);var tracks=[],numAudioTracks=0,numVideoTracks=0;if(this.localStreams.length&&(numAudioTracks=this.localStreams[0].getAudioTracks().length,numVideoTracks=this.localStreams[0].getVideoTracks().length),offerOptions){if(offerOptions.mandatory||offerOptions.optional)throw new TypeError("Legacy mandatory/optional constraints not supported.");void 0!==offerOptions.offerToReceiveAudio&&(numAudioTracks=offerOptions.offerToReceiveAudio),void 0!==offerOptions.offerToReceiveVideo&&(numVideoTracks=offerOptions.offerToReceiveVideo)}for(this.localStreams.length&&this.localStreams[0].getTracks().forEach(function(track){tracks.push({kind:track.kind,track:track,wantReceive:"audio"===track.kind?numAudioTracks>0:numVideoTracks>0}),"audio"===track.kind?numAudioTracks--:"video"===track.kind&&numVideoTracks--});numAudioTracks>0||numVideoTracks>0;)numAudioTracks>0&&(tracks.push({kind:"audio",wantReceive:!0}),numAudioTracks--),numVideoTracks>0&&(tracks.push({kind:"video",wantReceive:!0}),numVideoTracks--);var sdp=SDPUtils.writeSessionBoilerplate(),transceivers=[];tracks.forEach(function(mline,sdpMLineIndex){var rtpSender,rtpReceiver,track=mline.track,kind=mline.kind,mid=SDPUtils.generateIdentifier(),transports=self.usingBundle&&sdpMLineIndex>0?{iceGatherer:transceivers[0].iceGatherer,iceTransport:transceivers[0].iceTransport,dtlsTransport:transceivers[0].dtlsTransport}:self._createIceAndDtlsTransports(mid,sdpMLineIndex),localCapabilities=RTCRtpSender.getCapabilities(kind),sendEncodingParameters=[{ssrc:1001*(2*sdpMLineIndex+1)}];track&&(rtpSender=new RTCRtpSender(track,transports.dtlsTransport)),mline.wantReceive&&(rtpReceiver=new RTCRtpReceiver(transports.dtlsTransport,kind)),transceivers[sdpMLineIndex]={iceGatherer:transports.iceGatherer,iceTransport:transports.iceTransport,dtlsTransport:transports.dtlsTransport,localCapabilities:localCapabilities,remoteCapabilities:null,rtpSender:rtpSender,rtpReceiver:rtpReceiver,kind:kind,mid:mid,sendEncodingParameters:sendEncodingParameters,recvEncodingParameters:null}}),this.usingBundle&&(sdp+="a=group:BUNDLE "+transceivers.map(function(t){return t.mid}).join(" ")+"\r\n"),tracks.forEach(function(mline,sdpMLineIndex){var transceiver=transceivers[sdpMLineIndex];sdp+=SDPUtils.writeMediaSection(transceiver,transceiver.localCapabilities,"offer",self.localStreams[0])}),this._pendingOffer=transceivers;var desc=new RTCSessionDescription({type:"offer",sdp:sdp});return arguments.length&&"function"==typeof arguments[0]&&window.setTimeout(arguments[0],0,desc),Promise.resolve(desc)}, -window.RTCPeerConnection.prototype.createAnswer=function(){var self=this,sdp=SDPUtils.writeSessionBoilerplate();this.usingBundle&&(sdp+="a=group:BUNDLE "+this.transceivers.map(function(t){return t.mid}).join(" ")+"\r\n"),this.transceivers.forEach(function(transceiver){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");var commonCapabilities=self._getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);sdp+=SDPUtils.writeMediaSection(transceiver,commonCapabilities,"answer",self.localStreams[0])});var desc=new RTCSessionDescription({type:"answer",sdp:sdp});return arguments.length&&"function"==typeof arguments[0]&&window.setTimeout(arguments[0],0,desc),Promise.resolve(desc)},window.RTCPeerConnection.prototype.addIceCandidate=function(candidate){if(null===candidate)this.transceivers.forEach(function(transceiver){transceiver.iceTransport.addRemoteCandidate({})});else{var mLineIndex=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;if("1"!==cand.component)return;"endOfCandidates"===cand.type&&(cand={}),transceiver.iceTransport.addRemoteCandidate(cand);var sections=SDPUtils.splitSections(this.remoteDescription.sdp);sections[mLineIndex+1]+=(cand.type?candidate.candidate.trim():"a=end-of-candidates")+"\r\n",this.remoteDescription.sdp=sections.join("")}}return arguments.length>1&&"function"==typeof arguments[1]&&window.setTimeout(arguments[1],0),Promise.resolve()},window.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];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){results.set(id,result[id]),results[id]=result[id]})}),cb&&window.setTimeout(cb,0,results),resolve(results)})})}}};module.exports={shimPeerConnection:edgeShim.shimPeerConnection,shimGetUserMedia:requirecopy("./getusermedia")}},{"../utils":10,"./getusermedia":6,sdp:1}],6:[function(requirecopy,module,exports){"use strict";module.exports=function(){var 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))})}}},{}],7:[function(requirecopy,module,exports){"use strict";var browserDetails=requirecopy("../utils").browserDetails,firefoxShim={shimOnTrack:function(){"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.streams=[e.stream],this.dispatchEvent(event)}.bind(this))}.bind(this))}})},shimSourceObject:function(){"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(){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;i=pos&&parseInt(match[pos],10)},detectBrowser:function(){var result={};if(result.browser=null,result.version=null,"undefined"==typeof window||!window.navigator)return result.browser="Not a browser.",result;if(navigator.mozGetUserMedia)result.browser="firefox",result.version=this.extractVersion(navigator.userAgent,/Firefox\/([0-9]+)\./,1);else if(navigator.webkitGetUserMedia)if(window.webkitRTCPeerConnection)result.browser="chrome",result.version=this.extractVersion(navigator.userAgent,/Chrom(e|ium)\/([0-9]+)\./,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\/([0-9]+)\./,1)}else{if(!navigator.mediaDevices||!navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))return result.browser="Not a supported browser.",result;result.browser="edge",result.version=this.extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2)}return result}};module.exports={log:utils.log,disableLog:utils.disableLog,browserDetails:utils.detectBrowser(),extractVersion:utils.extractVersion}},{}]},{},[2])(2)}),AdapterJS.parseWebrtcDetectedBrowser(),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){var iceServer=null,urlParts=url.split(":");if(0===urlParts[0].indexOf("stun"))iceServer={urls:[url]};else if(0===urlParts[0].indexOf("turn"))if(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){var iceServers=[];for(i=0;i=43?element.srcObject=stream:void 0!==element.src&&(element.src=URL.createObjectURL(stream)),element},reattachMediaStream=function(to,from){return webrtcDetectedVersion>=43?to.srcObject=from.srcObject:to.src=from.src,to},createIceServer=function(url,username,password){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){var iceServers=[];if(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"!==webrtcDetectedBrowser&&"opera"!==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()),"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.defineMediaSourcePolyfill=function(){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};if(window.navigator.mozGetUserMedia?(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(constraints&&constraints.video&&constraints.video.mediaSource){if("screen"!==constraints.video.mediaSource&&"window"!==constraints.video.mediaSource)return void failureCb(new Error('GetUserMedia: Only "screen" and "window" are supported as mediaSource constraints'));var updatedConstraints=clone(constraints);updatedConstraints.video.mozMediaSource=updatedConstraints.video.mediaSource;var checkIfReady=setInterval(function(){"complete"===document.readyState&&(clearInterval(checkIfReady),baseGetUserMedia(updatedConstraints,successCb,function(error){["NotAllowedError","PermissionDeniedError","SecurityError","NotAllowedError"].indexOf(error.name)>-1&&"https:"===window.parent.location.protocol?AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_FF,AdapterJS.TEXT.EXTENSION.BUTTON_FF,function(e){window.open("https://addons.mozilla.org/en-US/firefox/addon/skylink-webrtc-tools/","_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):window.navigator.webkitGetUserMedia&&"safari"!==window.webrtcDetectedBrowser?(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(constraints&&constraints.video&&constraints.video.mediaSource){if("chrome"!==window.webrtcDetectedBrowser)return void failureCb(new Error("Current browser does not support screensharing"));var updatedConstraints=clone(constraints),chromeCallback=function(error,sourceId){error?failureCb("permission-denied"===error?new Error("Permission denied for screen retrieval"):new Error("Failed retrieving selected screen")):(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,sourceId&&(updatedConstraints.video.mandatory.chromeMediaSourceId=sourceId),delete updatedConstraints.video.mediaSource,baseGetUserMedia(updatedConstraints,successCb,failureCb))},onIFrameCallback=function(event){event.data&&(event.data.chromeMediaSourceId&&("PermissionDeniedError"===event.data.chromeMediaSourceId?chromeCallback("permission-denied"):chromeCallback(null,event.data.chromeMediaSourceId)),event.data.chromeExtensionStatus&&("not-installed"===event.data.chromeExtensionStatus?AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_CHROME,AdapterJS.TEXT.EXTENSION.BUTTON_CHROME,function(e){window.open(event.data.data,"_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")})}):chromeCallback(event.data.chromeExtensionStatus,null)),window.removeEventListener("message",onIFrameCallback))};window.addEventListener("message",onIFrameCallback),postFrameMessage({captureSourceId:!0})}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=window.getUserMedia=navigator.getUserMedia,navigator.mediaDevices.getUserMedia=function(constraints){return new Promise(function(resolve,reject){window.getUserMedia(constraints,resolve,reject)})}):navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)||(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(constraints&&constraints.video&&constraints.video.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"));updatedConstraints.video.optional=updatedConstraints.video.optional||[],updatedConstraints.video.optional.push({sourceId:AdapterJS.WebRTCPlugin.plugin.screensharingKey||"Screensharing"}),delete 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)),"chrome"===window.webrtcDetectedBrowser){var iframe=document.createElement("iframe");iframe.onload=function(){iframe.isLoaded=!0},iframe.src="https://cdn.temasys.com.sg/skylink/extensions/detectRTC.html",iframe.style.display="none",(document.body||document.documentElement).appendChild(iframe);var postFrameMessage=function(object){if(object=object||{},!iframe.isLoaded)return void setTimeout(function(){iframe.contentWindow.postMessage(object,"*")},100);iframe.contentWindow.postMessage(object,"*")}}else window.webrtcDetectedBrowser},"function"!=typeof window.require&&AdapterJS.defineMediaSourcePolyfill(),function(globals){"use strict";function Skylink(){this._enableDataChannel=!0,this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._filterCandidatesType={host:!1,srflx:!1,relay:!1},this._enableIceTrickle=!0,this._enableSTUN=!0,this._enableTURN=!0,this._usePublicSTUN=!0,this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._isUsingPlugin=!1,this._TURNTransport="any",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._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,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._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,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._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,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._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={}}!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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],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&&(self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")===-1||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"===window.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){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.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,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.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},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";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){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.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].indexOf(state)>-1}),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)}else 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),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),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}),delete self._dataTransfers[transferId]},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._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._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.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},i=0;i-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}})}(peerId,channelProp)}if(0===listOfPeers.length)return void log.warn("There are no Peers to start data session with.");self._dataStreams[transferId]={sessions:sessions,chunkType:"string"===sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:sessionChunkType,isPrivate:isPrivate,isStringStream:"string"===sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null,isUpload:!0};var startDataSessionFn=function(peerId,channelProp,targetPeers){if(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+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===window.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;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"), -result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},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),pc.setLocalDescription(new RTCSessionDescription(sessionDescription),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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={} -;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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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};return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(new RTCSessionDescription(offer),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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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};return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(new RTCSessionDescription(answer),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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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]||""),["audio","video"].indexOf(mediaType)===-1&&(self._sdpSessions[targetMid][direction].connection.data=!0);else if(mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){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]=["a=inactive","a=recvonly"].indexOf(sdpLines[i])===-1?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=["a=inactive","a=sendonly"].indexOf(sdpLines[i])===-1?"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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 +!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?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:this.onevent(packet);break;case parser.BINARY_EVENT:this.onevent(packet);break;case parser.ACK:this.onack(packet);break;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}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:function(){try{return window.localStorage}catch(e){}}(),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&&this.transports.indexOf("websocket")!=-1)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(/\\n/g,"\\\n"),this.area.value=data.replace(/\n/g,"\\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="[object Function]"==getClass.call(object);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="[object Function]"==getClass.call(object);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="[object Function]"==getClass.call(object),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"},toPaddedString=function(width,value){return("000000"+(value||0)).slice(-width)},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("[object Boolean]"==(className=getClass.call(value)))return""+value;if("[object Number]"==className)return value>-1/0&&value<1/0?""+value:"null";if("[object String]"==className)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,"[object Array]"==className){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("[object Array]"==getClass.call(value))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&&"[object Function]"==getClass.call(callback)?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=[];(tmp=decodeSymbol())!==!1;)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;i=0)hasMatch=navigator.userAgent.match(/OPR\/(\d+)/i)||[],webrtcDetectedBrowser="opera",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=26,webrtcDetectedType="webkit",webrtcDetectedDCSupport="SCTP";else if(navigator.userAgent.match(/Bowser\/[0-9.]*/g)){hasMatch=navigator.userAgent.match(/Bowser\/[0-9.]*/g)||[];var chromiumVersion=parseInt((navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./i)||[])[2]||"0",10);webrtcDetectedBrowser="bowser",webrtcDetectedVersion=parseFloat((hasMatch[0]||"0/0").split("/")[1],10),webrtcMinimumVersion=0,webrtcDetectedType="webkit",webrtcDetectedDCSupport=chromiumVersion>30?"SCTP":"RTP"}else if(navigator.userAgent.indexOf("OPiOS")>0)hasMatch=navigator.userAgent.match(/OPiOS\/([0-9]+)\./),webrtcDetectedBrowser="opera",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=0,webrtcDetectedType=null,webrtcDetectedDCSupport=null;else if(navigator.userAgent.indexOf("CriOS")>0)hasMatch=navigator.userAgent.match(/CriOS\/([0-9]+)\./)||[],webrtcDetectedBrowser="chrome",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=0,webrtcDetectedType=null,webrtcDetectedDCSupport=null;else if(navigator.userAgent.indexOf("FxiOS")>0)hasMatch=navigator.userAgent.match(/FxiOS\/([0-9]+)\./)||[],webrtcDetectedBrowser="firefox",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=0,webrtcDetectedType=null,webrtcDetectedDCSupport=null;else if(document.documentMode)hasMatch=/\brv[ :]+(\d+)/g.exec(navigator.userAgent)||[],webrtcDetectedBrowser="IE",webrtcDetectedVersion=parseInt(hasMatch[1],10),webrtcMinimumVersion=9,webrtcDetectedType="plugin",webrtcDetectedDCSupport="SCTP",webrtcDetectedVersion||(hasMatch=/\bMSIE[ :]+(\d+)/g.exec(navigator.userAgent)||[],webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10));else if(window.StyleMedia||navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))hasMatch=navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)||[],webrtcDetectedBrowser="edge",webrtcDetectedVersion=parseFloat((hasMatch[0]||"0/0").split("/")[1],10),webrtcMinimumVersion=13.10547,webrtcDetectedType="ms",webrtcDetectedDCSupport=null;else if("undefined"!=typeof InstallTrigger||navigator.userAgent.indexOf("irefox")>0)hasMatch=navigator.userAgent.match(/Firefox\/([0-9]+)\./)||[],webrtcDetectedBrowser="firefox",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=33,webrtcDetectedType="moz",webrtcDetectedDCSupport="SCTP";else if(window.chrome&&window.chrome.webstore||navigator.userAgent.indexOf("Chrom")>0)hasMatch=navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./i)||[],webrtcDetectedBrowser="chrome",webrtcDetectedVersion=parseInt(hasMatch[2]||"0",10),webrtcMinimumVersion=38,webrtcDetectedType="webkit",webrtcDetectedDCSupport=webrtcDetectedVersion>30?"SCTP":"RTP";else if(/^((?!chrome|android).)*safari/i.test(navigator.userAgent)){hasMatch=navigator.userAgent.match(/version\/(\d+)/i)||[];var isMobile=navigator.userAgent.match(/(iPhone|iPad)/gi)||[];webrtcDetectedBrowser="safari",webrtcDetectedVersion=parseInt(hasMatch[1]||"0",10),webrtcMinimumVersion=7,webrtcDetectedType=0===isMobile.length?"plugin":null,webrtcDetectedDCSupport=0===isMobile.length?"SCTP":null}window.webrtcDetectedBrowser=webrtcDetectedBrowser,window.webrtcDetectedVersion=webrtcDetectedVersion,window.webrtcMinimumVersion=webrtcMinimumVersion,window.webrtcDetectedType=webrtcDetectedType,window.webrtcDetectedDCSupport=webrtcDetectedDCSupport},AdapterJS.addEvent=function(elem,evnt,func){elem.addEventListener?elem.addEventListener(evnt,func,!1):elem.attachEvent?elem.attachEvent("on"+evnt,func):elem[evnt]=func},AdapterJS.renderNotificationBar=function(message,buttonText,buttonCallback){if("complete"===document.readyState){var w=window,i=document.createElement("iframe");i.name="adapterjs-alert",i.style.position="fixed",i.style.top="-41px",i.style.left=0,i.style.right=0,i.style.width="100%",i.style.height="40px",i.style.backgroundColor="#ffffe1",i.style.border="none",i.style.borderBottom="1px solid #888888",i.style.zIndex="9999999","string"==typeof i.style.webkitTransition?i.style.webkitTransition="all .5s ease-out":"string"==typeof i.style.transition&&(i.style.transition="all .5s ease-out"),document.body.appendChild(i);var c=i.contentWindow?i.contentWindow:i.contentDocument.document?i.contentDocument.document:i.contentDocument;c.document.open(),c.document.write(''+message+""),buttonText&&"function"==typeof buttonCallback?(c.document.write(''),c.document.close(),AdapterJS.addEvent(c.document.getElementById("okay"),"click",function(e){e.preventDefault();try{e.cancelBubble=!0}catch(error){}buttonCallback(e)}),AdapterJS.addEvent(c.document.getElementById("cancel"),"click",function(e){w.document.body.removeChild(i)})):c.document.close(),setTimeout(function(){"string"==typeof i.style.webkitTransform?i.style.webkitTransform="translateY(40px)":"string"==typeof i.style.transform?i.style.transform="translateY(40px)":i.style.top="0px"},300)}},webrtcDetectedType=null,checkMediaDataChannelSettings=function(peerBrowserAgent,peerBrowserVersion,callback,constraints){if("function"==typeof callback){var beOfferer=!0,isLocalFirefox="firefox"===webrtcDetectedBrowser,isLocalFirefoxInterop="moz"===webrtcDetectedType&&webrtcDetectedVersion>30,isPeerFirefox="firefox"===peerBrowserAgent;if(isLocalFirefox&&isPeerFirefox||isLocalFirefoxInterop)try{delete constraints.mandatory.MozDontOfferDataChannel}catch(error){console.error("Failed deleting MozDontOfferDataChannel"),console.error(error)}else isLocalFirefox&&!isPeerFirefox&&(constraints.mandatory.MozDontOfferDataChannel=!0);if(!isLocalFirefox)for(var prop in constraints.mandatory)constraints.mandatory.hasOwnProperty(prop)&&prop.indexOf("Moz")!==-1&&delete constraints.mandatory[prop];!isLocalFirefox||isPeerFirefox||isLocalFirefoxInterop||(beOfferer=!1),callback(beOfferer,constraints)}},checkIceConnectionState=function(peerId,iceConnectionState,callback){if("function"!=typeof callback)return void console.warn("No callback specified in checkIceConnectionState. Aborted.");peerId=peerId?peerId:"peer",AdapterJS._iceConnectionFiredStates[peerId]&&iceConnectionState!==AdapterJS._iceConnectionStates.disconnected&&iceConnectionState!==AdapterJS._iceConnectionStates.failed&&iceConnectionState!==AdapterJS._iceConnectionStates.closed||(AdapterJS._iceConnectionFiredStates[peerId]=[]),iceConnectionState=AdapterJS._iceConnectionStates[iceConnectionState],AdapterJS._iceConnectionFiredStates[peerId].indexOf(iceConnectionState)<0&&(AdapterJS._iceConnectionFiredStates[peerId].push(iceConnectionState),iceConnectionState===AdapterJS._iceConnectionStates.connected&&setTimeout(function(){AdapterJS._iceConnectionFiredStates[peerId].push(AdapterJS._iceConnectionStates.done),callback(AdapterJS._iceConnectionStates.done)},1e3),callback(iceConnectionState))},createIceServer=null,createIceServers=null,RTCPeerConnection="function"==typeof RTCPeerConnection?RTCPeerConnection:null,RTCSessionDescription="function"==typeof RTCSessionDescription?RTCSessionDescription:null,RTCIceCandidate="function"==typeof RTCIceCandidate?RTCIceCandidate:null,getUserMedia=null,attachMediaStream=null,reattachMediaStream=null,webrtcDetectedBrowser=null,webrtcDetectedVersion=null,webrtcMinimumVersion=null,!(navigator.mozGetUserMedia||navigator.webkitGetUserMedia||navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))||0===(navigator.userAgent.match(/android/gi)||[]).length&&0===(navigator.userAgent.match(/chrome/gi)||[]).length&&navigator.userAgent.indexOf("Safari/")>0?("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.parseWebrtcDetectedBrowser(),isIE="IE"===webrtcDetectedBrowser,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("complete"===document.readyState&&AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING){if(AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTING,"IE"===webrtcDetectedBrowser&&webrtcDetectedVersion<=10){var frag=document.createDocumentFragment();for(AdapterJS.WebRTCPlugin.plugin=document.createElement("div"),AdapterJS.WebRTCPlugin.plugin.innerHTML=' '+(AdapterJS.options.getAllCams?'':"")+"";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,isIE?(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(isIE){try{new ActiveXObject(comName+"."+plugName)}catch(e){return void notInstalledCb()}installedCb()}else{for(var pluginArray=navigator.mimeTypes,i=0;i=0)return void installedCb();notInstalledCb()}},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&&"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};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,navigator.mediaDevices||"undefined"==typeof Promise||(requestUserMedia=function(constraints){return new Promise(function(resolve,reject){getUserMedia(constraints,resolve,reject)})},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(){isIE||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)):(!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.adapter=f()}}(function(){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?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o-1?(parts.attribute=line.substr(sp+1,colon-sp-1),parts.value=line.substr(colon+1)):parts.attribute=line.substr(sp+1),parts},SDPUtils.getDtlsParameters=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);lines=lines.concat(SDPUtils.splitLines(sessionpart));var fpLine=lines.filter(function(line){return 0===line.indexOf("a=fingerprint:")})[0].substr(14);return{role:"auto",fingerprints:[{algorithm:fpLine.split(" ")[0],value:fpLine.split(" ")[1]}]}},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=description.fecMechanisms.indexOf("RED")!==-1,hasUlpfec=description.fecMechanisms.indexOf("ULPFEC")!==-1,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&&(0===bandwidth[0].indexOf("b=TIAS:")?bandwidth=parseInt(bandwidth[0].substr(7),10):0===bandwidth[0].indexOf("b=AS:")&&(bandwidth=parseInt(bandwidth[0].substr(5),10)),encodingParameters.forEach(function(params){params.maxBitrate=bandwidth})),encodingParameters},SDPUtils.writeSessionBoilerplate=function(){return"v=0\r\no=thisisadapterortc 8169639915646943137 2 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", +sdp+=transceiver.rtpSender&&transceiver.rtpReceiver?"a=sendrecv\r\n":transceiver.rtpSender?"a=sendonly\r\n":transceiver.rtpReceiver?"a=recvonly\r\n":"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(selector,successCallback);var fixChromeStats_=function(response){var standardReport={};return response.result().forEach(function(report){var standardStats={id:report.id,timestamp:report.timestamp,type:report.type};report.names().forEach(function(name){standardStats[name]=report.stat(name)}),standardReport[standardStats.id]=standardStats}),standardReport},makeMapStats=function(stats,legacyStats){var map=new Map(Object.keys(stats).map(function(key){return[key,stats[key]]}));return legacyStats=legacyStats||stats,Object.keys(legacyStats).forEach(function(key){map[key]=legacyStats[key]}),map};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){1===args.length&&"object"==typeof selector?origGetStats.apply(self,[function(response){resolve(makeMapStats(fixChromeStats_(response)))},reject]):origGetStats.apply(self,[function(response){resolve(makeMapStats(fixChromeStats_(response),response.result()))},reject])}).then(successCallback,errorCallback)},pc},window.RTCPeerConnection.prototype=webkitRTCPeerConnection.prototype,webkitRTCPeerConnection.generateCertificate&&Object.defineProperty(window.RTCPeerConnection,"generateCertificate",{get:function(){return webkitRTCPeerConnection.generateCertificate}}),["createOffer","createAnswer"].forEach(function(method){var nativeMethod=webkitRTCPeerConnection.prototype[method];webkitRTCPeerConnection.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)}}),browserDetails.version<51&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(method){var nativeMethod=webkitRTCPeerConnection.prototype[method];webkitRTCPeerConnection.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])})}}),["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(method){var nativeMethod=webkitRTCPeerConnection.prototype[method];webkitRTCPeerConnection.prototype[method]=function(){return arguments[0]=new("addIceCandidate"===method?RTCIceCandidate:RTCSessionDescription)(arguments[0]),nativeMethod.apply(this,arguments)}});var nativeAddIceCandidate=RTCPeerConnection.prototype.addIceCandidate;RTCPeerConnection.prototype.addIceCandidate=function(){return null===arguments[0]?Promise.resolve():nativeAddIceCandidate.apply(this,arguments)}}};module.exports={shimMediaStream:chromeShim.shimMediaStream,shimOnTrack:chromeShim.shimOnTrack,shimSourceObject:chromeShim.shimSourceObject,shimPeerConnection:chromeShim.shimPeerConnection,shimGetUserMedia:requirecopy("./getusermedia")}},{"../utils.js":10,"./getusermedia":4}],4:[function(requirecopy,module,exports){"use strict";var logging=requirecopy("../utils.js").log;module.exports=function(){var 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)),constraints&&constraints.audio&&(constraints.audio=constraintsToChrome_(constraints.audio)),constraints&&"object"==typeof constraints.video){var face=constraints.video.facingMode;if((face=face&&("object"==typeof face?face:{ideal:face}))&&("user"===face.exact||"environment"===face.exact||"user"===face.ideal||"environment"===face.ideal)&&(!navigator.mediaDevices.getSupportedConstraints||!navigator.mediaDevices.getSupportedConstraints().facingMode)&&(delete constraints.video.facingMode,"environment"===face.exact||"environment"===face.ideal))return navigator.mediaDevices.enumerateDevices().then(function(devices){devices=devices.filter(function(d){return"videoinput"===d.kind});var back=devices.find(function(d){return d.label.toLowerCase().indexOf("back")!==-1})||devices.length&&devices[devices.length-1];return back&&(constraints.video.deviceId=face.exact?{exact:back.deviceId}:{ideal:back.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",ConstraintNotSatisfiedError:"OverconstrainedError"}[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(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 MediaStreamTrack.getSources(function(devices){resolve(devices.map(function(device){return{label:device.label,kind:kinds[device.kind],deviceId:device.id,groupId:""}}))})})}}),navigator.mediaDevices.getUserMedia){var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(cs){return shimConstraints_(cs,function(c){return origGetUserMedia(c).catch(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":10}],5:[function(requirecopy,module,exports){"use strict";var SDPUtils=requirecopy("sdp"),browserDetails=requirecopy("../utils").browserDetails,edgeShim={shimPeerConnection:function(){window.RTCIceGatherer&&(window.RTCIceCandidate||(window.RTCIceCandidate=function(args){return args}),window.RTCSessionDescription||(window.RTCSessionDescription=function(args){return args})),window.RTCPeerConnection=function(config){var self=this,_eventTarget=document.createDocumentFragment();if(["addEventListener","removeEventListener","dispatchEvent"].forEach(function(method){self[method]=_eventTarget[method].bind(_eventTarget)}),this.onicecandidate=null,this.onaddstream=null,this.ontrack=null,this.onremovestream=null,this.onsignalingstatechange=null,this.oniceconnectionstatechange=null,this.onnegotiationneeded=null,this.ondatachannel=null,this.localStreams=[],this.remoteStreams=[],this.getLocalStreams=function(){return self.localStreams},this.getRemoteStreams=function(){return self.remoteStreams},this.localDescription=new RTCSessionDescription({type:"",sdp:""}),this.remoteDescription=new RTCSessionDescription({type:"",sdp:""}),this.signalingState="stable",this.iceConnectionState="new",this.iceGatheringState="new",this.iceOptions={gatherPolicy:"all",iceServers:[]},config&&config.iceTransportPolicy)switch(config.iceTransportPolicy){case"all":case"relay":this.iceOptions.gatherPolicy=config.iceTransportPolicy;break;case"none":throw new TypeError('iceTransportPolicy "none" not supported')}if(this.usingBundle=config&&"max-bundle"===config.bundlePolicy,config&&config.iceServers){var iceServers=JSON.parse(JSON.stringify(config.iceServers));this.iceOptions.iceServers=iceServers.filter(function(server){if(server&&server.urls){var urls=server.urls;return"string"==typeof urls&&(urls=[urls]),!!(urls=urls.filter(function(url){return 0===url.indexOf("turn:")&&url.indexOf("transport=udp")!==-1&&url.indexOf("turn:[")===-1||0===url.indexOf("stun:")&&browserDetails.version>=14393})[0])}return!1})}this.transceivers=[],this._localIceCandidatesBuffer=[]},window.RTCPeerConnection.prototype._emitBufferedCandidates=function(){var self=this,sections=SDPUtils.splitSections(self.localDescription.sdp);this._localIceCandidatesBuffer.forEach(function(event){if(event.candidate&&0!==Object.keys(event.candidate).length)event.candidate.candidate.indexOf("typ endOfCandidates")===-1&&(sections[event.candidate.sdpMLineIndex+1]+="a="+event.candidate.candidate+"\r\n");else for(var j=1;j-1&&(this.localStreams.splice(idx,1),this._maybeFireNegotiationNeeded())},window.RTCPeerConnection.prototype.getSenders=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpSender}).map(function(transceiver){return transceiver.rtpSender})},window.RTCPeerConnection.prototype.getReceivers=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpReceiver}).map(function(transceiver){return transceiver.rtpReceiver})},window.RTCPeerConnection.prototype._getCommonCapabilities=function(localCapabilities,remoteCapabilities){var commonCapabilities={codecs:[],headerExtensions:[],fecMechanisms:[]};return localCapabilities.codecs.forEach(function(lCodec){for(var i=0;i0;sections.forEach(function(mediaSection,sdpMLineIndex){var transceiver=self.transceivers[sdpMLineIndex],iceGatherer=transceiver.iceGatherer,iceTransport=transceiver.iceTransport,dtlsTransport=transceiver.dtlsTransport,localCapabilities=transceiver.localCapabilities,remoteCapabilities=transceiver.remoteCapabilities;if("0"!==mediaSection.split("\n",1)[0].split(" ",2)[1]&&!transceiver.isDatachannel){var remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);if(isIceLite){var cands=SDPUtils.matchPrefix(mediaSection,"a=candidate:").map(function(cand){return SDPUtils.parseCandidate(cand)}).filter(function(cand){return"1"===cand.component});cands.length&&iceTransport.setRemoteCandidates(cands)}var remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);isIceLite&&(remoteDtlsParameters.role="server"),self.usingBundle&&0!==sdpMLineIndex||(iceTransport.start(iceGatherer,remoteIceParameters,isIceLite?"controlling":"controlled"),dtlsTransport.start(remoteDtlsParameters));var params=self._getCommonCapabilities(localCapabilities,remoteCapabilities);self._transceive(transceiver,params.codecs.length>0,!1)}})}switch(this.localDescription={type:description.type,sdp:description.sdp},description.type){case"offer":this._updateSignalingState("have-local-offer");break;case"answer":this._updateSignalingState("stable");break;default:throw new TypeError('unsupported type "'+description.type+'"')}var hasCallback=arguments.length>1&&"function"==typeof arguments[1];if(hasCallback){var cb=arguments[1];window.setTimeout(function(){cb(),"new"===self.iceGatheringState&&(self.iceGatheringState="gathering"),self._emitBufferedCandidates()},0)}var p=Promise.resolve();return p.then(function(){hasCallback||("new"===self.iceGatheringState&&(self.iceGatheringState="gathering"),window.setTimeout(self._emitBufferedCandidates.bind(self),500))}),p},window.RTCPeerConnection.prototype.setRemoteDescription=function(description){var self=this,stream=new MediaStream,receiverList=[],sections=SDPUtils.splitSections(description.sdp),sessionpart=sections.shift(),isIceLite=SDPUtils.matchPrefix(sessionpart,"a=ice-lite").length>0;switch(this.usingBundle=SDPUtils.matchPrefix(sessionpart,"a=group:BUNDLE ").length>0,sections.forEach(function(mediaSection,sdpMLineIndex){var lines=SDPUtils.splitLines(mediaSection),mline=lines[0].substr(2).split(" "),kind=mline[0],rejected="0"===mline[1],direction=SDPUtils.getDirection(mediaSection,sessionpart),mid=SDPUtils.matchPrefix(mediaSection,"a=mid:");if(mid=mid.length?mid[0].substr(6):SDPUtils.generateIdentifier(),"application"===kind&&"DTLS/SCTP"===mline[2])return void(self.transceivers[sdpMLineIndex]={mid:mid,isDatachannel:!0});var transceiver,iceGatherer,iceTransport,dtlsTransport,rtpSender,rtpReceiver,sendEncodingParameters,recvEncodingParameters,localCapabilities,track,remoteIceParameters,remoteDtlsParameters,remoteCapabilities=SDPUtils.parseRtpParameters(mediaSection);rejected||(remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart),remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart),remoteDtlsParameters.role="client"),recvEncodingParameters=SDPUtils.parseRtpEncodingParameters(mediaSection);var cname,remoteSsrc=SDPUtils.matchPrefix(mediaSection,"a=ssrc:").map(function(line){return SDPUtils.parseSsrcMedia(line)}).filter(function(obj){return"cname"===obj.attribute})[0];remoteSsrc&&(cname=remoteSsrc.value);var isComplete=SDPUtils.matchPrefix(mediaSection,"a=end-of-candidates",sessionpart).length>0,cands=SDPUtils.matchPrefix(mediaSection,"a=candidate:").map(function(cand){return SDPUtils.parseCandidate(cand)}).filter(function(cand){return"1"===cand.component});if("offer"!==description.type||rejected)"answer"!==description.type||rejected||(transceiver=self.transceivers[sdpMLineIndex],iceGatherer=transceiver.iceGatherer,iceTransport=transceiver.iceTransport,dtlsTransport=transceiver.dtlsTransport,rtpSender=transceiver.rtpSender,rtpReceiver=transceiver.rtpReceiver,sendEncodingParameters=transceiver.sendEncodingParameters,localCapabilities=transceiver.localCapabilities,self.transceivers[sdpMLineIndex].recvEncodingParameters=recvEncodingParameters,self.transceivers[sdpMLineIndex].remoteCapabilities=remoteCapabilities,self.transceivers[sdpMLineIndex].cname=cname,(isIceLite||isComplete)&&cands.length&&iceTransport.setRemoteCandidates(cands),self.usingBundle&&0!==sdpMLineIndex||(iceTransport.start(iceGatherer,remoteIceParameters,"controlling"),dtlsTransport.start(remoteDtlsParameters)),self._transceive(transceiver,"sendrecv"===direction||"recvonly"===direction,"sendrecv"===direction||"sendonly"===direction),!rtpReceiver||"sendrecv"!==direction&&"sendonly"!==direction?delete transceiver.rtpReceiver:(track=rtpReceiver.track,receiverList.push([track,rtpReceiver]),stream.addTrack(track)));else{var transports=self.usingBundle&&sdpMLineIndex>0?{iceGatherer:self.transceivers[0].iceGatherer,iceTransport:self.transceivers[0].iceTransport,dtlsTransport:self.transceivers[0].dtlsTransport}:self._createIceAndDtlsTransports(mid,sdpMLineIndex);if(isComplete&&transports.iceTransport.setRemoteCandidates(cands),localCapabilities=RTCRtpReceiver.getCapabilities(kind),sendEncodingParameters=[{ssrc:1001*(2*sdpMLineIndex+2)}],rtpReceiver=new RTCRtpReceiver(transports.dtlsTransport,kind),track=rtpReceiver.track,receiverList.push([track,rtpReceiver]),stream.addTrack(track),self.localStreams.length>0&&self.localStreams[0].getTracks().length>=sdpMLineIndex){var localTrack;"audio"===kind?localTrack=self.localStreams[0].getAudioTracks()[0]:"video"===kind&&(localTrack=self.localStreams[0].getVideoTracks()[0]),localTrack&&(rtpSender=new RTCRtpSender(localTrack,transports.dtlsTransport))}self.transceivers[sdpMLineIndex]={iceGatherer:transports.iceGatherer,iceTransport:transports.iceTransport,dtlsTransport:transports.dtlsTransport,localCapabilities:localCapabilities,remoteCapabilities:remoteCapabilities,rtpSender:rtpSender,rtpReceiver:rtpReceiver,kind:kind,mid:mid,cname:cname,sendEncodingParameters:sendEncodingParameters,recvEncodingParameters:recvEncodingParameters},self._transceive(self.transceivers[sdpMLineIndex],!1,"sendrecv"===direction||"sendonly"===direction)}}),this.remoteDescription={type:description.type,sdp:description.sdp},description.type){case"offer":this._updateSignalingState("have-remote-offer");break;case"answer":this._updateSignalingState("stable");break;default:throw new TypeError('unsupported type "'+description.type+'"')}return stream.getTracks().length&&(self.remoteStreams.push(stream),window.setTimeout(function(){var event=new Event("addstream");event.stream=stream,self.dispatchEvent(event),null!==self.onaddstream&&window.setTimeout(function(){self.onaddstream(event)},0),receiverList.forEach(function(item){var track=item[0],receiver=item[1],trackEvent=new Event("track");trackEvent.track=track,trackEvent.receiver=receiver,trackEvent.streams=[stream],self.dispatchEvent(event),null!==self.ontrack&&window.setTimeout(function(){self.ontrack(trackEvent)},0)})},0)),arguments.length>1&&"function"==typeof arguments[1]&&window.setTimeout(arguments[1],0),Promise.resolve()},window.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")},window.RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event("signalingstatechange");this.dispatchEvent(event),null!==this.onsignalingstatechange&&this.onsignalingstatechange(event)},window.RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var event=new Event("negotiationneeded");this.dispatchEvent(event),null!==this.onnegotiationneeded&&this.onnegotiationneeded(event)},window.RTCPeerConnection.prototype._updateConnectionState=function(){var newState,self=this,states={new:0,closed:0,connecting:0,checking:0,connected:0,completed: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)}},window.RTCPeerConnection.prototype.createOffer=function(){var self=this;if(this._pendingOffer)throw new Error("createOffer called while there is a pending offer.");var offerOptions;1===arguments.length&&"function"!=typeof arguments[0]?offerOptions=arguments[0]:3===arguments.length&&(offerOptions=arguments[2]);var tracks=[],numAudioTracks=0,numVideoTracks=0;if(this.localStreams.length&&(numAudioTracks=this.localStreams[0].getAudioTracks().length,numVideoTracks=this.localStreams[0].getVideoTracks().length),offerOptions){if(offerOptions.mandatory||offerOptions.optional)throw new TypeError("Legacy mandatory/optional constraints not supported.");void 0!==offerOptions.offerToReceiveAudio&&(numAudioTracks=offerOptions.offerToReceiveAudio),void 0!==offerOptions.offerToReceiveVideo&&(numVideoTracks=offerOptions.offerToReceiveVideo)}for(this.localStreams.length&&this.localStreams[0].getTracks().forEach(function(track){tracks.push({kind:track.kind,track:track,wantReceive:"audio"===track.kind?numAudioTracks>0:numVideoTracks>0}),"audio"===track.kind?numAudioTracks--:"video"===track.kind&&numVideoTracks--});numAudioTracks>0||numVideoTracks>0;)numAudioTracks>0&&(tracks.push({kind:"audio",wantReceive:!0}),numAudioTracks--),numVideoTracks>0&&(tracks.push({kind:"video",wantReceive:!0}),numVideoTracks--);var sdp=SDPUtils.writeSessionBoilerplate(),transceivers=[];tracks.forEach(function(mline,sdpMLineIndex){var rtpSender,rtpReceiver,track=mline.track,kind=mline.kind,mid=SDPUtils.generateIdentifier(),transports=self.usingBundle&&sdpMLineIndex>0?{iceGatherer:transceivers[0].iceGatherer,iceTransport:transceivers[0].iceTransport,dtlsTransport:transceivers[0].dtlsTransport}:self._createIceAndDtlsTransports(mid,sdpMLineIndex),localCapabilities=RTCRtpSender.getCapabilities(kind),sendEncodingParameters=[{ssrc:1001*(2*sdpMLineIndex+1)}];track&&(rtpSender=new RTCRtpSender(track,transports.dtlsTransport)),mline.wantReceive&&(rtpReceiver=new RTCRtpReceiver(transports.dtlsTransport,kind)),transceivers[sdpMLineIndex]={iceGatherer:transports.iceGatherer,iceTransport:transports.iceTransport,dtlsTransport:transports.dtlsTransport,localCapabilities:localCapabilities,remoteCapabilities:null,rtpSender:rtpSender,rtpReceiver:rtpReceiver,kind:kind,mid:mid,sendEncodingParameters:sendEncodingParameters,recvEncodingParameters:null}}), +this.usingBundle&&(sdp+="a=group:BUNDLE "+transceivers.map(function(t){return t.mid}).join(" ")+"\r\n"),tracks.forEach(function(mline,sdpMLineIndex){var transceiver=transceivers[sdpMLineIndex];sdp+=SDPUtils.writeMediaSection(transceiver,transceiver.localCapabilities,"offer",self.localStreams[0])}),this._pendingOffer=transceivers;var desc=new RTCSessionDescription({type:"offer",sdp:sdp});return arguments.length&&"function"==typeof arguments[0]&&window.setTimeout(arguments[0],0,desc),Promise.resolve(desc)},window.RTCPeerConnection.prototype.createAnswer=function(){var self=this,sdp=SDPUtils.writeSessionBoilerplate();this.usingBundle&&(sdp+="a=group:BUNDLE "+this.transceivers.map(function(t){return t.mid}).join(" ")+"\r\n"),this.transceivers.forEach(function(transceiver){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");var commonCapabilities=self._getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);sdp+=SDPUtils.writeMediaSection(transceiver,commonCapabilities,"answer",self.localStreams[0])});var desc=new RTCSessionDescription({type:"answer",sdp:sdp});return arguments.length&&"function"==typeof arguments[0]&&window.setTimeout(arguments[0],0,desc),Promise.resolve(desc)},window.RTCPeerConnection.prototype.addIceCandidate=function(candidate){if(null===candidate)this.transceivers.forEach(function(transceiver){transceiver.iceTransport.addRemoteCandidate({})});else{var mLineIndex=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;if("1"!==cand.component)return;"endOfCandidates"===cand.type&&(cand={}),transceiver.iceTransport.addRemoteCandidate(cand);var sections=SDPUtils.splitSections(this.remoteDescription.sdp);sections[mLineIndex+1]+=(cand.type?candidate.candidate.trim():"a=end-of-candidates")+"\r\n",this.remoteDescription.sdp=sections.join("")}}return arguments.length>1&&"function"==typeof arguments[1]&&window.setTimeout(arguments[1],0),Promise.resolve()},window.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];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){results.set(id,result[id]),results[id]=result[id]})}),cb&&window.setTimeout(cb,0,results),resolve(results)})})}}};module.exports={shimPeerConnection:edgeShim.shimPeerConnection,shimGetUserMedia:requirecopy("./getusermedia")}},{"../utils":10,"./getusermedia":6,sdp:1}],6:[function(requirecopy,module,exports){"use strict";module.exports=function(){var 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))})}}},{}],7:[function(requirecopy,module,exports){"use strict";var browserDetails=requirecopy("../utils").browserDetails,firefoxShim={shimOnTrack:function(){"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.streams=[e.stream],this.dispatchEvent(event)}.bind(this))}.bind(this))}})},shimSourceObject:function(){"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(){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;i=pos&&parseInt(match[pos],10)},detectBrowser:function(){var result={};if(result.browser=null,result.version=null,"undefined"==typeof window||!window.navigator)return result.browser="Not a browser.",result;if(navigator.mozGetUserMedia)result.browser="firefox",result.version=this.extractVersion(navigator.userAgent,/Firefox\/([0-9]+)\./,1);else if(navigator.webkitGetUserMedia)if(window.webkitRTCPeerConnection)result.browser="chrome",result.version=this.extractVersion(navigator.userAgent,/Chrom(e|ium)\/([0-9]+)\./,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\/([0-9]+)\./,1)}else{if(!navigator.mediaDevices||!navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))return result.browser="Not a supported browser.",result;result.browser="edge",result.version=this.extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2)}return result}};module.exports={log:utils.log,disableLog:utils.disableLog,browserDetails:utils.detectBrowser(),extractVersion:utils.extractVersion}},{}]},{},[2])(2)}),AdapterJS.parseWebrtcDetectedBrowser(),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(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 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(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"!==webrtcDetectedBrowser&&"opera"!==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()),"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.defineMediaSourcePolyfill=function(){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};if(window.navigator.mozGetUserMedia?(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(constraints&&constraints.video&&constraints.video.mediaSource){if("screen"!==constraints.video.mediaSource&&"window"!==constraints.video.mediaSource)return void failureCb(new Error('GetUserMedia: Only "screen" and "window" are supported as mediaSource constraints'));var updatedConstraints=clone(constraints);updatedConstraints.video.mozMediaSource=updatedConstraints.video.mediaSource;var checkIfReady=setInterval(function(){"complete"===document.readyState&&(clearInterval(checkIfReady),baseGetUserMedia(updatedConstraints,successCb,function(error){["NotAllowedError","PermissionDeniedError","SecurityError","NotAllowedError"].indexOf(error.name)>-1&&"https:"===window.parent.location.protocol?AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_FF,AdapterJS.TEXT.EXTENSION.BUTTON_FF,function(e){window.open("https://addons.mozilla.org/en-US/firefox/addon/skylink-webrtc-tools/","_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):window.navigator.webkitGetUserMedia&&"safari"!==window.webrtcDetectedBrowser?(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(constraints&&constraints.video&&constraints.video.mediaSource){if("chrome"!==window.webrtcDetectedBrowser)return void failureCb(new Error("Current browser does not support screensharing"));var updatedConstraints=clone(constraints),chromeCallback=function(error,sourceId){error?failureCb("permission-denied"===error?new Error("Permission denied for screen retrieval"):new Error("Failed retrieving selected screen")):(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,sourceId&&(updatedConstraints.video.mandatory.chromeMediaSourceId=sourceId),delete updatedConstraints.video.mediaSource,baseGetUserMedia(updatedConstraints,successCb,failureCb))},onIFrameCallback=function(event){event.data&&(event.data.chromeMediaSourceId&&("PermissionDeniedError"===event.data.chromeMediaSourceId?chromeCallback("permission-denied"):chromeCallback(null,event.data.chromeMediaSourceId)),event.data.chromeExtensionStatus&&("not-installed"===event.data.chromeExtensionStatus?AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_CHROME,AdapterJS.TEXT.EXTENSION.BUTTON_CHROME,function(e){window.open(event.data.data,"_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")})}):chromeCallback(event.data.chromeExtensionStatus,null)),window.removeEventListener("message",onIFrameCallback))};window.addEventListener("message",onIFrameCallback),postFrameMessage({captureSourceId:!0})}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=window.getUserMedia=navigator.getUserMedia,navigator.mediaDevices.getUserMedia=function(constraints){return new Promise(function(resolve,reject){window.getUserMedia(constraints,resolve,reject)})}):navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)?console.warn("Edge does not support screensharing feature in getUserMedia"):(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(constraints&&constraints.video&&constraints.video.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"));updatedConstraints.video.optional=updatedConstraints.video.optional||[],updatedConstraints.video.optional.push({sourceId:AdapterJS.WebRTCPlugin.plugin.screensharingKey||"Screensharing"}),delete 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)),"chrome"===window.webrtcDetectedBrowser){var iframe=document.createElement("iframe");iframe.onload=function(){iframe.isLoaded=!0},iframe.src="https://cdn.temasys.com.sg/skylink/extensions/detectRTC.html",iframe.style.display="none",(document.body||document.documentElement).appendChild(iframe);var postFrameMessage=function(object){if(object=object||{},!iframe.isLoaded)return void setTimeout(function(){iframe.contentWindow.postMessage(object,"*")},100);iframe.contentWindow.postMessage(object,"*")}}else"opera"===window.webrtcDetectedBrowser&&console.warn("Opera does not support screensharing feature in getUserMedia")},"function"!=typeof window.require&&AdapterJS.defineMediaSourcePolyfill(),function(globals){"use strict";function Skylink(){this._enableDataChannel=!0,this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._filterCandidatesType={host:!1,srflx:!1,relay:!1},this._enableIceTrickle=!0,this._enableSTUN=!0,this._enableTURN=!0,this._usePublicSTUN=!0,this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._isUsingPlugin=!1,this._TURNTransport="any",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._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,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._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,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._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,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._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={}}!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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],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&&(self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")===-1||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"===window.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){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.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,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.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},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";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){console.info(evtPeerId,error,cN,cT),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.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].indexOf(state)>-1}),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)}else 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),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),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}),delete self._dataTransfers[transferId]},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._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._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.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},i=0;i-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}})}(peerId,channelProp)}if(0===listOfPeers.length)return void log.warn("There are no Peers to start data session with.");self._dataStreams[transferId]={sessions:sessions,chunkType:"string"===sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:sessionChunkType,isPrivate:isPrivate,isStringStream:"string"===sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null,isUpload:!0};var startDataSessionFn=function(peerId,channelProp,targetPeers){if(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+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===window.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;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10), +result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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]&&(peerInfo.settings.audio&&(this._sdpSessions[peerId].local&&this._sdpSessions[peerId].local.connection&&!((this._sdpSessions[peerId].local.connection.audio||"").indexOf("recv")>-1)||this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&!((this._sdpSessions[peerId].remote.connection.audio||"").indexOf("send")>-1))&&(peerInfo.settings.audio=!1),peerInfo.settings.video&&(this._sdpSessions[peerId].local&&this._sdpSessions[peerId].local.connection&&!((this._sdpSessions[peerId].local.connection.video||"").indexOf("recv")>-1)||this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&!((this._sdpSessions[peerId].remote.connection.video||"").indexOf("send")>-1))&&(peerInfo.settings.video=!1),peerInfo.settings.data&&(this._sdpSessions[peerId].local&&this._sdpSessions[peerId].local.connection&&!this._sdpSessions[peerId].local.connection.data||this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&!this._sdpSessions[peerId].remote.connection.data)&&(peerInfo.settings.data=!1))):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},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),pc.setLocalDescription(new RTCSessionDescription(sessionDescription),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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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="SkylinkJS";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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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};return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),void pc.setRemoteDescription(new RTCSessionDescription(offer),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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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};return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?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),void pc.setRemoteDescription(new RTCSessionDescription(answer),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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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]||""),["audio","video"].indexOf(mediaType)===-1&&(self._sdpSessions[targetMid][direction].connection.data=!0);else if(mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){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]=["a=inactive","a=recvonly"].indexOf(sdpLines[i])===-1?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=["a=inactive","a=sendonly"].indexOf(sdpLines[i])===-1?"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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 d403e8bd5..f7cf8d40d 100644 --- a/publish/skylink.debug.js +++ b/publish/skylink.debug.js @@ -1,4 +1,4 @@ -/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 18:32:00 GMT+0800 (SGT) */ +/*! skylinkjs - v0.6.19 - Tue Apr 18 2017 18:58:56 GMT+0800 (SGT) */ (function(globals) { @@ -7837,6 +7837,29 @@ Skylink.prototype.getPeerInfo = function(peerId) { peerInfo.connected = this._peerConnStatus[peerId] && !!this._peerConnStatus[peerId].connected; peerInfo.init = this._peerConnStatus[peerId] && !!this._peerConnStatus[peerId].init; + if (this._sdpSessions[peerId]) { + // Set audio to false if SDP m= line and direction is not available + if (peerInfo.settings.audio && !((this._sdpSessions[peerId].local && this._sdpSessions[peerId].local.connection ? + (this._sdpSessions[peerId].local.connection.audio || '').indexOf('recv') > -1 : true) && + (this._sdpSessions[peerId].remote && this._sdpSessions[peerId].remote.connection ? + (this._sdpSessions[peerId].remote.connection.audio || '').indexOf('send') > -1 : true))) { + peerInfo.settings.audio = false; + } + // Set video to false if SDP m= line and direction is not available + if (peerInfo.settings.video && !((this._sdpSessions[peerId].local && this._sdpSessions[peerId].local.connection ? + (this._sdpSessions[peerId].local.connection.video || '').indexOf('recv') > -1 : true) && + (this._sdpSessions[peerId].remote && this._sdpSessions[peerId].remote.connection ? + (this._sdpSessions[peerId].remote.connection.video || '').indexOf('send') > -1 : true))) { + peerInfo.settings.video = false; + } + // Set data to false if SDP m= line and direction is not available + if (peerInfo.settings.data && !((this._sdpSessions[peerId].local && this._sdpSessions[peerId].local.connection ? + this._sdpSessions[peerId].local.connection.data : true) && (this._sdpSessions[peerId].remote && + this._sdpSessions[peerId].remote.connection ? this._sdpSessions[peerId].remote.connection.data : true))) { + peerInfo.settings.data = false; + } + } + } else { peerInfo = { userData: clone(this._userData), @@ -15074,6 +15097,10 @@ Skylink.prototype._offerHandler = function(message) { self._addLocalMediaStreams(targetMid); } + if (message.userInfo) { + self._trigger('peerUpdated', targetMid, self.getPeerInfo(targetMid), false); + } + pc.setRemoteDescription(new RTCSessionDescription(offer), function() { log.debug([targetMid, 'RTCSessionDescription', message.type, 'Remote description set']); pc.setOffer = 'remote'; @@ -15274,6 +15301,10 @@ Skylink.prototype._answerHandler = function(message) { pc.processingRemoteSDP = true; + if (message.userInfo) { + self._trigger('peerUpdated', targetMid, self.getPeerInfo(targetMid), false); + } + pc.setRemoteDescription(new RTCSessionDescription(answer), function() { log.debug([targetMid, null, message.type, 'Remote description set']); pc.setAnswer = 'remote'; diff --git a/publish/skylink.min.js b/publish/skylink.min.js index 1c150e656..4c400b222 100644 --- a/publish/skylink.min.js +++ b/publish/skylink.min.js @@ -1,12 +1,12 @@ /*! skylinkjs - v0.6.19 - 2017-04-18 */ -!function(globals){"use strict";function Skylink(){this._enableDataChannel=!0,this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._filterCandidatesType={host:!1,srflx:!1,relay:!1},this._enableIceTrickle=!0,this._enableSTUN=!0,this._enableTURN=!0,this._usePublicSTUN=!0,this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._isUsingPlugin=!1,this._TURNTransport="any",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._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,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._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,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._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,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._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={}}!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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],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&&(self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")===-1||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"===window.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){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.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,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.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},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";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){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.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].indexOf(state)>-1}),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)}else 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),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),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}),delete self._dataTransfers[transferId]},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._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._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.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},i=0;i-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}})}(peerId,channelProp)}if(0===listOfPeers.length)return void log.warn("There are no Peers to start data session with.");self._dataStreams[transferId]={sessions:sessions,chunkType:"string"===sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:sessionChunkType,isPrivate:isPrivate,isStringStream:"string"===sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null,isUpload:!0};var startDataSessionFn=function(peerId,channelProp,targetPeers){if(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+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===window.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;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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) +!function(globals){"use strict";function Skylink(){this._enableDataChannel=!0,this._dataChannels={},this._dataTransfers={},this._dataStreams={},this._peerCandidatesQueue={},this._peerEndOfCandidatesCounter={},this._gatheredCandidates={},this._filterCandidatesType={host:!1,srflx:!1,relay:!1},this._enableIceTrickle=!0,this._enableSTUN=!0,this._enableTURN=!0,this._usePublicSTUN=!0,this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},this._isUsingPlugin=!1,this._TURNTransport="any",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._throttlingTimeouts={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},this._throttlingShouldThrowError=!1,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._socketTimeout=2e4,this._socketUseXDR=!1,this._enableIceRestart="firefox"!==window.webrtcDetectedBrowser||window.webrtcDetectedVersion>=48,this._hasMCU=!1,this._forceSSL=!1,this._forceTURNSSL=!1,this._forceTURN=!1,this._path=null,this._roomServer="//api.temasys.io",this._appKey=null,this._defaultRoom=null,this._roomStart=null,this._roomDuration=null,this._roomCredentials=null,this._readyState=0,this._key=null,this._appKeyOwner=null,this._room=null,this._peerMessagesStamps={},this._audioFallback=!1,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._selectedAudioCodec="auto",this._selectedVideoCodec="auto",this._disableVideoFecCodecs=!1,this._disableComfortNoiseCodec=!1,this._disableREMB=!1,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._mcuUseRenegoRestart=!1,this._iceServer=null,this._socketServer=null,this._currentCodecSupport=null,this._sdpSessions={},this._voiceActivityDetection=!0,this._binaryChunkType="firefox"===window.webrtcDetectedBrowser?this.DATA_TRANSFER_DATA_TYPE.BLOB:this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={}}!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;var clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=function(data){var copy=data.constructor();for(var attr in data)data.hasOwnProperty(attr)&&(copy[attr]=data[attr]);return copy};if("object"==typeof obj&&!Array.isArray(obj))try{return JSON.parse(JSON.stringify(obj))}catch(err){return copy(obj)}return copy(obj)};Skylink.prototype.DATA_CHANNEL_STATE={CONNECTING:"connecting",OPEN:"open",CLOSING:"closing",CLOSED:"closed",ERROR:"error",CREATE_ERROR:"createError",BUFFERED_AMOUNT_LOW:"bufferedAmountLow",SEND_MESSAGE_ERROR:"sendMessageError"},Skylink.prototype.DATA_CHANNEL_TYPE={MESSAGING:"messaging",DATA:"data"},Skylink.prototype.DATA_CHANNEL_MESSAGE_ERROR={MESSAGE:"message",TRANSFER:"transfer"},Skylink.prototype._createDataChannel=function(peerId,dataChannel,bufferThreshold,createAsMessagingChannel){var self=this,channelName=(self._user&&self._user.sid?self._user.sid:"-")+"_"+peerId,channelType=createAsMessagingChannel?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,channelProp=channelType===self.DATA_CHANNEL_TYPE.MESSAGING?"main":channelName;if(!self._user)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as User does not have Room session"]);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.error([peerId,"RTCDataChannel",channelProp,"Aborting of creating or initializing Datachannel as Peer connection does not exists"]);if(dataChannel&&"object"==typeof dataChannel?channelName=dataChannel.label:"string"==typeof dataChannel&&(channelName=dataChannel,dataChannel=null),!dataChannel)try{dataChannel=self._peerConnections[peerId].createDataChannel(channelName,{reliable:!0,ordered:!0})}catch(error){return log.error([peerId,"RTCDataChannel",channelProp,"Failed creating Datachannel ->"],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&&(self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")===-1||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"===window.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){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.DATA_TRANSFER_DATA_TYPE={BINARY_STRING:"binaryString",ARRAY_BUFFER:"arrayBuffer",BLOB:"blob",STRING:"string"},Skylink.prototype._CHUNK_FILE_SIZE=49152,Skylink.prototype._MOZ_CHUNK_FILE_SIZE=12288,Skylink.prototype._BINARY_FILE_SIZE=65456,Skylink.prototype._MOZ_BINARY_FILE_SIZE=16384,Skylink.prototype._CHUNK_DATAURL_SIZE=1212,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.DT_PROTOCOL_VERSION="0.1.3",Skylink.prototype.DATA_TRANSFER_TYPE={UPLOAD:"upload",DOWNLOAD:"download"},Skylink.prototype.DATA_TRANSFER_SESSION_TYPE={BLOB:"blob",DATA_URL:"dataURL"},Skylink.prototype.DATA_TRANSFER_STATE={UPLOAD_REQUEST:"request",UPLOAD_STARTED:"uploadStarted",DOWNLOAD_STARTED:"downloadStarted",REJECTED:"rejected",CANCEL:"cancel",ERROR:"error",UPLOADING:"uploading",DOWNLOADING:"downloading",UPLOAD_COMPLETED:"uploadCompleted",DOWNLOAD_COMPLETED:"downloadCompleted",USER_REJECTED:"userRejected",USER_UPLOAD_REQUEST:"userRequest",START_ERROR:"startError"},Skylink.prototype.DATA_STREAM_STATE={SENDING_STARTED:"sendStart",SENDING_STOPPED:"sendStop",RECEIVING_STARTED:"receiveStart",RECEIVING_STOPPED:"receiveStop",RECEIVED:"received",SENT:"sent",ERROR:"error",START_ERROR:"startError"},Skylink.prototype._DC_PROTOCOL_TYPE={WRQ:"WRQ",ACK:"ACK",ERROR:"ERROR",CANCEL:"CANCEL",MESSAGE:"MESSAGE"},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";if(self._dataChannels[peerId][transferId]&&(channelProp=transferId),accept){log.debug([peerId,"RTCDataChannel",transferId,"Accepted data transfer and starting ..."]);var dataChannelStateCbFn=function(state,evtPeerId,error,cN,cT){console.info(evtPeerId,error,cN,cT),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.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].indexOf(state)>-1}),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)}else 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),"main"===channelProp&&self._dataChannels[peerId].main&&(self._dataChannels[peerId].main.transferId=null),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}),delete self._dataTransfers[transferId]},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._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._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.");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},i=0;i-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}})}(peerId,channelProp)}if(0===listOfPeers.length)return void log.warn("There are no Peers to start data session with.");self._dataStreams[transferId]={sessions:sessions,chunkType:"string"===sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:sessionChunkType,isPrivate:isPrivate,isStringStream:"string"===sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null,isUpload:!0};var startDataSessionFn=function(peerId,channelProp,targetPeers){if(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+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===window.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;i-1&&"string"!=typeof dataChunk?new Int8Array(dataChunk):dataChunk:new Blob([dataChunk]))};for(var peerId in self._dataStreams[transferId].sessions)if(self._dataStreams[transferId].sessions.hasOwnProperty(peerId)&&self._dataStreams[transferId].sessions[peerId]){var channelProp=self._dataStreams[transferId].sessions[peerId];if(!self._dataChannels[self._hasMCU?"MCU":peerId]||!self._dataChannels[self._hasMCU?"MCU":peerId][channelProp]||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].channel.readyState!==self.DATA_CHANNEL_STATE.OPEN||self._dataChannels[self._hasMCU?"MCU":peerId][channelProp].streamId!==transferId)return log.error([peerId,"RTCDataChannel",transferId,"Failed streaming data as it has not started or is ready."]),void self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,peerId,sessionInfo,new Error("Streaming as it has not started or Datachannel connection is not open."));self._hasMCU?"main"===channelProp?peersInterop.push(peerId):peersNonInterop.push(peerId):sendDataFn(peerId,channelProp)}self._hasMCU&&(peersInterop.length>0&&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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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"===window.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:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion,target:targetPeers?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){if(peerConnectionStateCbFn&&self.off("peerConnectionState",peerConnectionStateCbFn),dataChannelStateCbFn&&self.off("dataChannelState",dataChannelStateCbFn),channelProp&&delete self._dataTransfers[transferId].peers[channelProp][peerId],state===self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED?callback(peerId,null):callback(peerId,error.message.message||error.message.toString()),self._hasMCU&&self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD){if(0!==Object.keys(self._dataTransfers[transferId].peers.main).length||0!==Object.keys(self._dataTransfers[transferId].peers[transferId]).length)return;delete self._dataTransfers[transferId]}else delete self._dataTransfers[transferId].sessions[peerId],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&&self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)===-1))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");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){return self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]?evtPeerId!==peerId||channelType===self.DATA_CHANNEL_TYPE.DATA&&channelName!==transferId?void 0:state===self.DATA_CHANNEL_STATE.OPEN&&channelType===self.DATA_CHANNEL_TYPE.DATA&&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 self.off("dataChannelState",dataChannelStateCbFn)}),void(requireInterop&&"MCU"!==peerId||"main"===channelProp?(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"===window.webrtcDetectedBrowser?16384:65546:"firefox"===window.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 errorMsg="Connection Timeout. Longer than "+self._dataTransfers[transferId].timeout+" seconds. Connection is abolished.";self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ERROR,content:errorMsg,isUploadError:self._dataTransfers[transferId].direction===self.DATA_TRANSFER_TYPE.UPLOAD,sender:self._user.sid,name:self._dataTransfers[transferId].name},self._dataChannels[peerId][transferId]?transferId:"main"),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){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 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{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"===window.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);log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),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)}(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);log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),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)}(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.CANDIDATE_GENERATION_STATE={NEW:"new",GATHERING:"gathering",COMPLETED:"completed"},Skylink.prototype.CANDIDATE_PROCESSING_STATE={RECEIVED:"received",DROPPED:"dropped",BUFFERED:"buffered",PROCESSING:"processing",PROCESS_SUCCESS:"processSuccess",PROCESS_ERROR:"processError"},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._filterCandidatesType[candidateType]){if(!self._hasMCU||!self._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._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._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._addSDPMediaStreamTrackIDs(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."));self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)},Skylink.prototype.ICE_CONNECTION_STATE={STARTING:"starting",CHECKING:"checking",CONNECTED:"connected",COMPLETED:"completed",CLOSED:"closed",FAILED:"failed",TRICKLE_FAILED:"trickleFailed",DISCONNECTED:"disconnected"},Skylink.prototype.TURN_TRANSPORT={UDP:"udp",TCP:"tcp",ANY:"any",NONE:"none",ALL:"all"},Skylink.prototype._setIceServers=function(givenConfig){var self=this,givenIceServers=clone(givenConfig.iceServers),iceServersList={},newIceServers=[],useTURNSSLProtocol=!1,useTURNSSLPort=!1;self._forceTURNSSL&&("chrome"===window.webrtcDetectedBrowser||"safari"===window.webrtcDetectedBrowser||"IE"===window.webrtcDetectedBrowser?useTURNSSLProtocol=!0:useTURNSSLPort=!0),log.log("TURN server connections SSL configuration",{useTURNSSLProtocol:useTURNSSLProtocol,useTURNSSLPort:useTURNSSLPort});var i,pushIceServer=function(username,credential,url,index){iceServersList[username]||(iceServersList[username]={}),iceServersList[username][credential]||(iceServersList[username][credential]=[]),iceServersList[username][credential].indexOf(url)===-1&&("number"==typeof index?iceServersList[username][credential].splice(index,0,url):iceServersList[username][credential].push(url))};for(i=0;i0){var protocolParts=server.url.split(":"),urlParts=protocolParts[1].split("@");server.username=urlParts[0],server.url=protocolParts[0]+":"+urlParts[1],"edge"===window.webrtcDetectedBrowser?server.url+=":3478":protocolParts[2]&&(server.url+=":"+protocolParts[2])}var username="string"==typeof server.username?server.username:"none",credential="string"==typeof server.credential?server.credential:"none";if(0===server.url.indexOf("turn"))if(self._TURNTransport===self.TURN_TRANSPORT.ANY)pushIceServer(username,credential,server.url);else{var rawUrl=server.url;if(rawUrl.indexOf("?transport=")>0&&(rawUrl=rawUrl.split("?transport=")[0]),self._TURNTransport===self.TURN_TRANSPORT.NONE)pushIceServer(username,credential,rawUrl);else if(self._TURNTransport===self.TURN_TRANSPORT.UDP)pushIceServer(username,credential,rawUrl+"?transport=udp");else if(self._TURNTransport===self.TURN_TRANSPORT.TCP)pushIceServer(username,credential,rawUrl+"?transport=tcp");else{if(self._TURNTransport!==self.TURN_TRANSPORT.ALL){log.warn('Invalid TURN transport option "'+self._TURNTransport+'". Ignoring TURN server at index'+i,clone(server));continue}pushIceServer(username,credential,rawUrl+"?transport=tcp"),pushIceServer(username,credential,rawUrl+"?transport=udp")}}else pushIceServer(username,credential,server.url)}else log.warn("Ignoring ICE server provided at index "+i,clone(server))}self._enableSTUN&&self._usePublicSTUN&&"firefox"===window.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport=!1;"chrome"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>34&&(hasUrlsSupport=!0),"firefox"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>38&&(hasUrlsSupport=!0),"opera"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion>31&&(hasUrlsSupport=!0),"safari"!==window.webrtcDetectedBrowser&&"IE"!==window.webrtcDetectedBrowser||(hasUrlsSupport=!0),["bowser","edge"].indexOf(window.webrtcDetectedBrowser)>-1&&(hasUrlsSupport=!0);for(var serverUsername in iceServersList)if(iceServersList.hasOwnProperty(serverUsername))for(var serverCred in iceServersList[serverUsername])if(iceServersList[serverUsername].hasOwnProperty(serverCred))if(hasUrlsSupport){var urlsItem={urls:iceServersList[serverUsername][serverCred]};if("none"!==serverUsername&&(urlsItem.username=serverUsername),"none"!==serverCred&&(urlsItem.credential=serverCred),"edge"===window.webrtcDetectedBrowser){if(urlsItem.username&&urlsItem.credential){urlsItem.urls=[urlsItem.urls[0]],newIceServers.push(urlsItem);break}}else newIceServers.push(urlsItem)}else for(var j=0;j0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?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)}(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"===window.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){completedTaskCounter.indexOf(peerId)===-1&&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}))},i=0;i"],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())}(peerId):(listOfPeerErrors[peerId]=new Error("The peer connection object does not exists"),log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],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;if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieivng connection status"]),!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));var pc=self._peerConnections[peerId],result={raw:null,connection:{iceConnectionState:pc.iceConnectionState,iceGatheringState:pc.iceGatheringState,signalingState:pc.signalingState,remoteDescription:{type:pc.remoteDescription?pc.remoteDescription.type||null:null,sdp:pc.remoteDescription?pc.remoteDescription.sdp||null:null},localDescription:{type:pc.localDescription?pc.localDescription.type||null:null,sdp:pc.localDescription?pc.localDescription.sdp||null:null},candidates:clone(self._gatheredCandidates[peerId]||{sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}}),dataChannels:{},constraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,optional:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,sdpConstraints:self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null},audio:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),nacks:null,inputLevel:null,echoReturnLoss:null,echoReturnLossEnhancement:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null},receiving:{ssrc:null,bytes:0,packets:0,packetsLost:0,packetsDiscarded:0,fractionLost:0,nacks:null,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),outputLevel:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null}},video:{sending:{ssrc:null,bytes:0,packets:0,packetsLost:0,rtt:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesDropped:null,framesPerSecond:null,framesInput:null,frames:null,frameRateEncoded:null,frameRate:null,frameRateInput:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,qpSum:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null},receiving:{ssrc:null,bytes:0,packets:0,packetsDiscarded:0,packetsLost:0,fractionLost:0,jitter:0,jitterBufferMs:null,codec:self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),frameWidth:null,frameHeight:null,framesDecoded:null,framesCorrupted:null,framesPerSecond:null,framesDropped:null,framesOutput:null,frames:null,frameRateMean:null,frameRateStdDev:null,nacks:null,plis:null,firs:null,slis:null,e2eDelay:null,totalBytes:0,totalPackets:0,totalPacketsLost:0,totalNacks:null,totalPlis:null,totalFirs:null,totalSlis:null,totalFrames:null}},selectedCandidate:{local:{ipAddress:null,candidateType:null,portNumber:null,transport:null,turnMediaTransport:null},remote:{ipAddress:null,candidateType:null,portNumber:null,transport:null},consentResponses:{received:null,sent:null,totalReceived:null,totalSent:null},consentRequests:{received:null,sent:null,totalReceived:null,totalSent:null},responses:{received:null,sent:null,totalReceived:null,totalSent:null},requests:{received:null,sent:null,totalReceived:null,totalSent:null}},certificate:{local:self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),remote:self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs),dtlsCipher:null,srtpCipher:null}};if(self._dataChannels[peerId])for(var channelProp in self._dataChannels[peerId])self._dataChannels[peerId].hasOwnProperty(channelProp)&&self._dataChannels[peerId][channelProp]&&(result.connection.dataChannels[self._dataChannels[peerId][channelProp].channel.label]={label:self._dataChannels[peerId][channelProp].channel.label,readyState:self._dataChannels[peerId][channelProp].channel.readyState,channelType:"main"===channelProp?self.DATA_CHANNEL_TYPE.MESSAGING:self.DATA_CHANNEL_TYPE.DATA,currentTransferId:self._dataChannels[peerId][channelProp].transferId||null,currentStreamId:self._dataChannels[peerId][channelProp].streamId||null});var loopFn=function(obj,fn){for(var prop in obj)obj.hasOwnProperty(prop)&&obj[prop]&&fn(obj[prop],prop)},formatCandidateFn=function(candidateDirType,candidate){result.selectedCandidate[candidateDirType].ipAddress=candidate.ipAddress,result.selectedCandidate[candidateDirType].candidateType=candidate.candidateType,result.selectedCandidate[candidateDirType].portNumber="number"!=typeof candidate.portNumber?parseInt(candidate.portNumber,10)||null:candidate.portNumber,result.selectedCandidate[candidateDirType].transport=candidate.transport};pc.getStats(null,function(stats){if(beSilentOnLogs||log.debug([peerId,"RTCStatsReport",null,"Retrieval success ->"],stats),isAutoBwStats?!self._peerStats[peerId]:!self._peerBandwidth[peerId])return void callback(new Error("Peer connection stats object is not defined.",null));if(result.raw=stats,"firefox"===window.webrtcDetectedBrowser)loopFn(stats,function(obj,prop){var dirType="";0===prop.indexOf("inbound_rtp")||0===prop.indexOf("outbound_rtp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].ssrc=obj.ssrc,"video"===obj.mediaType&&(result.video[dirType].frameRateMean=obj.framerateMean||0,result.video[dirType].frameRateStdDev=obj.framerateStdDev||0,result.video[dirType].framesDropped="number"==typeof obj.framesDropped?obj.framesDropped:"number"==typeof obj.droppedFrames?obj.droppedFrames:null,result.video[dirType].framesCorrupted="number"==typeof obj.framesCorrupted?obj.framesCorrupted:null,result.video[dirType].framesPerSecond="number"==typeof obj.framesPerSecond?obj.framesPerSecond:null,"sending"===dirType?(result.video[dirType].framesEncoded="number"==typeof obj.framesEncoded?obj.framesEncoded:null,result.video[dirType].frames="number"==typeof obj.framesSent?obj.framesSent:null):(result.video[dirType].framesDecoded="number"==typeof obj.framesDecoded?obj.framesDecoded:null,result.video[dirType].frames="number"==typeof obj.framesReceived?obj.framesReceived:null)),"receiving"===dirType&&(obj.packetsDiscarded=("number"==typeof obj.packetsDiscarded?obj.packetsDiscarded:obj.discardedPackets)||0,obj.packetsLost="number"==typeof obj.packetsLost?obj.packetsLost:0,result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.totalPacketsDiscarded=obj.packetsDiscarded,result[obj.mediaType].receiving.totalPacketsLost=obj.packetsLost),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):0===prop.indexOf("inbound_rtcp")||0===prop.indexOf("outbound_rtcp")?(dirType=0===prop.indexOf("inbound_rtp")?"receiving":"sending",isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),"sending"===dirType?(result[obj.mediaType].sending.rtt=obj.mozRtt||0,result[obj.mediaType].sending.targetBitrate="number"==typeof obj.targetBitrate?obj.targetBitrate:0):result[obj.mediaType].receiving.jitter=obj.jitter||0,isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj)):obj.nominated&&obj.selected&&(formatCandidateFn("remote",stats[obj.remoteCandidateId]),formatCandidateFn("local",stats[obj.localCandidateId]))});else if("edge"===window.webrtcDetectedBrowser){var tracks=[];pc.getRemoteStreams().length>0&&(tracks=tracks.concat(pc.getRemoteStreams()[0].getTracks())),pc.getLocalStreams().length>0&&(tracks=tracks.concat(pc.getLocalStreams()[0].getTracks())),loopFn(tracks,function(track){loopFn(stats,function(obj,prop){if("track"===obj.type&&obj.trackIdentifier===track.id){var dirType=obj.remoteSource?"receiving":"sending",mediaType=track.kind;"audio"===mediaType?(result[mediaType][dirType]["sending"===dirType?"inputLevel":"outputLevel"]=obj.audioLevel,"sending"===dirType&&(result[mediaType][dirType].echoReturnLoss=obj.echoReturnLoss,result[mediaType][dirType].echoReturnLossEnhancement=obj.echoReturnLossEnhancement)):(result[mediaType][dirType].frames=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"sending"===dirType?obj.framesSent:obj.framesReceived),result[mediaType][dirType].framesDropped=obj.framesDropped,result[mediaType][dirType].framesDecoded=obj.framesDecoded,result[mediaType][dirType].framesCorrupted=obj.framesCorrupted,result[mediaType][dirType].framesPerSecond=obj.framesPerSecond,result[mediaType][dirType].frameHeight=obj.frameHeight||null,result[mediaType][dirType].frameWidth=obj.frameWidth||null,result[mediaType][dirType].totalFrames="sending"===dirType?obj.framesSent:obj.framesReceived),loopFn(stats,function(streamObj,subprop){streamObj.mediaTrackId===obj.id&&["outboundrtp","inboundrtp"].indexOf(streamObj.type)>-1&&(isAutoBwStats?self._peerBandwidth[peerId][subprop]||(self._peerBandwidth[peerId][subprop]=streamObj):self._peerStats[peerId][subprop]||(self._peerStats[peerId][subprop]=streamObj),result[mediaType][dirType].ssrc=parseInt(streamObj.ssrc||"0",10),result[mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"nackCount"),result[mediaType][dirType].totalNacks=streamObj.nackCount,"video"===mediaType&&(result[mediaType][dirType].firs=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"firCount"),result[mediaType][dirType].plis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"pliCount"),result[mediaType][dirType].slis=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"sliCount"),result[mediaType][dirType].totalFirs=streamObj.firCount,result[mediaType][dirType].totalPlis=streamObj.plisCount,result[mediaType][dirType].totalSlis=streamObj.sliCount),result[mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[mediaType][dirType].totalBytes="receiving"===dirType?streamObj.bytesReceived:streamObj.bytesSent,result[mediaType][dirType].totalPackets="receiving"===dirType?streamObj.packetsReceived:streamObj.packetsSent,"receiving"===dirType?(result[mediaType][dirType].jitter=streamObj.jitter||0,result[mediaType].receiving.fractionLost=streamObj.fractionLost,result[mediaType][dirType].packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsLost"),result[mediaType][dirType].packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][subprop]:self._peerStats[peerId][subprop],streamObj,"packetsDiscarded"),result[mediaType][dirType].totalPacketsLost=streamObj.packetsLost,result[mediaType][dirType].totalPacketsDiscarded=streamObj.packetsDiscarded||0):(result[mediaType].sending.rtt=streamObj.roundTripTime||0,result[mediaType].sending.targetBitrate=streamObj.targetBitrate||0),result[mediaType][dirType].codec&&streamObj.codecId&&(result[mediaType][dirType].codec.name=streamObj.codecId))})}})})}else{var reportedCandidate=!1,reportedCertificate=!1;loopFn(stats,function(obj,prop){if(0===prop.indexOf("ssrc_")){var dirType=prop.indexOf("_recv")>0?"receiving":"sending";obj.mediaType||(obj.mediaType=obj.hasOwnProperty("audioOutputLevel")||obj.hasOwnProperty("audioInputLevel")||obj.hasOwnProperty("googEchoCancellationReturnLoss")||obj.hasOwnProperty("googEchoCancellation")?"audio":"video"),isAutoBwStats?self._peerBandwidth[peerId][prop]||(self._peerBandwidth[peerId][prop]=obj):self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj);try{if("video"===obj.mediaType&&"receiving"===dirType){var captureStartNtpTimeMs=parseInt(obj.googCaptureStartNtpTimeMs||"0",10);if(captureStartNtpTimeMs>0&&pc.getRemoteStreams().length>0&&document&&"function"==typeof document.getElementsByTagName){var streamId=pc.getRemoteStreams()[0].id||pc.getRemoteStreams()[0].label,elements=[];self._isUsingPlugin?elements=document.getElementsByTagName("object"):(elements=document.getElementsByTagName("video"),0===elements.length&&(elements=document.getElementsByTagName("audio")));for(var e=0;e0))break;for(var ec=0;ec"],error)}if(result[obj.mediaType][dirType].ssrc=parseInt(obj.ssrc||"0",10),result[obj.mediaType][dirType].bytes=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"bytesReceived":"bytesSent"),result[obj.mediaType][dirType].packets=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"packetsReceived":"packetsSent"),result[obj.mediaType][dirType].nacks=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"receiving"===dirType?"googNacksReceived":"googNacksSent"),result[obj.mediaType][dirType].totalPackets=parseInt(("receiving"===dirType?obj.packetsReceived:obj.packetsSent)||"0",10),result[obj.mediaType][dirType].totalBytes=parseInt(("receiving"===dirType?obj.bytesReceived:obj.bytesSent)||"0",10),result[obj.mediaType][dirType].totalNacks=parseInt(("receiving"===dirType?obj.googNacksReceived:obj.googNacksSent)||"0",10),result[obj.mediaType][dirType].codec&&(obj.googCodecName&&"unknown"!==obj.googCodecName&&(result[obj.mediaType][dirType].codec.name=obj.googCodecName),obj.codecImplementationName&&"unknown"!==obj.codecImplementationName&&(result[obj.mediaType][dirType].codec.implementation=obj.codecImplementationName)),"sending"===dirType?(result[obj.mediaType].sending.rtt=parseFloat(obj.googRtt||"0",10),result[obj.mediaType].sending.targetBitrate=obj.targetBitrate?parseInt(obj.targetBitrate,10):null):(result[obj.mediaType].receiving.packetsLost=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsLost"),result[obj.mediaType].receiving.packetsDiscarded=self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"packetsDiscarded"),result[obj.mediaType].receiving.jitter=parseFloat(obj.googJitterReceived||"0",10),result[obj.mediaType].receiving.jitterBufferMs=obj.googJitterBufferMs?parseFloat(obj.googJitterBufferMs||"0",10):null,result[obj.mediaType].receiving.totalPacketsLost=parseInt(obj.packetsLost||"0",10),result[obj.mediaType].receiving.totalPacketsDiscarded=parseInt(obj.packetsDiscarded||"0",10)),"video"===obj.mediaType?(result.video[dirType].framesCorrupted=obj.framesCorrupted?parseInt(obj.framesCorrupted,10):null,result.video[dirType].framesPerSecond=obj.framesPerSecond?parseFloat(obj.framesPerSecond,10):null,result.video[dirType].framesDropped=obj.framesDropped?parseInt(obj.framesDropped,10):null,"sending"===dirType?(result.video[dirType].frameWidth=obj.googFrameWidthSent?parseInt(obj.googFrameWidthSent,10):null,result.video[dirType].frameHeight=obj.googFrameHeightSent?parseInt(obj.googFrameHeightSent,10):null,result.video[dirType].plis=obj.googPlisSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisSent"):null,result.video[dirType].firs=obj.googFirsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsSent"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisSent?parseInt(obj.googPlisSent,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsSent?parseInt(obj.googFirsSent,10):null,result.video[dirType].framesEncoded=obj.framesEncoded?parseInt(obj.framesEncoded,10):null,result.video[dirType].frameRateEncoded=obj.googFrameRateEncoded?parseInt(obj.googFrameRateEncoded,10):null,result.video[dirType].frameRateInput=obj.googFrameRateInput?parseInt(obj.googFrameRateInput,10):null,result.video[dirType].frameRate=obj.googFrameRateSent?parseInt(obj.googFrameRateSent,10):null,result.video[dirType].qpSum=obj.qpSum?parseInt(obj.qpSum,10):null,result.video[dirType].frames=obj.framesSent?self._parseConnectionStats(self._peerStats[peerId][prop],obj,"framesSent"):null,result.video[dirType].totalFrames=obj.framesSent?parseInt(obj.framesSent,10):null):(result.video[dirType].frameWidth=obj.googFrameWidthReceived?parseInt(obj.googFrameWidthReceived,10):null,result.video[dirType].frameHeight=obj.googFrameHeightReceived?parseInt(obj.googFrameHeightReceived,10):null,result.video[dirType].plis=obj.googPlisReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googPlisReceived"):null,result.video[dirType].firs=obj.googFirsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"googFirsReceived"):null,result[obj.mediaType][dirType].totalPlis=obj.googPlisReceived?parseInt(obj.googPlisReceived,10):null,result[obj.mediaType][dirType].totalFirs=obj.googFirsReceived?parseInt(obj.googFirsReceived,10):null,result.video[dirType].framesDecoded=obj.framesDecoded?parseInt(obj.framesDecoded,10):null,result.video[dirType].frameRateDecoded=obj.googFrameRateDecoded?parseInt(obj.googFrameRateDecoded,10):null,result.video[dirType].frameRateOutput=obj.googFrameRateOutput?parseInt(obj.googFrameRateOutput,10):null,result.video[dirType].frameRate=obj.googFrameRateReceived?parseInt(obj.googFrameRateReceived,10):null,result.video[dirType].frames=obj.framesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],obj,"framesReceived"):null,result.video[dirType].totalFrames=obj.framesReceived?parseInt(obj.framesReceived,10):null)):"receiving"===dirType?result.audio[dirType].outputLevel=parseFloat(obj.audioOutputLevel||"0",10):(result.audio[dirType].inputLevel=parseFloat(obj.audioInputLevel||"0",10),result.audio[dirType].echoReturnLoss=parseFloat(obj.googEchoCancellationReturnLoss||"0",10),result.audio[dirType].echoReturnLossEnhancement=parseFloat(obj.googEchoCancellationReturnLossEnhancement||"0",10)),isAutoBwStats?self._peerBandwidth[peerId][prop]=obj:self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=obj),reportedCandidate||loopFn(stats,function(canObj,canProp){reportedCandidate||0!==canProp.indexOf("Conn-")||obj.transportId===canObj.googChannelId&&(isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),formatCandidateFn("local",stats[canObj.localCandidateId]),formatCandidateFn("remote",stats[canObj.remoteCandidateId]),result.selectedCandidate.writable=canObj.googWritable?"true"===canObj.googWritable:null,result.selectedCandidate.readable=canObj.googReadable?"true"===canObj.googReadable:null,result.selectedCandidate.rtt=canObj.googRtt?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"googRtt"):null,result.selectedCandidate.totalRtt=canObj.googRtt?parseInt(canObj.googRtt,10):null,result.selectedCandidate.requests={received:canObj.requestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsReceived"):null,sent:canObj.requestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"requestsSent"):null,totalReceived:canObj.requestsReceived?parseInt(canObj.requestsReceived,10):null,totalSent:canObj.requestsSent?parseInt(canObj.requestsSent,10):null},result.selectedCandidate.responses={received:canObj.responsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesReceived"):null,sent:canObj.responsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"responsesSent"):null,totalReceived:canObj.responsesReceived?parseInt(canObj.responsesReceived,10):null,totalSent:canObj.responsesSent?parseInt(canObj.responsesSent,10):null},result.selectedCandidate.consentRequests={received:canObj.consentRequestsReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsReceived"):null,sent:canObj.consentRequestsSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentRequestsSent"):null,totalReceived:canObj.consentRequestsReceived?parseInt(canObj.consentRequestsReceived,10):null,totalSent:canObj.consentRequestsSent?parseInt(canObj.consentRequestsSent,10):null},result.selectedCandidate.consentResponses={received:canObj.consentResponsesReceived?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesReceived"):null,sent:canObj.consentResponsesSent?self._parseConnectionStats(isAutoBwStats?self._peerBandwidth[peerId][canProp]:self._peerStats[peerId][canProp],canObj,"consentResponsesSent"):null,totalReceived:canObj.consentResponsesReceived?parseInt(canObj.consentResponsesReceived,10):null,totalSent:canObj.consentResponsesSent?parseInt(canObj.consentResponsesSent,10):null},isAutoBwStats?self._peerBandwidth[peerId][canProp]||(self._peerBandwidth[peerId][canProp]=canObj):self._peerStats[peerId][canProp]||(self._peerStats[peerId][canProp]=canObj),reportedCandidate=!0)}),!reportedCertificate&&stats[obj.transportId]){result.certificate.srtpCipher=stats[obj.transportId].srtpCipher||null,result.certificate.dtlsCipher=stats[obj.transportId].dtlsCipher||null;var localCertId=stats[obj.transportId].localCertificateId,remoteCertId=stats[obj.transportId].remoteCertificateId;localCertId&&stats[localCertId]&&(result.certificate.local.derBase64=stats[localCertId].googDerBase64||null,stats[localCertId].googFingerprint&&(result.certificate.local.fingerprint=stats[localCertId].googFingerprint),stats[localCertId].googFingerprintAlgorithm&&(result.certificate.local.fingerprintAlgorithm=stats[localCertId].googFingerprintAlgorithm)),remoteCertId&&stats[remoteCertId]&&(result.certificate.remote.derBase64=stats[remoteCertId].googDerBase64||null,stats[remoteCertId].googFingerprint&&(result.certificate.remote.fingerprint=stats[remoteCertId].googFingerprint),stats[remoteCertId].googFingerprintAlgorithm&&(result.certificate.remote.fingerprintAlgorithm=stats[remoteCertId].googFingerprintAlgorithm)),reportedCertificate=!0}}})}0===(result.selectedCandidate.local.candidateType||"").indexOf("relay")?(result.selectedCandidate.local.turnMediaTransport="UDP",self._forceTURNSSL&&"firefox"!==window.webrtcDetectedBrowser?result.selectedCandidate.local.turnMediaTransport="TCP/TLS":(self._TURNTransport===self.TURN_TRANSPORT.TCP||self._forceTURNSSL)&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)&&self._room.connection.peerConfig.iceServers[0]&&self._room.connection.peerConfig.iceServers[0].urls[0]&&self._room.connection.peerConfig.iceServers[0].urls[0].indexOf("?transport=tcp")>0&&(result.selectedCandidate.local.turnMediaTransport="TCP")):result.selectedCandidate.local.turnMediaTransport=null,callback(null,result)},function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)})},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._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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},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),pc.setLocalDescription(new RTCSessionDescription(sessionDescription),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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null,packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey, -self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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++){_storedLogs[i][0],"undefined"!==console[_storedLogs[i][1]]&&_storedLogs[i][1],_storedLogs[i][2],_storedLogs[i][3]}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="SkylinkJS";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&&(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace)){void 0===console.trace&&logLevel[3];console.trace}},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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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};return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),void pc.setRemoteDescription(new RTCSessionDescription(offer),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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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};return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer):(pc.processingRemoteSDP=!0,void pc.setRemoteDescription(new RTCSessionDescription(answer),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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream), -isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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]||""),["audio","video"].indexOf(mediaType)===-1&&(self._sdpSessions[targetMid][direction].connection.data=!0);else if(mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){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]=["a=inactive","a=recvonly"].indexOf(sdpLines[i])===-1?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=["a=inactive","a=sendonly"].indexOf(sdpLines[i])===-1?"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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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 +type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:doIceRestart===!0&&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,doIceRestart===!0),"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(),"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._filterCandidatesType.host&&self._filterCandidatesType.srflx&&!self._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 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,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._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(event){if(self._peerConnections[targetMid]){var stream=event.stream||event,streamId=stream.id||stream.label;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);if(!self._hasMCU&&"firefox"===window.webrtcDetectedBrowser&&pc.getRemoteStreams().length>1&&pc.remoteDescription&&pc.remoteDescription.sdp&&pc.remoteDescription.sdp.indexOf(" msid:"+streamId+" ")===-1)return void log.warn([targetMid,"MediaStream",streamId,"Ignoring received empty remote stream ->"],stream);var peerSettings=clone(self.getPeerInfo(targetMid).settings),hasScreenshare=peerSettings.video&&"object"==typeof peerSettings.video&&!!peerSettings.video.screenshare;pc.hasStream=!0,pc.hasScreen=!!hasScreenshare,self._streamsSession[targetMid][streamId]=peerSettings,self._onRemoteStreamAdded(targetMid,stream,!!hasScreenshare)}},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"===window.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._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"!==window.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),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"===window.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"===window.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=peerInfo.settings.audio.stereo===!0),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._getSDPEdgeVideoSupports(peerId)||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!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]&&(peerInfo.settings.audio&&(this._sdpSessions[peerId].local&&this._sdpSessions[peerId].local.connection&&!((this._sdpSessions[peerId].local.connection.audio||"").indexOf("recv")>-1)||this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&!((this._sdpSessions[peerId].remote.connection.audio||"").indexOf("send")>-1))&&(peerInfo.settings.audio=!1),peerInfo.settings.video&&(this._sdpSessions[peerId].local&&this._sdpSessions[peerId].local.connection&&!((this._sdpSessions[peerId].local.connection.video||"").indexOf("recv")>-1)||this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&!((this._sdpSessions[peerId].remote.connection.video||"").indexOf("send")>-1))&&(peerInfo.settings.video=!1),peerInfo.settings.data&&(this._sdpSessions[peerId].local&&this._sdpSessions[peerId].local.connection&&!this._sdpSessions[peerId].local.connection.data||this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&!this._sdpSessions[peerId].remote.connection.data)&&(peerInfo.settings.data=!1))):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:window.webrtcDetectedBrowser,version:window.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._enableDataChannel,enableIceTrickle:this._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._enableDataChannel&&this._sdpSettings.connection.data,peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&("boolean"==typeof this._codecParams.audio.opus.stereo&&(peerInfo.settings.audio.stereo=this._codecParams.audio.opus.stereo),"boolean"==typeof this._codecParams.audio.opus.usedtx&&(peerInfo.settings.audio.usedtx=this._codecParams.audio.opus.usedtx),"number"==typeof this._codecParams.audio.opus.maxplaybackrate&&(peerInfo.settings.audio.maxplaybackrate=this._codecParams.audio.opus.maxplaybackrate),"boolean"==typeof this._codecParams.audio.opus.useinbandfec&&(peerInfo.settings.audio.useinbandfec=this._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;i0){stream=streams[j];break}listOfPeersStreams[listOfPeers[i]]={streamId:stream?stream.id||stream.label||null:null,stream:stream,isSelf:!1}}if(this._user&&this._user.sid){var selfStream=null;this._streams.screenshare&&this._streams.screenshare.stream?selfStream=this._streams.screenshare.stream:this._streams.userMedia&&this._streams.userMedia.stream&&(selfStream=this._streams.userMedia.stream),listOfPeersStreams[this._user.sid]={streamId:selfStream?selfStream.id||selfStream.label||null:null,stream:selfStream,isSelf:!0}}return listOfPeersStreams},Skylink.prototype.getPeersDatachannels=function(){for(var listOfPeersDatachannels={},listOfPeers=Object.keys(this._peerConnections),i=0;i'],pc.signalingState);var doIceRestart=!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),offerConstraints={offerToReceiveAudio:offerToReceiveAudio,offerToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection};peerBrowser.os=peerBrowser.os||"",["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={mandatory:{OfferToReceiveAudio:offerToReceiveAudio,OfferToReceiveVideo:offerToReceiveVideo,iceRestart:doIceRestart,voiceActivityDetection:self._voiceActivityDetection}}),self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._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),pc.createOffer(function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)},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);self._hasMCU&&"MCU"!==targetMid||"edge"===window.webrtcDetectedBrowser||self._addLocalMediaStreams(targetMid);var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPEdgeVideoSupports(targetMid),answerConstraints="edge"===window.webrtcDetectedBrowser?{offerToReceiveVideo:offerToReceiveVideo,offerToReceiveAudio:offerToReceiveAudio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints),pc.createAnswer(function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)},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),pc.setLocalDescription(new RTCSessionDescription(sessionDescription),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._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._addSDPMediaStreamTrackIDs(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},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)})},Skylink.prototype.GET_PEERS_STATE={ENQUIRED:"enquired",RECEIVED:"received"},Skylink.prototype.INTRODUCE_STATE={INTRODUCING:"introducing",ERROR:"error"},Skylink.prototype.getPeers=function(showAll,callback){var self=this;return self._isPrivileged?self._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.SYSTEM_ACTION={WARNING:"warning",REJECT:"reject"},Skylink.prototype.SYSTEM_ACTION_REASON={CREDENTIALS_EXPIRED:"oldTimeStamp",CREDENTIALS_ERROR:"credentialError",DUPLICATED_LOGIN:"duplicatedLogin",ROOM_NOT_STARTED:"notStart",EXPIRED:"expired",ROOM_LOCKED:"locked",FAST_MESSAGE:"fastmsg",ROOM_CLOSING:"toclose",ROOM_CLOSED:"roomclose",SERVER_ERROR:"serverError",KEY_ERROR:"keyFailed"},Skylink.prototype.joinRoom=function(room,options,callback){var self=this,selectedRoom=self._defaultRoom,previousRoom=self._selectedRoom,mediaOptions={};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:"string"==typeof error?new Error(error):error})},joinRoomFn=function(){self._initSelectedRoom(selectedRoom,function(initError,initSuccess){if(initError)return void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState);self._waitForOpenChannel(mediaOptions,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);self.once("peerJoined",function(peerId,peerInfo,isSelf){"function"==typeof callback&&(log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo}))},function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),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:self._isPrivileged===!0,autoIntroduce:self._autoIntroduce!==!1,key:self._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);if(self._inRoom){var stopStream=mediaOptions.audio===!1&&mediaOptions.video===!1;self.leaveRoom(stopStream,function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()})}else 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?stopMediaOptions===!1&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=stopMediaOptions.userMedia!==!1,stopScreenshare=stopMediaOptions.screenshare!==!1):"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]&&peersThatLeft.indexOf(connPeerId)===-1&&(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,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){self._condition("channelOpen",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))),mediaOptions.manualGetUserMedia===!0){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){mediaAccessRequiredFailure===!0?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)},function(){return self._channelOpen||self._openChannel(),self._channelOpen},function(state){return!0})},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.19",Skylink.prototype.READY_STATE_CHANGE={INIT:0,LOADING:1,COMPLETED:2,ERROR:-1},Skylink.prototype.READY_STATE_CHANGE_ERROR={API_INVALID:4001,API_DOMAIN_NOT_MATCH:4002,API_CORS_DOMAIN_NOT_MATCH:4003,API_CREDENTIALS_INVALID:4004,API_CREDENTIALS_NOT_MATCH:4005,API_INVALID_PARENT_KEY:4006,API_NO_MEETING_RECORD_FOUND:4010,API_OVER_SEAT_LIMIT:4020,API_RETRIEVAL_FAILED:4021,API_WRONG_ACCESS_DOMAIN:5005,XML_HTTP_REQUEST_ERROR:-1,NO_SOCKET_IO:1,NO_XMLHTTPREQUEST_SUPPORT:2,NO_WEBRTC_SUPPORT:3,NO_PATH:4,ADAPTER_NO_LOADED:7,PARSE_CODECS:8},Skylink.prototype.REGIONAL_SERVER={APAC1:"",US1:""},Skylink.prototype.PRIORITY_WEIGHT_SCHEME={ENFORCE_OFFERER:"enforceOfferer",ENFORCE_ANSWERER:"enforceAnswerer",AUTO:"auto"},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;if("function"==typeof options&&(callback=options,options=void 0),!options){var error="No API key provided";return log.error(error),void("function"==typeof callback&&callback(error,null))}var appKey,room,defaultRoom,startDateTime,duration,credentials,roomServer=self._roomServer,enableIceTrickle=!0,enableDataChannel=!0,enableSTUNServer=!0,enableTURNServer=!0,TURNTransport=self.TURN_TRANSPORT.ANY,audioFallback=!1,forceSSL=!1,socketTimeout=2e4,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!0,disableVideoFecCodecs=!1,disableComfortNoiseCodec=!1,disableREMB=!1,filterCandidatesType={host:!1,srflx:!1,relay:!1},throttleIntervals={shareScreen:1e4,refreshConnection:5e3,getUserMedia:0},throttleShouldThrowError=!1,mcuUseRenegoRestart=!1,iceServer=null,socketServer=null,codecParams={audio:{opus:{}},video:{h264:{},vp8:{},vp9:{}}},priorityWeightScheme=self.PRIORITY_WEIGHT_SCHEME.AUTO;if(log.log("Provided init options:",options),"string"==typeof options)appKey=options,defaultRoom=appKey,room=appKey;else{if(appKey=options.appKey||options.apiKey,roomServer="string"==typeof options.roomServer?options.roomServer:roomServer,roomServer=roomServer.lastIndexOf("/")===roomServer.length-1?roomServer.substring(0,roomServer.length-1):roomServer,defaultRoom="string"==typeof options.defaultRoom&&options.defaultRoom?options.defaultRoom:appKey,room=defaultRoom,enableIceTrickle="boolean"==typeof options.enableIceTrickle?options.enableIceTrickle:enableIceTrickle,enableDataChannel="boolean"==typeof options.enableDataChannel?options.enableDataChannel:enableDataChannel,enableSTUNServer="boolean"==typeof options.enableSTUNServer?options.enableSTUNServer:enableSTUNServer,enableTURNServer="boolean"==typeof options.enableTURNServer?options.enableTURNServer:enableTURNServer,forceSSL="boolean"==typeof options.forceSSL?options.forceSSL:forceSSL,socketTimeout="number"==typeof options.socketTimeout?options.socketTimeout:socketTimeout,socketTimeout=socketTimeout<5e3?5e3:socketTimeout,forceTURNSSL="boolean"==typeof options.forceTURNSSL?options.forceTURNSSL:forceTURNSSL,forceTURN="boolean"==typeof options.forceTURN?options.forceTURN:forceTURN,usePublicSTUN="boolean"==typeof options.usePublicSTUN?options.usePublicSTUN:usePublicSTUN,disableVideoFecCodecs="boolean"==typeof options.disableVideoFecCodecs?options.disableVideoFecCodecs:disableVideoFecCodecs,disableComfortNoiseCodec="boolean"==typeof options.disableComfortNoiseCodec?options.disableComfortNoiseCodec:disableComfortNoiseCodec,disableREMB="boolean"==typeof options.disableREMB?options.disableREMB:disableREMB,throttleShouldThrowError="boolean"==typeof options.throttleShouldThrowError?options.throttleShouldThrowError:throttleShouldThrowError,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,mcuUseRenegoRestart="boolean"==typeof options.mcuUseRenegoRestart?options.mcuUseRenegoRestart:mcuUseRenegoRestart,"object"==typeof options.filterCandidatesType&&options.filterCandidatesType&&(filterCandidatesType.host="boolean"==typeof options.filterCandidatesType.host?options.filterCandidatesType.host:filterCandidatesType.host,filterCandidatesType.srflx="boolean"==typeof options.filterCandidatesType.srflx?options.filterCandidatesType.srflx:filterCandidatesType.srflx,filterCandidatesType.relay="boolean"==typeof options.filterCandidatesType.relay?options.filterCandidatesType.relay:filterCandidatesType.relay),"object"==typeof options.throttleIntervals&&options.throttleIntervals&&(throttleIntervals.shareScreen="number"==typeof options.throttleIntervals.shareScreen?options.throttleIntervals.shareScreen:throttleIntervals.shareScreen,throttleIntervals.refreshConnection="number"==typeof options.throttleIntervals.refreshConnection?options.throttleIntervals.refreshConnection:throttleIntervals.refreshConnection,throttleIntervals.getUserMedia="number"==typeof options.throttleIntervals.getUserMedia?options.throttleIntervals.getUserMedia:throttleIntervals.getUserMedia),options.socketServer&&("string"==typeof options.socketServer?socketServer=options.socketServer:"object"==typeof options.socketServer&&options.socketServer.url&&"string"==typeof options.socketServer.url&&(socketServer={url:options.socketServer.url,ports:Array.isArray(options.socketServer.ports)&&options.socketServer.ports.length>0?options.socketServer.ports:[],protocol:options.socketServer.protocol&&"string"==typeof options.socketServer.protocol?options.socketServer.protocol:null})),options.iceServer&&(iceServer="string"==typeof options.iceServer?{urls:[options.iceServer]}:Array.isArray(options.iceServer)&&options.iceServer.length>0&&options.iceServer[0]&&"string"==typeof options.iceServer[0]?{urls:options.iceServer}:null),"string"==typeof options.TURNServerTransport)for(var ttType in self.TURN_TRANSPORT)if(self.TURN_TRANSPORT.hasOwnProperty(ttType)&&self.TURN_TRANSPORT[ttType]===options.TURNServerTransport){TURNTransport=options.TURNServerTransport;break}if(options.audioCodec&&("string"==typeof options.audioCodec&&options.audioCodec!==self.AUDIO_CODEC.AUTO||"object"==typeof options.audioCodec&&options.audioCodec.codec&&"string"==typeof options.audioCodec.codec&&options.audioCodec.codec!==self.AUDIO_CODEC.AUTO))for(var acType in self.AUDIO_CODEC)if(self.AUDIO_CODEC.hasOwnProperty(acType)){if("string"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec){audioCodec=options.audioCodec;break}if("object"==typeof options.audioCodec&&self.AUDIO_CODEC[acType]===options.audioCodec.codec){audioCodec={codec:options.audioCodec.codec,samplingRate:"number"==typeof options.audioCodec.samplingRate&&options.audioCodec.samplingRate>0?options.audioCodec.samplingRate:null,channels:"number"==typeof options.audioCodec.channels&&options.audioCodec.channels>0?options.audioCodec.channels:null};break}}if(options.videoCodec&&("string"==typeof options.videoCodec&&options.videoCodec!==self.VIDEO_CODEC.AUTO||"object"==typeof options.videoCodec&&options.videoCodec.codec&&"string"==typeof options.videoCodec.codec&&options.videoCodec.codec!==self.VIDEO_CODEC.AUTO))for(var vcType in self.VIDEO_CODEC)if(self.VIDEO_CODEC.hasOwnProperty(vcType)){if("string"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec){videoCodec=options.videoCodec;break}if("object"==typeof options.videoCodec&&self.VIDEO_CODEC[vcType]===options.videoCodec.codec){videoCodec={codec:options.videoCodec.codec,samplingRate:"number"==typeof options.videoCodec.samplingRate&&options.videoCodec.samplingRate>0?options.videoCodec.samplingRate:null};break}}if("string"==typeof options.priorityWeightScheme)for(var pwsType in self.PRIORITY_WEIGHT_SCHEME)if(self.PRIORITY_WEIGHT_SCHEME.hasOwnProperty(pwsType)&&self.PRIORITY_WEIGHT_SCHEME[pwsType]===options.priorityWeightScheme){priorityWeightScheme=options.priorityWeightScheme;break}options.codecParams&&"object"==typeof options.codecParams&&(options.codecParams.audio&&"object"==typeof options.codecParams.audio&&options.codecParams.audio.opus&&"object"==typeof options.codecParams.audio.opus&&(codecParams.audio.opus={stereo:"boolean"==typeof options.codecParams.audio.opus.stereo?options.codecParams.audio.opus.stereo:null,usedtx:"boolean"==typeof options.codecParams.audio.opus.usedtx?options.codecParams.audio.opus.usedtx:null,useinbandfec:"boolean"==typeof options.codecParams.audio.opus.useinbandfec?options.codecParams.audio.opus.useinbandfec:null,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,minptime:"number"==typeof options.codecParams.audio.opus.minptime&&options.codecParams.audio.opus.minptime>=3?options.codecParams.audio.opus.minptime:null}),options.codecParams.video&&"object"==typeof options.codecParams.video&&(options.codecParams.video.h264&&"object"==typeof options.codecParams.video.h264&&(codecParams.video.h264={profileLevelId:options.codecParams.video.h264.profileLevelId&&"string"==typeof options.codecParams.video.h264.profileLevelId?options.codecParams.video.h264.profileLevelId:null,levelAsymmetryAllowed:"boolean"==typeof options.codecParams.video.h264.levelAsymmetryAllowed?options.codecParams.video.h264.levelAsymmetryAllowed:null, +packetizationMode:"boolean"==typeof options.codecParams.video.h264.packetizationMode?options.codecParams.video.h264.packetizationMode:null}),options.codecParams.video.vp8&&"object"==typeof options.codecParams.video.vp8&&(codecParams.video.vp8={maxFs:"number"==typeof options.codecParams.video.vp8.maxFs?options.codecParams.video.vp8.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp8.maxFr?options.codecParams.video.vp8.maxFr:null}),options.codecParams.video.vp9&&"object"==typeof options.codecParams.video.vp9&&(codecParams.video.vp9={maxFs:"number"==typeof options.codecParams.video.vp9.maxFs?options.codecParams.video.vp9.maxFs:null,maxFr:"number"==typeof options.codecParams.video.vp9.maxFr?options.codecParams.video.vp9.maxFr:null}))),audioFallback=options.audioFallback||audioFallback,options.credentials&&"string"==typeof options.credentials.credentials&&"number"==typeof options.credentials.duration&&"string"==typeof options.credentials.startDateTime&&(startDateTime=options.credentials.startDateTime,duration=options.credentials.duration,credentials=options.credentials.credentials),forceTURN===!0&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===window.webrtcDetectedBrowser&&(forceTURNSSL=!1,TURNTransport=self.TURN_TRANSPORT.UDP,enableDataChannel=!1),self._appKey=appKey,self._roomServer=roomServer,self._defaultRoom=defaultRoom,self._selectedRoom=room,self._path=roomServer+"/api/"+appKey+"/"+room,credentials&&startDateTime&&duration&&(self._roomStart=startDateTime,self._roomDuration=duration,self._roomCredentials=credentials,self._path+=credentials?"/"+startDateTime+"/"+duration+"?&cred="+credentials:""),self._path+=(credentials?"&":"?")+"rand="+(new Date).toISOString(),self._enableIceTrickle=enableIceTrickle,self._enableDataChannel=enableDataChannel,self._enableSTUN=enableSTUNServer,self._enableTURN=enableTURNServer,self._TURNTransport=TURNTransport,self._audioFallback=audioFallback,self._forceSSL=forceSSL,self._socketTimeout=socketTimeout,self._forceTURNSSL=forceTURNSSL,self._selectedAudioCodec=audioCodec,self._selectedVideoCodec=videoCodec,self._forceTURN=forceTURN,self._usePublicSTUN=usePublicSTUN,self._disableVideoFecCodecs=disableVideoFecCodecs,self._disableComfortNoiseCodec=disableComfortNoiseCodec,self._filterCandidatesType=filterCandidatesType,self._throttlingTimeouts=throttleIntervals,self._throttlingShouldThrowError=throttleShouldThrowError,self._disableREMB=disableREMB,self._mcuUseRenegoRestart=mcuUseRenegoRestart,self._iceServer=iceServer,self._socketServer=socketServer,self._codecParams=codecParams,self._priorityWeightScheme=priorityWeightScheme,log.log("Init configuration:",{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme}),self._readyState=0,self._trigger("readyStateChange",self.READY_STATE_CHANGE.INIT,null,self._selectedRoom),"function"==typeof callback){var hasTriggered=!1,readyStateChangeFn=function(readyState,error){hasTriggered||(readyState===self.READY_STATE_CHANGE.COMPLETED?(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback(null,{serverUrl:self._path,readyState:self._readyState,appKey:self._appKey,roomServer:self._roomServer,defaultRoom:self._defaultRoom,selectedRoom:self._selectedRoom,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer,socketServer:self._socketServer,codecParams:self._codecParams,priorityWeightScheme:self._priorityWeightScheme})):readyState===self.READY_STATE_CHANGE.ERROR&&(log.log([null,"Socket",null,"Firing callback. Ready state change has met provided state ->"],readyState),log.debug([null,"Socket",null,"Ready state met failure"],error),hasTriggered=!0,self.off("readyStateChange",readyStateChangeFn),callback({error:new Error(error),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,useXDomainRequest="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest;self._socketUseXDR=useXDomainRequest;var xhr;url=self._forceSSL?"https:"+url:url,useXDomainRequest?(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest. XMLHttpRequest is now XDomainRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:window.webrtcDetectedBrowser,version:window.webrtcDetectedVersion}),xhr=new window.XMLHttpRequest,xhr.setContentType=function(contentType){xhr.setRequestHeader("Content-type",contentType)}),xhr.onload=function(){var response=xhr.responseText||xhr.response,status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters"],JSON.parse(response||"{}")),callback(status,JSON.parse(response||"{}"))},xhr.onerror=function(error){log.error([null,"XMLHttpRequest",method,"Failed retrieving information:"],{status:xhr.status}),self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"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),log.debug([null,"XMLHttpRequest",method,"Provided parameters:"],params)},xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()},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:":info.httpPortList,"https:":info.httpsPortList},this._readyState=2,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,adapter=function(){try{return window.AdapterJS||AdapterJS}catch(error){return!1}}();if(!adapter||"function"!=typeof adapter.webRTCReady){return void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used",errorCode:self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED},self._selectedRoom)}return window.io?window.XMLHttpRequest?self._path?void adapter.webRTCReady(function(){if(self._isUsingPlugin=!!adapter.WebRTCPlugin.plugin&&!!adapter.WebRTCPlugin.plugin.VERSION,!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&&self._isUsingPlugin?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:self._isUsingPlugin&&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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content: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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"No audio/video codecs available to start connection",errorCode:self.READY_STATE_CHANGE_ERROR.PARSE_CODECS},self._selectedRoom)):(self._readyState=1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.LOADING,null,self._selectedRoom),void self._requestServerInfo("GET",self._path,function(status,response){if(200!==status){var errorMessage="XMLHttpRequest status not OK\nStatus was: "+status;return self._readyState=0,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:status,content:response?response.info||errorMessage:errorMessage,errorCode:response.error||self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS},self._selectedRoom)}self._parseInfo(response)}))})}):(log.error("Skylink is not initialised. Please call init() first"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"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 void log.error("Invalid room provided. Room:",room);var defaultRoom=self._defaultRoom,initOptions={appKey:self._appKey,roomServer:self._roomServer,defaultRoom:room,enableDataChannel:self._enableDataChannel,enableIceTrickle:self._enableIceTrickle,enableTURNServer:self._enableTURN,enableSTUNServer:self._enableSTUN,TURNServerTransport:self._TURNTransport,audioFallback:self._audioFallback,forceSSL:self._forceSSL,socketTimeout:self._socketTimeout,forceTURNSSL:self._forceTURNSSL,audioCodec:self._selectedAudioCodec,videoCodec:self._selectedVideoCodec,forceTURN:self._forceTURN,usePublicSTUN:self._usePublicSTUN,disableVideoFecCodecs:self._disableVideoFecCodecs,disableComfortNoiseCodec:self._disableComfortNoiseCodec,disableREMB:self._disableREMB,filterCandidatesType:self._filterCandidatesType,throttleIntervals:self._throttlingTimeouts,throttleShouldThrowError:self._throttlingShouldThrowError,mcuUseRenegoRestart:self._mcuUseRenegoRestart,iceServer:self._iceServer?self._iceServer.urls:null,socketServer:self._socketServer?self._socketServer:null,codecParams:self._codecParams?self._codecParams:null,priorityWeightScheme:self._priorityWeightScheme?self._priorityWeightScheme:null};self._roomCredentials&&(initOptions.credentials={credentials:self._roomCredentials,duration:self._roomDuration,startDateTime:self._roomStart}),self.init(initOptions,function(error,success){self._defaultRoom=defaultRoom,error?callback(error,null):callback(null,success)})},Skylink.prototype.LOG_LEVEL={DEBUG:4,LOG:3,INFO:2,WARN:1,ERROR:0,NONE:-1};var _LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!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="SkylinkJS";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){void 0===logLevel&&(logLevel=Skylink.LOG_LEVEL.WARN);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){if("object"==typeof isDebugMode&&(Object.keys(isDebugMode).length>0?(_enableDebugTrace=!!isDebugMode.trace,_enableDebugStack=!!isDebugMode.storeLogs):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)),isDebugMode===!1)return _enableDebugMode=!1,_enableDebugTrace=!1,void(_enableDebugStack=!1);_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0};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<=1e3)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},1e3-((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.debug([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<16?sendGroupMessageFn(self._socketMessageQueue.splice(0,self._socketMessageQueue.length)):(sendGroupMessageFn(self._socketMessageQueue.splice(0,16)),setQueueFn()))};if(self._groupMessageList.indexOf(message.type)>-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=1e3)log.warn([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.warn([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.debug([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){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._socketTimeout,reconnectionAttempts:2,reconnectionDelayMax:5e3,reconnectionDelay:1e3,transports:["websocket"]},ports=self._socketServer&&"object"==typeof self._socketServer&&Array.isArray(self._socketServer.ports)&&self._socketServer.ports.length>0?self._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._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,retries=0;self._socketServer&&(url="string"==typeof self._socketServer?self._socketServer:(self._socketServer.protocol?self._socketServer.protocol:self._signalingServerProtocol)+"//"+self._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));try{self._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))}self._socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),self._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):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))}),self._socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),self._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))}),self._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())))}),self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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),self._inRoom=!0,self._user.sid=message.sid,self._peerPriorityWeight=message.tieBreaker+(self._priorityWeightScheme===self.PRIORITY_WEIGHT_SCHEME.AUTO?0:self._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:window.webrtcDetectedBrowser,version:(window.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._enableIceTrickle,enableDataChannel:self._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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:window.webrtcDetectedBrowser,version:(window.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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId case ->'],message);if(self._hasMCU&&!self._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,message.doIceRestart===!0,{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:window.webrtcDetectedBrowser,version:(window.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:message.doIceRestart===!0,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,message.doIceRestart===!0)},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:message.receiveOnly===!0,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)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId 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._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:window.webrtcDetectedBrowser,version:(window.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};return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE?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}):pc.processingRemoteSDP?void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer):(pc.processingRemoteSDP=!0,"edge"!==window.webrtcDetectedBrowser||self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),void pc.setRemoteDescription(new RTCSessionDescription(offer),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)},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})}))},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._filterCandidatesType[candidateType]){if(!this._hasMCU||!this._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};return 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"),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER?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}):pc.processingRemoteSDP?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),void pc.setRemoteDescription(new RTCSessionDescription(answer),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]&&(pc.remoteDescription.sdp.indexOf("m=application")===-1||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},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})}))},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);else{log.error("Unable to send stream as user is not in the Room.",stream),"function"==typeof callback&&callback(new Error("Unable to send stream as user is not in the Room."),null)}};if("object"!=typeof options||null===options){return log.error("Provided stream settings is invalid",options),void("function"==typeof callback&&callback(new Error("Provided stream settings is invalid"),null))}if(!self._inRoom){var notInRoomError="Unable to send stream as user is not in the Room.";return log.error(notInRoomError,options),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}if("edge"===window.webrtcDetectedBrowser){return log.error("Edge browser currently does not support renegotiation.",options),void("function"==typeof callback&&callback(new Error("Edge browser currently does not support renegotiation."),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0||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});try{enableAudio&&"firefox"===window.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio={echoCancellation:enableAudioSettings.echoCancellation}),navigator.getUserMedia(settings.getUserMediaSettings,function(stream){if("firefox"===window.webrtcDetectedBrowser||!enableAudio)return void self._onStreamAccessSuccess(stream,settings,!0,!1);navigator.getUserMedia({audio:{echoCancellation:enableAudioSettings.echoCancellation}},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)}},function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)})},function(error){self._onStreamAccessError(error,settings,!0,!1)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._throttlingShouldThrowError){var throttleLimitError="Unable to run as throttle interval has not reached ("+self._throttlingTimeouts.shareScreen+"ms).";log.error(throttleLimitError),"function"==typeof callback&&callback(new Error(throttleLimitError),null)}},"shareScreen",self._throttlingTimeouts.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._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"!==window.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"!==window.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,options.useExactConstraints?settings.getUserMediaSettings.audio.deviceId={exact:options.audio.deviceId}:(Array.isArray(settings.getUserMediaSettings.audio.optional)||(settings.getUserMediaSettings.audio.optional=[]),settings.getUserMediaSettings.audio.optional.push({sourceId:options.audio.deviceId}))))),"edge"===window.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"!==window.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,options.useExactConstraints?settings.getUserMediaSettings.video.deviceId={exact:options.video.deviceId}:(Array.isArray(settings.getUserMediaSettings.video.optional)||(settings.getUserMediaSettings.video.optional=[]),settings.getUserMediaSettings.video.optional.push({sourceId: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&&!self._isUsingPlugin)&&(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&&self._isUsingPlugin&&(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})):options.useExactConstraints?settings.getUserMediaSettings.video={width:{exact:settings.settings.video.resolution.width},height:{exact:settings.settings.video.resolution.height}}:settings.getUserMediaSettings.video.mandatory={maxWidth:settings.settings.video.resolution.width,maxHeight:settings.settings.video.resolution.height},"edge"===window.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;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"]),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(window.webrtcDetectedBrowser)>-1?stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])}:"firefox"===window.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._audioFallback)return log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0),void navigator.getUserMedia({audio:!0},function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},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)});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;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",stream.id,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",stream.id,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",stream.id,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,stream.id||stream.label),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],offerToReceiveAudio=(((self._peerInformations[peerId]||{}).agent||{}).name,((self._peerInformations[peerId]||{}).agent||{}).version,!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)),offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPEdgeVideoSupports(peerId);if(pc)if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){for(var hasStream=!1,streams=pc.getLocalStreams(),i=0;i-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){var shouldTrigger=!!self._streamsSession[peerId][streamId];if(!checkStreamId&&self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED)for(var streams=self._peerConnections[peerId].getRemoteStreams(),i=0;i0){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?cLineIndex===-1?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:"+1024*bw:"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._selectedAudioCodec),parseFn("video",overrideSettings?overrideSettings.video:self._selectedVideoCodec),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._addSDPMediaStreamTrackIDs=function(targetMid,sessionDescription){if(!(this._peerConnections[targetMid]&&this._peerConnections[targetMid].getLocalStreams().length>0))return log.log([targetMid,"RTCSessionDesription",sessionDescription.type,"Not enforcing MediaStream IDs as no Streams is sent."]),sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;this._enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),localStream=(((this._peerInformations[targetMid]||{}).agent||{}).name,this._peerConnections[targetMid].getLocalStreams()[0]),localStreamId=localStream.id||localStream.label,parseFn=function(type,tracks){if(0===tracks.length)return void log.log([targetMid,"RTCSessionDesription",sessionDescription.type,'Not enforcing "'+type+'" MediaStreamTrack IDs as no Stream "'+type+'" tracks is sent.']);for(var trackId=tracks[0].id||tracks[0].label,trackLabel=tracks[0].label||"Default",ssrcId=null,hasReachedType=!1,i=0;i0?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Updating MediaStreamTrack ssrc ("+ssrcId+') for "'+localStreamId+'" stream and "'+trackId+'" (label:"'+trackLabel+'")']),sdpLines.splice(i+1,0,"a=ssrc:"+ssrcId+" msid:"+localStreamId+" "+trackId,"a=ssrc:"+ssrcId+" mslabel:"+trackId,"a=ssrc:"+ssrcId+" label:"+trackId),i+=3):(sdpLines.splice(i,1),i--));break}}else{if(hasReachedType)break;hasReachedType=!0}};if(parseFn("audio",localStream.getAudioTracks()),parseFn("video",localStream.getVideoTracks()),!this._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var i=0;i"],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)),sdpLines.join("\r\n")},Skylink.prototype._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var codecsPayload=[],sdpLines=sessionDescription.sdp.split("\r\n"),hasVideo=!1,rtxs={},parts=[],i=0;i0))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._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._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._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){if(!sessionDescription||!sessionDescription.sdp)return null;for(var sdpLines=sessionDescription.sdp.split("\r\n"),selectedCodecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null},i=0;i'],selectedCodecInfo),selectedCodecInfo},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._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._filterCandidatesType.host&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "host" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*host.*\r\n/g,"")),this._filterCandidatesType.srflx&&(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Removing "srflx" ICE candidates.']),sessionDescription.sdp=sessionDescription.sdp.replace(/a=candidate:.*srflx.*\r\n/g,"")),this._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);self._currentCodecSupport={audio:{},video:{}};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={offerToReceiveAudio:!0,offerToReceiveVideo:!0};["IE","safari"].indexOf(window.webrtcDetectedBrowser)>-1&&(offerConstraints={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){for(var sdpLines=offer.sdp.split("\r\n"),mediaType="",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]||""),["audio","video"].indexOf(mediaType)===-1&&(self._sdpSessions[targetMid][direction].connection.data=!0);else if(mediaType&&["audio","video"].indexOf(mediaType)>-1&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){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]=["a=inactive","a=recvonly"].indexOf(sdpLines[i])===-1?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=["a=inactive","a=sendonly"].indexOf(sdpLines[i])===-1?"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._getSDPEdgeVideoSupports=function(peerId){var self=this;if(peerId){var peerAgent=((self._peerInformations[peerId]||{}).agent||{}).name||"",peerVersion=((self._peerInformations[peerId]||{}).agent||{}).version||0;return"edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019&&"edge"!==peerAgent?!!self._currentCodecSupport.video.h264:!("edge"!==window.webrtcDetectedBrowser&&"edge"===peerAgent&&peerVersion<15.15019)||!!self._currentCodecSupport.video.h264}return!("edge"===window.webrtcDetectedBrowser&&window.webrtcDetectedVersion<15.15019)||!!self._currentCodecSupport.video.h264},"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/source/peer-data.js b/source/peer-data.js index ff449bec3..15244f7f0 100644 --- a/source/peer-data.js +++ b/source/peer-data.js @@ -208,6 +208,29 @@ Skylink.prototype.getPeerInfo = function(peerId) { peerInfo.connected = this._peerConnStatus[peerId] && !!this._peerConnStatus[peerId].connected; peerInfo.init = this._peerConnStatus[peerId] && !!this._peerConnStatus[peerId].init; + if (this._sdpSessions[peerId]) { + // Set audio to false if SDP m= line and direction is not available + if (peerInfo.settings.audio && !((this._sdpSessions[peerId].local && this._sdpSessions[peerId].local.connection ? + (this._sdpSessions[peerId].local.connection.audio || '').indexOf('recv') > -1 : true) && + (this._sdpSessions[peerId].remote && this._sdpSessions[peerId].remote.connection ? + (this._sdpSessions[peerId].remote.connection.audio || '').indexOf('send') > -1 : true))) { + peerInfo.settings.audio = false; + } + // Set video to false if SDP m= line and direction is not available + if (peerInfo.settings.video && !((this._sdpSessions[peerId].local && this._sdpSessions[peerId].local.connection ? + (this._sdpSessions[peerId].local.connection.video || '').indexOf('recv') > -1 : true) && + (this._sdpSessions[peerId].remote && this._sdpSessions[peerId].remote.connection ? + (this._sdpSessions[peerId].remote.connection.video || '').indexOf('send') > -1 : true))) { + peerInfo.settings.video = false; + } + // Set data to false if SDP m= line and direction is not available + if (peerInfo.settings.data && !((this._sdpSessions[peerId].local && this._sdpSessions[peerId].local.connection ? + this._sdpSessions[peerId].local.connection.data : true) && (this._sdpSessions[peerId].remote && + this._sdpSessions[peerId].remote.connection ? this._sdpSessions[peerId].remote.connection.data : true))) { + peerInfo.settings.data = false; + } + } + } else { peerInfo = { userData: clone(this._userData), diff --git a/source/socket-message.js b/source/socket-message.js index bff71737a..7d86488be 100644 --- a/source/socket-message.js +++ b/source/socket-message.js @@ -1566,6 +1566,10 @@ Skylink.prototype._offerHandler = function(message) { self._addLocalMediaStreams(targetMid); } + if (message.userInfo) { + self._trigger('peerUpdated', targetMid, self.getPeerInfo(targetMid), false); + } + pc.setRemoteDescription(new RTCSessionDescription(offer), function() { log.debug([targetMid, 'RTCSessionDescription', message.type, 'Remote description set']); pc.setOffer = 'remote'; @@ -1766,6 +1770,10 @@ Skylink.prototype._answerHandler = function(message) { pc.processingRemoteSDP = true; + if (message.userInfo) { + self._trigger('peerUpdated', targetMid, self.getPeerInfo(targetMid), false); + } + pc.setRemoteDescription(new RTCSessionDescription(answer), function() { log.debug([targetMid, null, message.type, 'Remote description set']); pc.setAnswer = 'remote'; From 4c3404c87b3d6bbc1eaf34ba29dd418ea83b262f Mon Sep 17 00:00:00 2001 From: Leticia Choo Date: Tue, 18 Apr 2017 19:05:27 +0800 Subject: [PATCH 10/11] Release 0.6.20. --- README.md | 2 +- bower.json | 2 +- doc/classes/Skylink.html | 105 +++++++++++++++++------ doc/data.json | 59 +++++++------ doc/files/source_data-channel.js.html | 4 +- doc/files/source_data-process.js.html | 4 +- doc/files/source_data-transfer.js.html | 4 +- doc/files/source_ice-candidate.js.html | 4 +- doc/files/source_ice-connection.js.html | 4 +- doc/files/source_peer-connection.js.html | 16 ++-- doc/files/source_peer-data.js.html | 50 ++++++----- doc/files/source_peer-handshake.js.html | 61 ++++++------- doc/files/source_peer-privileged.js.html | 4 +- doc/files/source_room-connection.js.html | 4 +- doc/files/source_room-init.js.html | 9 +- doc/files/source_skylink-events.js.html | 4 +- doc/files/source_socket-channel.js.html | 4 +- doc/files/source_socket-message.js.html | 24 ++++-- doc/files/source_stream-media.js.html | 10 +-- doc/files/source_stream-sdp.js.html | 95 +++++++++++++++----- doc/index.html | 6 +- package.json | 2 +- publish/skylink.complete.js | 6 +- publish/skylink.complete.min.js | 4 +- publish/skylink.debug.js | 4 +- publish/skylink.min.js | 4 +- 26 files changed, 306 insertions(+), 189 deletions(-) diff --git a/README.md b/README.md index e6c587182..a4c8860b4 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ You can raise tickets on [our support portal](http://support.temasys.io) or on [ ##### Current versions and stability We recommend that you always use the latest versions of the Temasys Web SDK as WebRTC is still evolving and we adapt to changes very frequently. -[Latest version: `0.6.19`](https://github.com/Temasys/SkylinkJS/releases/tag/0.6.19). +[Latest version: `0.6.20`](https://github.com/Temasys/SkylinkJS/releases/tag/0.6.20). #### Noted Issues and Solutions ##### Installing `0.6.3` - `0.6.10` versions in NPM diff --git a/bower.json b/bower.json index 7980dd542..cd153e96d 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "skylinkjs", "description": "WebRTC real-time video conversation library", - "version": "0.6.19", + "version": "0.6.20", "homepage": "https://skylink.io", "author": { "name": "Temasys Communications Pte. Ltd.", diff --git a/doc/classes/Skylink.html b/doc/classes/Skylink.html index 8527a7cff..6425757e2 100644 --- a/doc/classes/Skylink.html +++ b/doc/classes/Skylink.html @@ -2,7 +2,7 @@ - SkylinkJS 0.6.19 + SkylinkJS 0.6.20 @@ -33,7 +33,7 @@ - Version: 0.6.19 + Version: 0.6.20 -   Defined in: source/peer-connection.js:1502 +   Defined in: source/peer-connection.js:1506 @@ -2359,7 +2364,7 @@

_answerHandler

-   Defined in: source/socket-message.js:1685 +   Defined in: source/socket-message.js:1689 @@ -2716,7 +2721,7 @@

_candidateHandler

-   Defined in: source/socket-message.js:1590 +   Defined in: source/socket-message.js:1594 @@ -3124,7 +3129,7 @@

_createPeerConnection

-   Defined in: source/peer-connection.js:1796 +   Defined in: source/peer-connection.js:1800 @@ -3274,7 +3279,7 @@

_doAnswer

-   Defined in: source/peer-handshake.js:130 +   Defined in: source/peer-handshake.js:126 @@ -3611,6 +3616,56 @@

Returns:

+
+
+

_getSDPEdgeVideoSupports

+ () + +
+
+ + + + private + + + + + + + + + +
+ +
+ +
+ + +   Defined in: source/stream-sdp.js:1133 + + + +      Available since 0.6.18 + + +
+ +
+

Function that gets edge browser video supports.

+ +
+ + + +
+

Events Sequence:

+ There is no event sequence for this method. +
+ + +

_getSDPFingerprint

@@ -3638,7 +3693,7 @@

_getSDPFingerprint

-   Defined in: source/stream-sdp.js:1067 +   Defined in: source/stream-sdp.js:1095 @@ -3889,7 +3944,7 @@

_getUserInfo

-   Defined in: source/peer-data.js:650 +   Defined in: source/peer-data.js:662 @@ -3989,7 +4044,7 @@

_handleEndedStreams

-   Defined in: source/stream-media.js:2058 +   Defined in: source/stream-media.js:2056 @@ -4039,7 +4094,7 @@

_handleSDPConnectionSettings

-   Defined in: source/stream-sdp.js:887 +   Defined in: source/stream-sdp.js:888 @@ -4090,7 +4145,7 @@

_initSelectedRoom

-   Defined in: source/room-init.js:1335 +   Defined in: source/room-init.js:1330 @@ -4244,7 +4299,7 @@

_isLowerThanVersion

-   Defined in: source/socket-message.js:1799 +   Defined in: source/socket-message.js:1807 @@ -4902,7 +4957,7 @@

_parseConnectionStats

-   Defined in: source/peer-connection.js:2200 +   Defined in: source/peer-connection.js:2204 @@ -5583,7 +5638,7 @@

_removePeer

-   Defined in: source/peer-connection.js:1692 +   Defined in: source/peer-connection.js:1696 @@ -5987,7 +6042,7 @@

_restartMCUConnection

-   Defined in: source/peer-connection.js:2052 +   Defined in: source/peer-connection.js:2056 @@ -6040,7 +6095,7 @@

_restartPeerConnection

-   Defined in: source/peer-connection.js:1541 +   Defined in: source/peer-connection.js:1545 @@ -6345,7 +6400,7 @@

_setLocalAndSendMessage

-   Defined in: source/peer-handshake.js:191 +   Defined in: source/peer-handshake.js:183 @@ -6548,7 +6603,7 @@

_signalingEndOfCandidates

-   Defined in: source/peer-connection.js:2220 +   Defined in: source/peer-connection.js:2224 @@ -8115,7 +8170,7 @@

getCurrentDataStreamsSession

-   Defined in: source/peer-data.js:484 +   Defined in: source/peer-data.js:503 @@ -8188,7 +8243,7 @@

getCurrentDataTransfers

-   Defined in: source/peer-data.js:446 +   Defined in: source/peer-data.js:465 @@ -8261,7 +8316,7 @@

getPeerCustomSettings

-   Defined in: source/peer-data.js:528 +   Defined in: source/peer-data.js:547 @@ -8607,7 +8662,7 @@

getPeersDatachannels

-   Defined in: source/peer-data.js:390 +   Defined in: source/peer-data.js:409 @@ -8690,7 +8745,7 @@

getPeersInRoom

-   Defined in: source/peer-data.js:296 +   Defined in: source/peer-data.js:315 @@ -8759,7 +8814,7 @@

getPeersStream

-   Defined in: source/peer-data.js:327 +   Defined in: source/peer-data.js:346 diff --git a/doc/data.json b/doc/data.json index 9e13b1849..ac86dea45 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.19", + "version": "0.6.20", "url": "https://temasys.io/" }, "files": { @@ -3201,7 +3201,7 @@ }, { "file": "source/peer-connection.js", - "line": 1502, + "line": 1506, "description": "Function that starts the Peer connection session.\nRemember to remove previous method of reconnection (re-creating the Peer connection - destroy and create connection).", "itemtype": "method", "name": "_addPeer", @@ -3212,7 +3212,7 @@ }, { "file": "source/peer-connection.js", - "line": 1541, + "line": 1545, "description": "Function that re-negotiates a Peer connection.\nRemember to remove previous method of reconnection (re-creating the Peer connection - destroy and create connection).", "itemtype": "method", "name": "_restartPeerConnection", @@ -3223,7 +3223,7 @@ }, { "file": "source/peer-connection.js", - "line": 1692, + "line": 1696, "description": "Function that ends the Peer connection session.", "itemtype": "method", "name": "_removePeer", @@ -3234,7 +3234,7 @@ }, { "file": "source/peer-connection.js", - "line": 1796, + "line": 1800, "description": "Function that creates the Peer connection.", "itemtype": "method", "name": "_createPeerConnection", @@ -3245,7 +3245,7 @@ }, { "file": "source/peer-connection.js", - "line": 2052, + "line": 2056, "description": "Function that handles the _restartPeerConnection scenario\n for MCU enabled Peer connections.\nThis is implemented currently by making the user leave and join the Room again.\nThe Peer ID will not stay the same though.", "itemtype": "method", "name": "_restartMCUConnection", @@ -3256,7 +3256,7 @@ }, { "file": "source/peer-connection.js", - "line": 2200, + "line": 2204, "description": "Function that handles the stats tabulation.", "itemtype": "method", "name": "_parseConnectionStats", @@ -3267,7 +3267,7 @@ }, { "file": "source/peer-connection.js", - "line": 2220, + "line": 2224, "description": "Function that signals the end-of-candidates flag.", "itemtype": "method", "name": "_signalingEndOfCandidates", @@ -3346,7 +3346,7 @@ }, { "file": "source/peer-data.js", - "line": 296, + "line": 315, "description": "Function that gets the list of connected Peers in the Room.", "itemtype": "method", "name": "getPeersInRoom", @@ -3362,7 +3362,7 @@ }, { "file": "source/peer-data.js", - "line": 327, + "line": 346, "description": "Function that gets the list of connected Peers Streams in the Room.", "itemtype": "method", "name": "getPeersStream", @@ -3378,7 +3378,7 @@ }, { "file": "source/peer-data.js", - "line": 390, + "line": 409, "description": "Function that gets the current list of connected Peers Datachannel connections in the Room.", "itemtype": "method", "name": "getPeersDatachannels", @@ -3394,7 +3394,7 @@ }, { "file": "source/peer-data.js", - "line": 446, + "line": 465, "description": "Function that gets the list of current data transfers.", "itemtype": "method", "name": "getCurrentDataTransfers", @@ -3410,7 +3410,7 @@ }, { "file": "source/peer-data.js", - "line": 484, + "line": 503, "description": "Function that gets the list of current data streaming sessions.", "itemtype": "method", "name": "getCurrentDataStreamsSession", @@ -3426,7 +3426,7 @@ }, { "file": "source/peer-data.js", - "line": 528, + "line": 547, "description": "Function that gets the list of current custom Peer settings sent and set.", "itemtype": "method", "name": "getPeerCustomSettings", @@ -3442,7 +3442,7 @@ }, { "file": "source/peer-data.js", - "line": 650, + "line": 662, "description": "Function that returns the User session information to be sent to Peers.", "itemtype": "method", "name": "_getUserInfo", @@ -3502,7 +3502,7 @@ }, { "file": "source/peer-handshake.js", - "line": 130, + "line": 126, "description": "Function that creates the Peer connection answer session description.\nThis comes after receiving and setting the offer session description.", "itemtype": "method", "name": "_doAnswer", @@ -3513,7 +3513,7 @@ }, { "file": "source/peer-handshake.js", - "line": 191, + "line": 183, "description": "Function that sets the local session description and sends to Peer.\nIf trickle ICE is disabled, the local session description will be sent after\n ICE gathering has been completed.", "itemtype": "method", "name": "_setLocalAndSendMessage", @@ -4972,7 +4972,7 @@ }, { "file": "source/room-init.js", - "line": 1335, + "line": 1330, "description": "Starts initialising for Room credentials for room name provided in joinRoom() method.", "itemtype": "method", "name": "_initSelectedRoom", @@ -9039,7 +9039,7 @@ }, { "file": "source/socket-message.js", - "line": 1590, + "line": 1594, "description": "Function that handles the \"candidate\" socket message received.\nSee confluence docs for the \"candidate\" expected properties to be received\n based on the current SM_PROTOCOL_VERSION.", "itemtype": "method", "name": "_candidateHandler", @@ -9050,7 +9050,7 @@ }, { "file": "source/socket-message.js", - "line": 1685, + "line": 1689, "description": "Function that handles the \"answer\" socket message received.\nSee confluence docs for the \"answer\" expected properties to be received\n based on the current SM_PROTOCOL_VERSION.", "itemtype": "method", "name": "_answerHandler", @@ -9061,7 +9061,7 @@ }, { "file": "source/socket-message.js", - "line": 1799, + "line": 1807, "description": "Function that compares the SM / DT protocol versions to see if it in the version.", "itemtype": "method", "name": "_isLowerThanVersion", @@ -9800,7 +9800,7 @@ }, { "file": "source/stream-media.js", - "line": 2058, + "line": 2056, "description": "Function that handles ended streams.", "itemtype": "method", "name": "_handleEndedStreams", @@ -9932,7 +9932,7 @@ }, { "file": "source/stream-sdp.js", - "line": 887, + "line": 888, "description": "Function that modifies the session description to handle the connection settings.\nThis is experimental and never recommended to end-users.", "itemtype": "method", "name": "_handleSDPConnectionSettings", @@ -9943,7 +9943,7 @@ }, { "file": "source/stream-sdp.js", - "line": 1067, + "line": 1095, "description": "Function that parses and retrieves the session description fingerprint.", "itemtype": "method", "name": "_getSDPFingerprint", @@ -9951,6 +9951,17 @@ "tagname": "", "since": "0.6.18", "class": "Skylink" + }, + { + "file": "source/stream-sdp.js", + "line": 1133, + "description": "Function that gets edge browser video supports.", + "itemtype": "method", + "name": "_getSDPEdgeVideoSupports", + "access": "private", + "tagname": "", + "since": "0.6.18", + "class": "Skylink" } ], "warnings": [ diff --git a/doc/files/source_data-channel.js.html b/doc/files/source_data-channel.js.html index 53b271421..5443a3e98 100644 --- a/doc/files/source_data-channel.js.html +++ b/doc/files/source_data-channel.js.html @@ -2,7 +2,7 @@ - SkylinkJS 0.6.19 + SkylinkJS 0.6.20 @@ -33,7 +33,7 @@ - Version: 0.6.19 + Version: 0.6.20 diff --git a/doc/index.html b/doc/index.html index bff7f301d..2cc5c1303 100644 --- a/doc/index.html +++ b/doc/index.html @@ -2,7 +2,7 @@ - SkylinkJS 0.6.19 + SkylinkJS 0.6.20 @@ -33,7 +33,7 @@ - Version: 0.6.19 + Version: 0.6.20