diff --git a/README.md b/README.md
index cbbc63dc1..59e3b910a 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,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.25`](https://github.com/Temasys/SkylinkJS/releases/tag/0.6.25).
+[Latest version: `0.6.26`](https://github.com/Temasys/SkylinkJS/releases/tag/0.6.26).
##### Setting AdapterJS flags
If you require to set Temasys AdapterJS flags (e.g. forcing Temasys WebRTC plugin), we recommend the following method:
diff --git a/bower.json b/bower.json
index 865d454b6..dec98569d 100644
--- a/bower.json
+++ b/bower.json
@@ -1,7 +1,7 @@
{
"name": "skylinkjs",
"description": "WebRTC real-time video conversation library",
- "version": "0.6.25",
+ "version": "0.6.26",
"homepage": "https://temasys.io",
"author": {
"name": "Temasys Communications Pte. Ltd.",
diff --git a/doc/assets/favicon.png b/doc/assets/favicon.png
new file mode 100644
index 000000000..5a95ddab6
Binary files /dev/null and b/doc/assets/favicon.png differ
diff --git a/doc/classes/Skylink.html b/doc/classes/Skylink.html
index c0ade0a9c..55ad4f2bb 100644
--- a/doc/classes/Skylink.html
+++ b/doc/classes/Skylink.html
@@ -2,7 +2,7 @@
The flag if publicly available STUN ICE servers should
be used if options.enableSTUNServer is enabled.
@@ -16543,7 +16570,7 @@
Parameters:
- DEFAULT: false
+ DEFAULT: true
The flag if HTTPS connections should be enforced
during request to Auth server and socket connections to Signaling server
when accessing window.location.protocol value is "http:".
@@ -16687,16 +16714,32 @@
Parameters:
- DEFAULT: 20000
+ DEFAULT: 7000
The timeout for each attempts for socket connection
with the Signaling server to indicate that connection has timed out and has failed to establish.
Note that the mininum timeout value is 5000. If less, this value will be 5000.
- Note that it is recommended to use 12000 as the lowest timeout value if Peers are connecting
+ Note that it is recommended to use 7000 as the lowest timeout value if Peers are connecting
using Polling transports to prevent connection errors.
+
+
+
+ apiTimeout
+ {Number}
+
+ Optional
+
+
+
+ DEFAULT: 4000
+
The timeout to wait for response from Auth server.
+
+
+
+
@@ -17708,6 +17751,19 @@
Parameters:
+
+ apiTimeout
+ {Number}
+
+
+
+
+
+
+ The configured value of the options.apiTimeout.
+
\nFunction that locks the current Room when in session to prevent other Peers from joining the Room.",
"itemtype": "method",
"name": "lockRoom",
@@ -4146,7 +4170,7 @@
},
{
"file": "source/room-connection.js",
- "line": 681,
+ "line": 709,
"description": "
\nFunction that unlocks the current Room when in session to allow other Peers to join the Room.",
"itemtype": "method",
"name": "unlockRoom",
@@ -4156,7 +4180,7 @@
},
{
"file": "source/room-connection.js",
- "line": 715,
+ "line": 743,
"description": "Function that waits for Socket connection to Signaling to be opened.",
"itemtype": "method",
"name": "_waitForOpenChannel",
@@ -4271,6 +4295,11 @@
"description": "Value -1\n The value of the failure code when requesting to Auth server has timed out.",
"type": "Number"
},
+ {
+ "name": "XML_HTTP_NO_REPONSE_ERROR",
+ "description": "Value -2\n The value of the failure code when response from Auth server is empty or timed out.",
+ "type": "Number"
+ },
{
"name": "NO_SOCKET_IO",
"description": "Value 1\n The value of the failure code when dependency Socket.IO client is not loaded.\n To resolve this, ensure that the Socket.IO client dependency is loaded before the Skylink SDK.\n You may use the provided Socket.IO client CDN here.",
@@ -4309,7 +4338,7 @@
},
{
"file": "source/room-init.js",
- "line": 140,
+ "line": 143,
"description": "Spoofs the REGIONAL_SERVER to prevent errors on deployed apps except the fact this no longer works.\nAutomatic regional selection has already been implemented hence REGIONAL_SERVER is no longer useful.",
"itemtype": "attribute",
"name": "REGIONAL_SERVER",
@@ -4322,7 +4351,7 @@
},
{
"file": "source/room-init.js",
- "line": 155,
+ "line": 158,
"description": "The list of User's priority weight schemes for \njoinRoom() method connections.",
"itemtype": "attribute",
"name": "PRIORITY_WEIGHT_SCHEME",
@@ -4350,7 +4379,7 @@
},
{
"file": "source/room-init.js",
- "line": 176,
+ "line": 179,
"description": "Function that generates an UUID (Unique ID).",
"itemtype": "method",
"name": "generateUUID",
@@ -4363,7 +4392,7 @@
},
{
"file": "source/room-init.js",
- "line": 195,
+ "line": 198,
"description": "Function that authenticates and initialises App Key used for Room connections.",
"itemtype": "method",
"name": "init",
@@ -4430,7 +4459,7 @@
"description": "The flag if publicly available STUN ICE servers should\n be used if options.enableSTUNServer is enabled.",
"type": "Boolean",
"optional": true,
- "optdefault": "true"
+ "optdefault": "false"
},
{
"name": "TURNServerTransport",
@@ -4494,7 +4523,7 @@
"description": "The flag if HTTPS connections should be enforced\n during request to Auth server and socket connections to Signaling server\n when accessing window.location.protocol value is \"http:\".\n By default, \"https:\" protocol connections uses HTTPS connections.",
"type": "Boolean",
"optional": true,
- "optdefault": "false"
+ "optdefault": "true"
},
{
"name": "audioCodec",
@@ -4542,10 +4571,17 @@
},
{
"name": "socketTimeout",
- "description": "The timeout for each attempts for socket connection\n with the Signaling server to indicate that connection has timed out and has failed to establish.\n Note that the mininum timeout value is 5000. If less, this value will be 5000.\n Note that it is recommended to use 12000 as the lowest timeout value if Peers are connecting\n using Polling transports to prevent connection errors.",
+ "description": "The timeout for each attempts for socket connection\n with the Signaling server to indicate that connection has timed out and has failed to establish.\n Note that the mininum timeout value is 5000. If less, this value will be 5000.\n Note that it is recommended to use 7000 as the lowest timeout value if Peers are connecting\n using Polling transports to prevent connection errors.",
"type": "Number",
"optional": true,
- "optdefault": "20000"
+ "optdefault": "7000"
+ },
+ {
+ "name": "apiTimeout",
+ "description": "The timeout to wait for response from Auth server.",
+ "type": "Number",
+ "optional": true,
+ "optdefault": "4000"
},
{
"name": "forceTURNSSL",
@@ -4927,6 +4963,11 @@
"description": "The configured value of the options.socketTimeout.",
"type": "Number"
},
+ {
+ "name": "apiTimeout",
+ "description": "The configured value of the options.apiTimeout.",
+ "type": "Number"
+ },
{
"name": "forceTURNSSL",
"description": "The configured value of the options.forceTURNSSL.",
@@ -5011,7 +5052,7 @@
},
{
"file": "source/room-init.js",
- "line": 1082,
+ "line": 1092,
"description": "Starts retrieving Room credentials information from API server.",
"itemtype": "method",
"name": "_requestServerInfo",
@@ -5022,7 +5063,7 @@
},
{
"file": "source/room-init.js",
- "line": 1156,
+ "line": 1196,
"description": "Parses the Room credentials information retrieved from API server.",
"itemtype": "method",
"name": "_parseInfo",
@@ -5033,7 +5074,7 @@
},
{
"file": "source/room-init.js",
- "line": 1226,
+ "line": 1266,
"description": "Loads and checks the dependencies if they are loaded correctly.",
"itemtype": "method",
"name": "_loadInfo",
@@ -5044,7 +5085,7 @@
},
{
"file": "source/room-init.js",
- "line": 1352,
+ "line": 1392,
"description": "Starts initialising for Room credentials for room name provided in joinRoom() method.",
"itemtype": "method",
"name": "_initSelectedRoom",
@@ -5181,6 +5222,20 @@
{
"file": "source/skylink-debug.js",
"line": 108,
+ "description": "Stores the flag if logs should print timestamp.",
+ "itemtype": "attribute",
+ "name": "_printTimestamp",
+ "type": "Boolean",
+ "default": "false",
+ "access": "private",
+ "tagname": "",
+ "scoped": "true",
+ "since": "0.6.26",
+ "class": "Skylink"
+ },
+ {
+ "file": "source/skylink-debug.js",
+ "line": 120,
"description": "Stores the logs used for SkylinkLogs object.",
"itemtype": "attribute",
"name": "_storedLogs",
@@ -5193,7 +5248,7 @@
},
{
"file": "source/skylink-debug.js",
- "line": 119,
+ "line": 131,
"description": "Function that gets the stored logs.",
"itemtype": "method",
"name": "_getStoredLogsFn",
@@ -5205,7 +5260,7 @@
},
{
"file": "source/skylink-debug.js",
- "line": 140,
+ "line": 152,
"description": "Function that clears the stored logs.",
"itemtype": "method",
"name": "_clearAllStoredLogsFn",
@@ -5217,7 +5272,7 @@
},
{
"file": "source/skylink-debug.js",
- "line": 152,
+ "line": 164,
"description": "Function that prints in the Web Console interface the stored logs.",
"itemtype": "method",
"name": "_printAllStoredLogsFn",
@@ -5229,7 +5284,7 @@
},
{
"file": "source/skylink-debug.js",
- "line": 176,
+ "line": 188,
"description": "
\n To utilise and enable the SkylinkLogs API functionalities, the\n setDebugMode() method\n options.storeLogs parameter has to be enabled.\n
\nThe object interface to manage the SDK \nJavascript Web Console logs.",
"itemtype": "property",
"name": "SkylinkLogs",
@@ -5240,7 +5295,7 @@
},
{
"file": "source/skylink-debug.js",
- "line": 191,
+ "line": 203,
"description": "Function that gets the current stored SDK console logs.",
"itemtype": "property",
"name": "SkylinkLogs.getLogs",
@@ -5267,7 +5322,7 @@
},
{
"file": "source/skylink-debug.js",
- "line": 218,
+ "line": 230,
"description": "Function that clears all the current stored SDK console logs.",
"itemtype": "property",
"name": "SkylinkLogs.clearAllLogs",
@@ -5282,7 +5337,7 @@
},
{
"file": "source/skylink-debug.js",
- "line": 232,
+ "line": 244,
"description": "Function that prints all the current stored SDK console logs into the\nJavascript Web Console.",
"itemtype": "property",
"name": "SkylinkLogs.printAllLogs",
@@ -5297,7 +5352,7 @@
},
{
"file": "source/skylink-debug.js",
- "line": 248,
+ "line": 260,
"description": "Function that handles the logs received and prints in the Web Console interface according to the log level set.",
"itemtype": "method",
"name": "_logFn",
@@ -5310,7 +5365,7 @@
},
{
"file": "source/skylink-debug.js",
- "line": 317,
+ "line": 332,
"description": "Stores the logging functions.",
"itemtype": "attribute",
"name": "log",
@@ -5350,7 +5405,7 @@
},
{
"file": "source/skylink-debug.js",
- "line": 353,
+ "line": 368,
"description": "Function that configures the level of console API logs to be printed in the\nJavascript Web Console.",
"itemtype": "method",
"name": "setLogLevel",
@@ -5370,7 +5425,7 @@
},
{
"file": "source/skylink-debug.js",
- "line": 390,
+ "line": 405,
"description": "Function that configures the debugging mode of the SDK.",
"itemtype": "method",
"name": "setDebugMode",
@@ -5395,6 +5450,13 @@
"type": "Boolean",
"optional": true,
"optdefault": "false"
+ },
+ {
+ "name": "printTimestamp",
+ "description": "The flag if SDK should print the timestamp of the console logs.",
+ "type": "Boolean",
+ "optional": true,
+ "optdefault": "false"
}
]
}
@@ -8684,7 +8746,7 @@
},
{
"file": "source/socket-channel.js",
- "line": 444,
+ "line": 453,
"description": "Function that starts the socket connection to the Signaling.\nThis starts creating the socket connection and called at first not when requiring to fallback.",
"itemtype": "method",
"name": "_openChannel",
@@ -8695,7 +8757,7 @@
},
{
"file": "source/socket-channel.js",
- "line": 488,
+ "line": 497,
"description": "Function that stops the socket connection to the Signaling.",
"itemtype": "method",
"name": "_closeChannel",
@@ -9617,7 +9679,7 @@
},
{
"file": "source/stream-media.js",
- "line": 655,
+ "line": 665,
"description": "
Deprecation Warning!\n This method has been deprecated. Use muteStream() method instead.\n
\nFunction that mutes both getUserMedia() Stream and\nshareScreen() Stream audio tracks.",
"itemtype": "method",
"name": "disableAudio",
@@ -9734,7 +9796,7 @@
},
{
"file": "source/stream-media.js",
- "line": 1109,
+ "line": 1119,
"description": "
Deprecation Warning!\n This method has been deprecated. Use muteStream() method instead.\n
\nFunction that unmutes both getUserMedia() Stream and\nshareScreen() Stream video tracks.",
"itemtype": "method",
"name": "enableVideo",
@@ -9749,7 +9811,7 @@
},
{
"file": "source/stream-media.js",
- "line": 1136,
+ "line": 1146,
"description": "
Deprecation Warning!\n This method has been deprecated. Use muteStream() method instead.\n
\nFunction that mutes both getUserMedia() Stream and\nshareScreen() Stream video tracks.",
"itemtype": "method",
"name": "disableVideo",
@@ -9764,7 +9826,7 @@
},
{
"file": "source/stream-media.js",
- "line": 1163,
+ "line": 1173,
"description": "
\n For a better user experience, the functionality is throttled when invoked many times in less\n than the milliseconds interval configured in the init() method.\n Note that the Opera and Edge browser does not support screensharing, and as for IE / Safari browsers using\n the Temasys Plugin screensharing support, check out the \n commercial licensing for more options.\n
var selectedRoom = self._defaultRoom;
var previousRoom = self._selectedRoom;
var mediaOptions = {};
+ var timestamp = (new Date()).getTime() + Math.floor(Math.random() * 10000);
+ self._joinRoomManager.timestamp = timestamp;
if (room && typeof room === 'string') {
selectedRoom = room;
@@ -513,16 +515,30 @@
File: source/room-connection.js
};
var joinRoomFn = function () {
+ // If room has been stopped but does not matches timestamp skip.
+ if (self._joinRoomManager.timestamp !== timestamp) {
+ resolveAsErrorFn('joinRoom() process did not complete', selectedRoom);
+ return;
+ }
+
self._initSelectedRoom(selectedRoom, function(initError, initSuccess) {
if (initError) {
resolveAsErrorFn(initError.error, self._selectedRoom, self._readyState);
return;
+ // If details has been initialised but does not matches timestamp skip.
+ } else if (self._joinRoomManager.timestamp !== timestamp) {
+ resolveAsErrorFn('joinRoom() process did not complete', selectedRoom);
+ return;
}
- self._waitForOpenChannel(mediaOptions, function (error, success) {
+ self._waitForOpenChannel(mediaOptions || {}, timestamp, function (error, success) {
if (error) {
resolveAsErrorFn(error, self._selectedRoom, self._readyState);
return;
+ // If socket and stream has been retrieved but socket connection does not matches timestamp skip.
+ } else if (self._joinRoomManager.timestamp !== timestamp) {
+ resolveAsErrorFn('joinRoom() process did not complete', selectedRoom);
+ return;
}
if (AdapterJS.webrtcDetectedType === 'AppleWebKit') {
@@ -607,14 +623,26 @@
* <code>roomServer</code> configuration, contact our <a href="http://support.temasys.io">support portal</a>.</small>
* @param {Number} XML_HTTP_REQUEST_ERROR <small>Value <code>-1</code></small>
* The value of the failure code when requesting to Auth server has timed out.
+ * @param {Number} XML_HTTP_NO_REPONSE_ERROR <small>Value <code>-2</code></small>
+ * The value of the failure code when response from Auth server is empty or timed out.
* @param {Number} NO_SOCKET_IO <small>Value <code>1</code></small>
* The value of the failure code when dependency <a href="http://socket.io/download/">Socket.IO client</a> is not loaded.
* <small>To resolve this, ensure that the Socket.IO client dependency is loaded before the Skylink SDK.
@@ -220,6 +222,7 @@
* configuration is not honoured as Peers connected with MCU is similar as a forced TURN connection. The flags
* will act as if the value is <code>false</code> and ICE candidates will never be filtered regardless of the
* <code>options.filterCandidatesType</code> configuration.</small>
- * @param {Boolean} [options.usePublicSTUN=true] The flag if publicly available STUN ICE servers should
+ * @param {Boolean} [options.usePublicSTUN=false] The flag if publicly available STUN ICE servers should
* be used if <code>options.enableSTUNServer</code> is enabled.
* @param {Boolean} [options.TURNServerTransport] <blockquote class="info">
* Note that configuring the protocol may not necessarily result in the desired network transports protocol
@@ -389,7 +392,7 @@
File: source/room-init.js
* @param {Boolean} [options.audioFallback=false] The flag if <a href="#method_getUserMedia">
* <code>getUserMedia()</code> method</a> should fallback to retrieve only audio Stream when
* retrieving audio and video Stream fails.
- * @param {Boolean} [options.forceSSL=false] The flag if HTTPS connections should be enforced
+ * @param {Boolean} [options.forceSSL=true] The flag if HTTPS connections should be enforced
* during request to Auth server and socket connections to Signaling server
* when accessing <code>window.location.protocol</code> value is <code>"http:"</code>.
* <small>By default, <code>"https:"</code> protocol connections uses HTTPS connections.</small>
@@ -416,11 +419,12 @@
File: source/room-init.js
* <small>The value must not be <code>AUTO</code>.</small>
* [Rel: Skylink.VIDEO_CODEC]
* @param {Number} [options.videoCodec.samplingRate] The video codec sampling to prefer to encode sending video data when available.
- * @param {Number} [options.socketTimeout=20000] The timeout for each attempts for socket connection
+ * @param {Number} [options.socketTimeout=7000] The timeout for each attempts for socket connection
* with the Signaling server to indicate that connection has timed out and has failed to establish.
* <small>Note that the mininum timeout value is <code>5000</code>. If less, this value will be <code>5000</code>.</small>
- * <small>Note that it is recommended to use <code>12000</code> as the lowest timeout value if Peers are connecting
+ * <small>Note that it is recommended to use <code>7000</code> as the lowest timeout value if Peers are connecting
* using Polling transports to prevent connection errors.</small>
+ * @param {Number} [options.apiTimeout=4000] The timeout to wait for response from Auth server.
* @param {Boolean} [options.forceTURNSSL=false] <blockquote class="info">
* Note that currently Firefox does not support the TURNS protocol, and that if TURNS is required,
* TURN ICE servers using port <code>443</code> will be used instead.<br>
@@ -596,6 +600,7 @@
File: source/room-init.js
* @param {String|JSON} callback.success.audioCodec The configured value of the <code>options.audioCodec</code>.
* @param {String|JSON} callback.success.videoCodec The configured value of the <code>options.videoCodec</code>.
* @param {Number} callback.success.socketTimeout The configured value of the <code>options.socketTimeout</code>.
+ * @param {Number} callback.success.apiTimeout The configured value of the <code>options.apiTimeout</code>.
* @param {Boolean} callback.success.forceTURNSSL The configured value of the <code>options.forceTURNSSL</code>.
* @param {Boolean} callback.success.forceTURN The configured value of the <code>options.forceTURN</code>.
* @param {Boolean} callback.success.usePublicSTUN The configured value of the <code>options.usePublicSTUN</code>.
@@ -698,13 +703,14 @@
File: source/room-init.js
var enableTURNServer = true;
var TURNTransport = self.TURN_TRANSPORT.ANY;
var audioFallback = false;
- var forceSSL = false;
- var socketTimeout = 20000;
+ var forceSSL = true;
+ var socketTimeout = 7000;
+ var apiTimeout = 4000;
var forceTURNSSL = false;
var audioCodec = self.AUDIO_CODEC.AUTO;
var videoCodec = self.VIDEO_CODEC.AUTO;
var forceTURN = false;
- var usePublicSTUN = true;
+ var usePublicSTUN = false;
var disableVideoFecCodecs = false;
var disableComfortNoiseCodec = false;
var disableREMB = false;
@@ -767,11 +773,12 @@
File: source/room-init.js
// set the force ssl always option
forceSSL = (typeof options.forceSSL === 'boolean') ?
options.forceSSL : forceSSL;
- // set the socket timeout option
- socketTimeout = (typeof options.socketTimeout === 'number') ?
- options.socketTimeout : socketTimeout;
// set the socket timeout option to be above 5000
- socketTimeout = (socketTimeout < 5000) ? 5000 : socketTimeout;
+ socketTimeout = (typeof options.socketTimeout === 'number' && socketTimeout < 5000 && socketTimeout > 0) ?
+ options.socketTimeout : socketTimeout;
+ // set the api timeout option
+ apiTimeout = (typeof options.apiTimeout === 'number' && options.apiTimeout > 0) ?
+ options.apiTimeout : apiTimeout;
// set the force turn ssl always option
forceTURNSSL = (typeof options.forceTURNSSL === 'boolean') ?
options.forceTURNSSL : forceTURNSSL;
@@ -1048,6 +1055,7 @@
SkylinkJS API Documentation
- Version: 0.6.25
+ Version: 0.6.26
diff --git a/package.json b/package.json
index 274fe29b2..a4d115fa3 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "skylinkjs",
"description": "Temasys Web SDK is an open-source client-side library for your web-browser that enables any website to easily leverage the capabilities of WebRTC and its direct data streaming powers between peers for audio/video conferencing or file transfer.",
- "version": "0.6.25",
+ "version": "0.6.26",
"homepage": "https://temasys.io/",
"author": {
"name": "Temasys Communications Pte. Ltd.",
diff --git a/publish/skylink.complete.js b/publish/skylink.complete.js
index e4a53710a..551b6eeba 100644
--- a/publish/skylink.complete.js
+++ b/publish/skylink.complete.js
@@ -1,4 +1,4 @@
-/*! skylinkjs - v0.6.25 - Fri Sep 08 2017 17:34:14 GMT+0800 (+08) */
+/*! skylinkjs - v0.6.26 - Fri Sep 15 2017 15:25:49 GMT+0800 (+08) */
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.io = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) {
+ // server[?transport=xxx]
+ iceServerName = (server.url.split(':')[1] || '').split('?')[0] || null;
} else {
- iceServersList[username][credential].push(url);
+ iceServers[0].urls.push(server.url);
}
- }
- };
- var i, serverItem;
+ } else if (server.url.indexOf('turn:') === 0 && server.url.indexOf('@') > 0 && server.credential &&
+ !(iceServers[1].username || iceServers[1].credential)) {
+ var parts = server.url.split(':');
+ var urlParts = (parts[1] || '').split('@');
- for (i = 0; i < givenIceServers.length; i++) {
- var server = givenIceServers[i];
-
- if (typeof server.url !== 'string') {
- log.warn('Ignoring ICE server provided at index ' + i, clone(server));
- continue;
+ // server[?transport=xxx]
+ iceServerName = (urlParts[1] || '').split('?')[0];
+ iceServers[1].username = urlParts[0];
+ iceServers[1].credential = server.credential;
+ iceServerProtocol = 'turn';
}
+ });
- if (server.url.indexOf('stun') === 0) {
- if (!self._enableSTUN) {
- log.warn('Ignoring STUN server provided at index ' + i, clone(server));
- continue;
- }
-
- if (!self._usePublicSTUN && server.url.indexOf('temasys') === -1) {
- log.warn('Ignoring public STUN server provided at index ' + i, clone(server));
- continue;
- }
+ if (self._iceServer) {
+ iceServers = [{
+ urls: self._iceServer.urls,
+ username: iceServers[1].username,
+ credential: iceServers[1].credential
+ }];
- } else if (server.url.indexOf('turn') === 0) {
- if (!self._enableTURN) {
- log.warn('Ignoring TURN server provided at index ' + i, clone(server));
- continue;
- }
+ } else {
+ iceServerName = iceServerName || 'turn.temasys.io';
- if (server.url.indexOf(':443') === -1 && useTURNSSLPort) {
- log.log('Ignoring TURN Server (non-SSL port) provided at index ' + i, clone(server));
- continue;
- }
+ if (AdapterJS.webrtcDetectedBrowser === 'edge') {
+ iceServerPorts.udp = [3478];
+ iceServerPorts.tcp = [];
+ iceServerPorts.both = [];
+ iceServerProtocol = 'turn';
+
+ } else if (self._forceTURNSSL) {
+ if (AdapterJS.webrtcDetectedBrowser === 'firefox' && AdapterJS.webrtcDetectedVersion < 53) {
+ iceServerPorts.udp = [];
+ iceServerPorts.tcp = [443];
+ iceServerPorts.both = [];
+ iceServerProtocol = 'turn';
- if (useTURNSSLProtocol) {
- var parts = server.url.split(':');
- parts[0] = 'turns';
- server.url = parts.join(':');
+ } else {
+ iceServerPorts.udp = [];
+ iceServerProtocol = 'turns';
}
- }
-
- // parse "@" settings
- if (server.url.indexOf('@') > 0) {
- var protocolParts = server.url.split(':');
- var urlParts = protocolParts[1].split('@');
- server.username = urlParts[0];
- server.url = protocolParts[0] + ':' + urlParts[1];
- // add the ICE server port
- // Edge uses 3478 with ?transport=udp for now
- if (AdapterJS.webrtcDetectedBrowser === 'edge') {
- server.url += ':3478';
- } else if (protocolParts[2]) {
- server.url += ':' + protocolParts[2];
- }
+ // Limit the number of ports..
+ } else if (AdapterJS.webrtcDetectedBrowser === 'firefox') {
+ iceServerPorts.udp = [3478];
+ iceServerPorts.tcp = [443, 80];
}
- var username = typeof server.username === 'string' ? server.username : 'none';
- var credential = typeof server.credential === 'string' ? server.credential : 'none';
+ if (self._TURNTransport === self.TURN_TRANSPORT.UDP && !self._forceTURNSSL) {
+ iceServerPorts.udp = iceServerPorts.udp.concat(iceServerPorts.both);
+ iceServerPorts.tcp = [];
+ iceServerPorts.both = [];
- if (server.url.indexOf('turn') === 0) {
- if (self._TURNTransport === self.TURN_TRANSPORT.ANY) {
- pushIceServer(username, credential, server.url);
+ } else if (self._TURNTransport === self.TURN_TRANSPORT.TCP) {
+ iceServerPorts.tcp = iceServerPorts.tcp.concat(iceServerPorts.both);
+ iceServerPorts.udp = [];
+ iceServerPorts.both = [];
- } else {
- var rawUrl = server.url;
-
- if (rawUrl.indexOf('?transport=') > 0) {
- rawUrl = rawUrl.split('?transport=')[0];
- }
-
- if (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) {
- pushIceServer(username, credential, rawUrl + '?transport=tcp');
- pushIceServer(username, credential, rawUrl + '?transport=udp');
- } else {
- log.warn('Invalid TURN transport option "' + self._TURNTransport +
- '". Ignoring TURN server at index' + i, clone(server));
- continue;
- }
- }
- } else {
- pushIceServer(username, credential, server.url);
+ } else if (self._TURNTransport === self.TURN_TRANSPORT.NONE) {
+ iceServerPorts.tcp = [];
+ iceServerPorts.udp = [];
}
- }
- // add mozilla STUN for firefox
- if (self._enableSTUN && self._usePublicSTUN && AdapterJS.webrtcDetectedBrowser === 'firefox') {
- pushIceServer('none', 'none', 'stun:stun.services.mozilla.com', 0);
- }
+ if (iceServerProtocol === 'stun') {
+ iceServerPorts.tcp = [];
+ }
- var hasUrlsSupport =
- (AdapterJS.webrtcDetectedBrowser === 'chrome' && AdapterJS.webrtcDetectedVersion > 34) ||
- (AdapterJS.webrtcDetectedBrowser === 'firefox' && AdapterJS.webrtcDetectedVersion > 38) ||
- (AdapterJS.webrtcDetectedBrowser === 'opera' && AdapterJS.webrtcDetectedVersion > 31) ||
- (['plugin', 'AppleWebKit'].indexOf(AdapterJS.webrtcDetectedType) > -1) ||
- (['bowser', 'edge'].indexOf(AdapterJS.webrtcDetectedBrowser) > -1);
+ iceServerPorts.tcp.forEach(function (tcpPort) {
+ iceServers[1].urls.push(iceServerProtocol + ':' + iceServerName + ':' + tcpPort + '?transport=tcp');
+ });
- 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 (serverUsername !== 'none') {
- urlsItem.username = serverUsername;
- }
- if (serverCred !== 'none') {
- urlsItem.credential = serverCred;
- }
+ iceServerPorts.udp.forEach(function (udpPort) {
+ iceServers[1].urls.push(iceServerProtocol + ':' + iceServerName + ':' + udpPort + '?transport=udp');
+ });
- // Edge uses 1 url only for now
- if (AdapterJS.webrtcDetectedBrowser === 'edge') {
- if (urlsItem.username && urlsItem.credential) {
- urlsItem.urls = [urlsItem.urls[0]];
- newIceServers.push(urlsItem);
- break;
- }
- } else {
- newIceServers.push(urlsItem);
- }
- } else {
- for (var j = 0; j < iceServersList[serverUsername][serverCred].length; j++) {
- var urlItem = {
- url: iceServersList[serverUsername][serverCred][j]
- };
- if (serverUsername !== 'none') {
- urlItem.username = serverUsername;
- }
- if (serverCred !== 'none') {
- urlItem.credential = serverCred;
- }
- newIceServers.push(urlItem);
- }
- }
- }
- }
- }
+ iceServerPorts.both.forEach(function (bothPort) {
+ iceServers[1].urls.push(iceServerProtocol + ':' + iceServerName + ':' + bothPort);
+ });
}
- if (self._iceServer) {
- var nUsername = null, nCredential = null;
- for (i = 0; i < newIceServers.length; i++) {
- if (newIceServers[i].username) {
- nUsername = newIceServers[i].username;
- }
- if (newIceServers[i].credential) {
- nCredential = newIceServers[i].credential;
- }
- }
- newIceServers = [{
- urls: self._iceServer.urls,
- username: nUsername,
- credential: nCredential
- }];
+ if (!self._usePublicSTUN) {
+ iceServers.splice(0, 1);
}
- log.log('Output iceServers configuration:', newIceServers);
+ log.log('Output iceServers configuration:', iceServers);
return {
- iceServers: newIceServers
+ iceServers: iceServers
};
};
Skylink.prototype.PEER_CONNECTION_STATE = {
@@ -23006,6 +22934,8 @@ Skylink.prototype.joinRoom = function(room, options, callback) {
var selectedRoom = self._defaultRoom;
var previousRoom = self._selectedRoom;
var mediaOptions = {};
+ var timestamp = (new Date()).getTime() + Math.floor(Math.random() * 10000);
+ self._joinRoomManager.timestamp = timestamp;
if (room && typeof room === 'string') {
selectedRoom = room;
@@ -23034,16 +22964,30 @@ Skylink.prototype.joinRoom = function(room, options, callback) {
};
var joinRoomFn = function () {
+ // If room has been stopped but does not matches timestamp skip.
+ if (self._joinRoomManager.timestamp !== timestamp) {
+ resolveAsErrorFn('joinRoom() process did not complete', selectedRoom);
+ return;
+ }
+
self._initSelectedRoom(selectedRoom, function(initError, initSuccess) {
if (initError) {
resolveAsErrorFn(initError.error, self._selectedRoom, self._readyState);
return;
+ // If details has been initialised but does not matches timestamp skip.
+ } else if (self._joinRoomManager.timestamp !== timestamp) {
+ resolveAsErrorFn('joinRoom() process did not complete', selectedRoom);
+ return;
}
- self._waitForOpenChannel(mediaOptions, function (error, success) {
+ self._waitForOpenChannel(mediaOptions || {}, timestamp, function (error, success) {
if (error) {
resolveAsErrorFn(error, self._selectedRoom, self._readyState);
return;
+ // If socket and stream has been retrieved but socket connection does not matches timestamp skip.
+ } else if (self._joinRoomManager.timestamp !== timestamp) {
+ resolveAsErrorFn('joinRoom() process did not complete', selectedRoom);
+ return;
}
if (AdapterJS.webrtcDetectedType === 'AppleWebKit') {
@@ -23128,14 +23072,26 @@ Skylink.prototype.joinRoom = function(room, options, callback) {
return;
}
- if (self._inRoom) {
- var stopStream = mediaOptions.audio === false && mediaOptions.video === false;
+ self._joinRoomManager.socketsFn.forEach(function (fnItem) {
+ fnItem(timestamp);
+ });
+
+ self._joinRoomManager.socketsFn = [];
+
+ var stopStream = mediaOptions.audio === false && mediaOptions.video === false;
- self.leaveRoom(stopStream, function (lRError, lRSuccess) {
+ if (self._inRoom) {
+ self.leaveRoom({
+ userMedia: stopStream
+ }, function (lRError, lRSuccess) {
log.debug([null, 'Room', previousRoom, 'Leave Room callback result ->'], [lRError, lRSuccess]);
joinRoomFn();
});
} else {
+ if (stopStream) {
+ self.stopStream();
+ }
+
joinRoomFn();
}
};
@@ -23331,7 +23287,7 @@ Skylink.prototype.unlockRoom = function() {
* @for Skylink
* @since 0.5.5
*/
-Skylink.prototype._waitForOpenChannel = function(mediaOptions, callback) {
+Skylink.prototype._waitForOpenChannel = function(mediaOptions, joinRoomTimestamp, callback) {
var self = this;
// when reopening room, it should stay as 0
self._socketCurrentReconnectionAttempt = 0;
@@ -23548,7 +23504,7 @@ Skylink.prototype._waitForOpenChannel = function(mediaOptions, callback) {
self.once('socketError', onChannelError, function (errorState) {
return errorState === self.SOCKET_ERROR.RECONNECTION_ABORTED;
});
- self._openChannel();
+ self._openChannel(joinRoomTimestamp);
} else {
onChannelOpen();
}
@@ -23557,7 +23513,7 @@ Skylink.prototype._waitForOpenChannel = function(mediaOptions, callback) {
});
};
-Skylink.prototype.VERSION = '0.6.25';
+Skylink.prototype.VERSION = '0.6.26';
/**
* The list of init() method ready states.
@@ -23637,6 +23593,8 @@ Skylink.prototype.READY_STATE_CHANGE = {
* roomServer configuration, contact our support portal.
* @param {Number} XML_HTTP_REQUEST_ERROR Value -1
* The value of the failure code when requesting to Auth server has timed out.
+ * @param {Number} XML_HTTP_NO_REPONSE_ERROR Value -2
+ * The value of the failure code when response from Auth server is empty or timed out.
* @param {Number} NO_SOCKET_IO Value 1
* The value of the failure code when dependency Socket.IO client is not loaded.
* To resolve this, ensure that the Socket.IO client dependency is loaded before the Skylink SDK.
@@ -23680,6 +23638,7 @@ Skylink.prototype.READY_STATE_CHANGE_ERROR = {
API_RETRIEVAL_FAILED: 4021,
API_WRONG_ACCESS_DOMAIN: 5005,
XML_HTTP_REQUEST_ERROR: -1,
+ XML_HTTP_NO_REPONSE_ERROR: -2,
NO_SOCKET_IO: 1,
NO_XMLHTTPREQUEST_SUPPORT: 2,
NO_WEBRTC_SUPPORT: 3,
@@ -23787,7 +23746,7 @@ Skylink.prototype.generateUUID = function() {
* configuration is not honoured as Peers connected with MCU is similar as a forced TURN connection. The flags
* will act as if the value is false and ICE candidates will never be filtered regardless of the
* options.filterCandidatesType configuration.
- * @param {Boolean} [options.usePublicSTUN=true] The flag if publicly available STUN ICE servers should
+ * @param {Boolean} [options.usePublicSTUN=false] The flag if publicly available STUN ICE servers should
* be used if options.enableSTUNServer is enabled.
* @param {Boolean} [options.TURNServerTransport]
* Note that configuring the protocol may not necessarily result in the desired network transports protocol
@@ -23849,7 +23808,7 @@ Skylink.prototype.generateUUID = function() {
* @param {Boolean} [options.audioFallback=false] The flag if
* getUserMedia() method should fallback to retrieve only audio Stream when
* retrieving audio and video Stream fails.
- * @param {Boolean} [options.forceSSL=false] The flag if HTTPS connections should be enforced
+ * @param {Boolean} [options.forceSSL=true] The flag if HTTPS connections should be enforced
* during request to Auth server and socket connections to Signaling server
* when accessing window.location.protocol value is "http:".
* By default, "https:" protocol connections uses HTTPS connections.
@@ -23876,11 +23835,12 @@ Skylink.prototype.generateUUID = function() {
* The value must not be AUTO.
* [Rel: Skylink.VIDEO_CODEC]
* @param {Number} [options.videoCodec.samplingRate] The video codec sampling to prefer to encode sending video data when available.
- * @param {Number} [options.socketTimeout=20000] The timeout for each attempts for socket connection
+ * @param {Number} [options.socketTimeout=7000] The timeout for each attempts for socket connection
* with the Signaling server to indicate that connection has timed out and has failed to establish.
* Note that the mininum timeout value is 5000. If less, this value will be 5000.
- * Note that it is recommended to use 12000 as the lowest timeout value if Peers are connecting
+ * Note that it is recommended to use 7000 as the lowest timeout value if Peers are connecting
* using Polling transports to prevent connection errors.
+ * @param {Number} [options.apiTimeout=4000] The timeout to wait for response from Auth server.
* @param {Boolean} [options.forceTURNSSL=false]
* Note that currently Firefox does not support the TURNS protocol, and that if TURNS is required,
* TURN ICE servers using port 443 will be used instead.
@@ -24056,6 +24016,7 @@ Skylink.prototype.generateUUID = function() {
* @param {String|JSON} callback.success.audioCodec The configured value of the options.audioCodec.
* @param {String|JSON} callback.success.videoCodec The configured value of the options.videoCodec.
* @param {Number} callback.success.socketTimeout The configured value of the options.socketTimeout.
+ * @param {Number} callback.success.apiTimeout The configured value of the options.apiTimeout.
* @param {Boolean} callback.success.forceTURNSSL The configured value of the options.forceTURNSSL.
* @param {Boolean} callback.success.forceTURN The configured value of the options.forceTURN.
* @param {Boolean} callback.success.usePublicSTUN The configured value of the options.usePublicSTUN.
@@ -24158,13 +24119,14 @@ Skylink.prototype.init = function(options, callback) {
var enableTURNServer = true;
var TURNTransport = self.TURN_TRANSPORT.ANY;
var audioFallback = false;
- var forceSSL = false;
- var socketTimeout = 20000;
+ var forceSSL = true;
+ var socketTimeout = 7000;
+ var apiTimeout = 4000;
var forceTURNSSL = false;
var audioCodec = self.AUDIO_CODEC.AUTO;
var videoCodec = self.VIDEO_CODEC.AUTO;
var forceTURN = false;
- var usePublicSTUN = true;
+ var usePublicSTUN = false;
var disableVideoFecCodecs = false;
var disableComfortNoiseCodec = false;
var disableREMB = false;
@@ -24227,11 +24189,12 @@ Skylink.prototype.init = function(options, callback) {
// set the force ssl always option
forceSSL = (typeof options.forceSSL === 'boolean') ?
options.forceSSL : forceSSL;
- // set the socket timeout option
- socketTimeout = (typeof options.socketTimeout === 'number') ?
- options.socketTimeout : socketTimeout;
// set the socket timeout option to be above 5000
- socketTimeout = (socketTimeout < 5000) ? 5000 : socketTimeout;
+ socketTimeout = (typeof options.socketTimeout === 'number' && socketTimeout < 5000 && socketTimeout > 0) ?
+ options.socketTimeout : socketTimeout;
+ // set the api timeout option
+ apiTimeout = (typeof options.apiTimeout === 'number' && options.apiTimeout > 0) ?
+ options.apiTimeout : apiTimeout;
// set the force turn ssl always option
forceTURNSSL = (typeof options.forceTURNSSL === 'boolean') ?
options.forceTURNSSL : forceTURNSSL;
@@ -24508,6 +24471,7 @@ Skylink.prototype.init = function(options, callback) {
self._audioFallback = audioFallback;
self._forceSSL = forceSSL;
self._socketTimeout = socketTimeout;
+ self._apiTimeout = apiTimeout;
self._forceTURNSSL = forceTURNSSL;
self._selectedAudioCodec = audioCodec;
self._selectedVideoCodec = videoCodec;
@@ -24542,6 +24506,7 @@ Skylink.prototype.init = function(options, callback) {
audioFallback: self._audioFallback,
forceSSL: self._forceSSL,
socketTimeout: self._socketTimeout,
+ apiTimeout: self._apiTimeout,
forceTURNSSL: self._forceTURNSSL,
audioCodec: self._selectedAudioCodec,
videoCodec: self._selectedVideoCodec,
@@ -24590,6 +24555,7 @@ Skylink.prototype.init = function(options, callback) {
audioFallback: self._audioFallback,
forceSSL: self._forceSSL,
socketTimeout: self._socketTimeout,
+ apiTimeout: self._apiTimeout,
forceTURNSSL: self._forceTURNSSL,
audioCodec: self._selectedAudioCodec,
videoCodec: self._selectedVideoCodec,
@@ -24639,69 +24605,99 @@ Skylink.prototype.init = function(options, callback) {
*/
Skylink.prototype._requestServerInfo = function(method, url, callback, params) {
var self = this;
- // XDomainRequest is supported in IE8 - 9
- var useXDomainRequest = typeof window.XDomainRequest === 'function' ||
- typeof window.XDomainRequest === 'object';
-
- self._socketUseXDR = useXDomainRequest;
- var xhr;
+ var retries = 0;
- // set force SSL option
+ // XDomainRequest is supported in IE8 - 9 for CORS connection.
+ self._socketUseXDR = typeof window.XDomainRequest === 'function' || typeof window.XDomainRequest === 'object';
url = (self._forceSSL) ? 'https:' + url : url;
- if (useXDomainRequest) {
- log.debug([null, 'XMLHttpRequest', method, 'Using XDomainRequest. ' +
- 'XMLHttpRequest is now XDomainRequest'], {
- agent: AdapterJS.webrtcDetectedBrowser,
- version: AdapterJS.webrtcDetectedVersion
- });
- xhr = new XDomainRequest();
- xhr.setContentType = function (contentType) {
- xhr.contentType = contentType;
+ (function requestFn () {
+ var xhr = new XMLHttpRequest();
+ var completed = false;
+
+ if (self._socketUseXDR) {
+ log.debug([null, 'XMLHttpRequest', method, 'Using XDomainRequest for CORS authentication.']);
+ xhr = new XDomainRequest();
+ xhr.setContentType = function (contentType) {
+ xhr.contentType = contentType;
+ };
+ }
+
+ xhr.onload = function () {
+ if (completed) {
+ return;
+ }
+ completed = true;
+ var response = JSON.parse(xhr.responseText || xhr.response || '{}');
+ var status = xhr.status || 200;
+ log.debug([null, 'XMLHttpRequest', method, 'Received sessions parameters ->'], response);
+ callback(status, response);
};
- } else {
- log.debug([null, 'XMLHttpRequest', method, 'Using XMLHttpRequest'], {
- agent: AdapterJS.webrtcDetectedBrowser,
- version: AdapterJS.webrtcDetectedVersion
- });
- xhr = new window.XMLHttpRequest();
- xhr.setContentType = function (contentType) {
- xhr.setRequestHeader('Content-type', contentType);
+
+ xhr.onerror = function (error) {
+ if (completed) {
+ return;
+ }
+ completed = true;
+ log.error([null, 'XMLHttpRequest', method, 'Failed retrieving information with 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.onload = function () {
- var response = xhr.responseText || xhr.response;
- var status = xhr.status || 200;
- log.debug([null, 'XMLHttpRequest', method, 'Received sessions parameters'],
- JSON.parse(response || '{}'));
- callback(status, JSON.parse(response || '{}'));
- };
+ xhr.onprogress = function () {
+ log.debug([null, 'XMLHttpRequest', method, 'Retrieving information and config from webserver ->'], {
+ url: url,
+ params: params
+ });
+ };
- 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);
- };
+ try {
+ xhr.open(method, url, true);
+ if (params) {
+ xhr.setContentType('application/json;charset=UTF-8');
+ xhr.send(JSON.stringify(params));
+ } else {
+ xhr.send();
+ }
+ } catch (error) {
+ completed = true;
+ self._readyState = -1;
+ self._trigger('readyStateChange', self.READY_STATE_CHANGE.ERROR, {
+ status: xhr.status || null,
+ content: 'Failed starting XHR process.',
+ errorCode: self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR
+ }, self._selectedRoom);
+ return;
+ }
- xhr.onprogress = function () {
- log.debug([null, 'XMLHttpRequest', method,
- 'Retrieving information and config from webserver. Url:'], url);
- log.debug([null, 'XMLHttpRequest', method, 'Provided parameters:'], params);
- };
+ setTimeout(function () {
+ if (completed) {
+ return;
+ }
+ completed = true;
+ xhr.onload = null;
+ xhr.onerror = null;
+ xhr.onprogress = null;
- xhr.open(method, url, true);
- if (params) {
- xhr.setContentType('application/json;charset=UTF-8');
- xhr.send(JSON.stringify(params));
- } else {
- xhr.send();
- }
+ if (retries < 2) {
+ retries++;
+ requestFn();
+
+ } else {
+ self._readyState = -1;
+ self._trigger('readyStateChange', self.READY_STATE_CHANGE.ERROR, {
+ status: xhr.status || null,
+ content: 'Response timed out from API server',
+ errorCode: self.READY_STATE_CHANGE_ERROR.XML_HTTP_NO_REPONSE_ERROR
+ }, self._selectedRoom);
+ }
+ }, self._apiTimeout);
+ })();
};
/**
@@ -24760,8 +24756,8 @@ Skylink.prototype._parseInfo = function(info) {
// set the socket ports
this._socketPorts = {
- 'http:': info.httpPortList,
- 'https:': info.httpsPortList
+ 'http:': Array.isArray(info.httpPortList) && info.httpPortList.length > 0 ? info.httpPortList : [80, 3000],
+ 'https:': Array.isArray(info.httpsPortList) && info.httpsPortList.length > 0 ? info.httpsPortList : [443, 3443]
};
// use default bandwidth and media resolution provided by server
@@ -24926,6 +24922,7 @@ Skylink.prototype._initSelectedRoom = function(room, callback) {
audioFallback: self._audioFallback,
forceSSL: self._forceSSL,
socketTimeout: self._socketTimeout,
+ apiTimeout: self._apiTimeout,
forceTURNSSL: self._forceTURNSSL,
audioCodec: self._selectedAudioCodec,
videoCodec: self._selectedVideoCodec,
@@ -24963,7 +24960,6 @@ Skylink.prototype._initSelectedRoom = function(room, callback) {
};
-
Skylink.prototype.LOG_LEVEL = {
DEBUG: 4,
LOG: 3,
@@ -25047,6 +25043,18 @@ var _enableDebugStack = false;
*/
var _enableDebugTrace = false;
+/**
+ * Stores the flag if logs should print timestamp.
+ * @attribute _printTimestamp
+ * @type Boolean
+ * @default false
+ * @private
+ * @scoped true
+ * @for Skylink
+ * @since 0.6.26
+ */
+var _printTimestamp = false;
+
/**
* Stores the logs used for SkylinkLogs object.
* @attribute _storedLogs
@@ -25197,7 +25205,8 @@ var SkylinkLogs = {
* @since 0.5.5
*/
var _logFn = function(logLevel, message, debugObject) {
- var outputLog = _LOG_KEY;
+ var outputLog = '';
+ var datetime = (new Date());
if (typeof message === 'object') {
outputLog += (message[0]) ? ' [' + message[0] + '] -' : ' -';
@@ -25219,7 +25228,7 @@ var _logFn = function(logLevel, message, debugObject) {
if (_enableDebugMode && _enableDebugStack) {
// store the logs
- var logItem = [(new Date()), _LOG_LEVELS[logLevel], outputLog];
+ var logItem = [datetime, _LOG_LEVELS[logLevel], outputLog];
if (typeof debugObject !== 'undefined') {
logItem.push(debugObject);
@@ -25227,6 +25236,8 @@ var _logFn = function(logLevel, message, debugObject) {
_storedLogs.push(logItem);
}
+ outputLog = _LOG_KEY + (_printTimestamp ? ' :: ' + datetime.toISOString() : '') + outputLog;
+
if (_logLevel >= logLevel) {
// Fallback to log if failure
logLevel = (typeof console[_LOG_LEVELS[logLevel]] === 'undefined') ? 3 : logLevel;
@@ -25343,6 +25354,7 @@ Skylink.prototype.setLogLevel = function(logLevel) {
* will fallback to use console.log() API.
* @param {Boolean} [options.storeLogs=false] The flag if SDK should store the console logs.
* This is required to be enabled for SkylinkLogs API.
+ * @param {Boolean} [options.printTimestamp=false] The flag if SDK should print the timestamp of the console logs.
* @example
* // Example 1: Enable both options.storeLogs and options.trace
* skylinkDemo.setDebugMode(true);
@@ -25361,16 +25373,19 @@ Skylink.prototype.setDebugMode = function(isDebugMode) {
_enableDebugMode = true;
_enableDebugTrace = isDebugMode.trace === true;
_enableDebugStack = isDebugMode.storeLogs === true;
+ _printTimestamp = isDebugMode.printTimestamp === true;
// setDebugMode(true)
} else if (isDebugMode === true) {
_enableDebugMode = true;
_enableDebugTrace = true;
_enableDebugStack = true;
+ _printTimestamp = false;
// setDebugMode()
} else {
_enableDebugMode = false;
_enableDebugTrace = false;
_enableDebugStack = false;
+ _printTimestamp = false;
}
};
var _eventsDocs = {
@@ -27198,7 +27213,7 @@ Skylink.prototype._sendChannelMessage = function(message) {
* @for Skylink
* @since 0.5.10
*/
-Skylink.prototype._createSocket = function (type) {
+Skylink.prototype._createSocket = function (type, joinRoomTimestamp) {
var self = this;
var options = {
forceNew: true,
@@ -27238,7 +27253,7 @@ Skylink.prototype._createSocket = function (type) {
options.transports = ['xhr-polling', 'jsonp-polling', 'polling'];
}
- var url = self._signalingServerProtocol + '//' + self._signalingServer + ':' + self._signalingServerPort;
+ var url = self._signalingServerProtocol + '//' + self._signalingServer + ':' + self._signalingServerPort + '?rand=' + Date.now();
var retries = 0;
if (self._socketServer) {
@@ -27271,8 +27286,10 @@ Skylink.prototype._createSocket = function (type) {
log.log('Opening channel with signaling server url:', clone(self._socketSession));
+ var socket = null;
+
try {
- self._socket = io.connect(url, options);
+ socket = io.connect(url, options);
} catch (error){
log.error('Failed creating socket connection object ->', error);
if (fallbackType === self.SOCKET_FALLBACK.NON_FALLBACK) {
@@ -27285,13 +27302,13 @@ Skylink.prototype._createSocket = function (type) {
return;
}
- self._socket.on('reconnect_attempt', function (attempt) {
+ 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 () {
+ socket.on('reconnect_failed', function () {
if (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));
@@ -27301,14 +27318,14 @@ Skylink.prototype._createSocket = function (type) {
}
if (self._socketSession.finalAttempts < 2) {
- self._createSocket(type);
+ self._createSocket(type, joinRoomTimestamp);
} else {
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 () {
+ socket.on('connect', function () {
if (!self._channelOpen) {
log.log([null, 'Socket', null, 'Channel opened']);
self._channelOpen = true;
@@ -27316,7 +27333,7 @@ Skylink.prototype._createSocket = function (type) {
}
});
- self._socket.on('reconnect', function () {
+ socket.on('reconnect', function () {
if (!self._channelOpen) {
log.log([null, 'Socket', null, 'Channel opened']);
self._channelOpen = true;
@@ -27324,7 +27341,7 @@ Skylink.prototype._createSocket = function (type) {
}
});
- self._socket.on('error', function(error) {
+ socket.on('error', function(error) {
if (error ? error.message.indexOf('xhr poll error') > -1 : false) {
log.error([null, 'Socket', null, 'XHR poll connection unstable. Disconnecting.. ->'], error);
self._closeChannel();
@@ -27334,7 +27351,7 @@ Skylink.prototype._createSocket = function (type) {
self._trigger('channelError', error, clone(self._socketSession));
});
- self._socket.on('disconnect', function() {
+ socket.on('disconnect', function() {
if (self._channelOpen) {
self._channelOpen = false;
self._trigger('channelClose', clone(self._socketSession));
@@ -27347,7 +27364,7 @@ Skylink.prototype._createSocket = function (type) {
}
});
- self._socket.on('message', function(messageStr) {
+ socket.on('message', function(messageStr) {
var message = JSON.parse(messageStr);
log.log([null, 'Socket', null, 'Received message ->'], message);
@@ -27364,6 +27381,13 @@ Skylink.prototype._createSocket = function (type) {
self._trigger('channelMessage', message, clone(self._socketSession));
}
});
+
+ self._joinRoomManager.socketsFn.push(function (currentJoinRoomTimestamp) {
+ if (currentJoinRoomTimestamp !== joinRoomTimestamp) {
+ socket.disconnect();
+ }
+ });
+ self._socket = socket;
};
/**
@@ -27374,7 +27398,7 @@ Skylink.prototype._createSocket = function (type) {
* @for Skylink
* @since 0.5.5
*/
-Skylink.prototype._openChannel = function() {
+Skylink.prototype._openChannel = function(joinRoomTimestamp) {
var self = this;
if (self._channelOpen) {
log.error([null, 'Socket', null, 'Unable to instantiate a new channel connection ' +
@@ -27407,7 +27431,7 @@ Skylink.prototype._openChannel = function() {
self._signalingServerPort = null;
// Begin with a websocket connection
- self._createSocket(socketType);
+ self._createSocket(socketType, joinRoomTimestamp);
};
/**
@@ -28409,7 +28433,7 @@ 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._room.connection.peerConfig = self._setIceServers((message.pc_config || {}).iceServers || []);
self._inRoom = true;
self._user.sid = message.sid;
self._peerPriorityWeight = message.tieBreaker + (self._priorityWeightScheme === self.PRIORITY_WEIGHT_SCHEME.AUTO ?
@@ -29917,7 +29941,17 @@ Skylink.prototype.getUserMedia = function(options,callback) {
self._onStreamAccessError(error, settings, false, false);
};
- navigator.getUserMedia(settings.getUserMediaSettings, onSuccessCbFn, onErrorCbFn);
+ try {
+ if (typeof (AdapterJS || {}).webRTCReady !== 'function') {
+ return onErrorCbFn(new Error('Failed to call getUserMedia() as AdapterJS is not yet loaded!'));
+ }
+
+ AdapterJS.webRTCReady(function () {
+ navigator.getUserMedia(settings.getUserMediaSettings, onSuccessCbFn, onErrorCbFn);
+ });
+ } catch (error) {
+ onErrorCbFn(error);
+ }
}, 'getUserMedia', self._throttlingTimeouts.getUserMedia);
};
@@ -30796,8 +30830,13 @@ Skylink.prototype.shareScreen = function (enableAudio, mediaSource, callback) {
self._onStreamAccessError(error, settings, true, false);
};
- navigator.getUserMedia(settings.getUserMediaSettings, onSuccessCbFn, onErrorCbFn);
+ if (typeof (AdapterJS || {}).webRTCReady !== 'function') {
+ return onErrorCbFn(new Error('Failed to call getUserMedia() as AdapterJS is not yet loaded!'));
+ }
+ AdapterJS.webRTCReady(function () {
+ navigator.getUserMedia(settings.getUserMediaSettings, onSuccessCbFn, onErrorCbFn);
+ });
} catch (error) {
self._onStreamAccessError(error, settings, true, false);
}
diff --git a/publish/skylink.complete.min.js b/publish/skylink.complete.min.js
index 35e3025a7..ddaf6aa56 100644
--- a/publish/skylink.complete.min.js
+++ b/publish/skylink.complete.min.js
@@ -1,4 +1,4 @@
-/*! skylinkjs - v0.6.25 - 2017-09-08 */
+/*! skylinkjs - v0.6.26 - 2017-09-15 */
!function(f){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=f();else if("function"==typeof define&&define.amd)define([],f);else{var g;g="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,g.io=f()}}(function(){var define;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n||e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o0&&!this.encoding){var pack=this.packetBuffer.shift();this.packet(pack)}},Manager.prototype.cleanup=function(){debug("cleanup");for(var sub;sub=this.subs.shift();)sub.destroy();this.packetBuffer=[],this.encoding=!1,this.lastPing=null,this.decoder.destroy()},Manager.prototype.close=Manager.prototype.disconnect=function(){debug("disconnect"),this.skipReconnect=!0,this.reconnecting=!1,"opening"==this.readyState&&this.cleanup(),this.backoff.reset(),this.readyState="closed",this.engine&&this.engine.close()},Manager.prototype.onclose=function(reason){debug("onclose"),this.cleanup(),this.backoff.reset(),this.readyState="closed",this.emit("close",reason),this._reconnection&&!this.skipReconnect&&this.reconnect()},Manager.prototype.reconnect=function(){if(this.reconnecting||this.skipReconnect)return this;var self=this;if(this.backoff.attempts>=this._reconnectionAttempts)debug("reconnect failed"),this.backoff.reset(),this.emitAll("reconnect_failed"),this.reconnecting=!1;else{var delay=this.backoff.duration();debug("will wait %dms before reconnect attempt",delay),this.reconnecting=!0;var timer=setTimeout(function(){self.skipReconnect||(debug("attempting reconnect"),self.emitAll("reconnect_attempt",self.backoff.attempts),self.emitAll("reconnecting",self.backoff.attempts),self.skipReconnect||self.open(function(err){err?(debug("reconnect attempt error"),self.reconnecting=!1,self.reconnect(),self.emitAll("reconnect_error",err.data)):(debug("reconnect success"),self.onreconnect())}))},delay);this.subs.push({destroy:function(){clearTimeout(timer)}})}},Manager.prototype.onreconnect=function(){var attempt=this.backoff.attempts;this.reconnecting=!1,this.backoff.reset(),this.updateSocketIds(),this.emitAll("reconnect",attempt)}},{"./on":3,"./socket":4,backo2:8,"component-bind":11,"component-emitter":12,debug:14,"engine.io-client":16,indexof:32,"socket.io-parser":40}],3:[function(_dereq_,module,exports){function on(obj,ev,fn){return obj.on(ev,fn),{destroy:function(){obj.removeListener(ev,fn)}}}module.exports=on},{}],4:[function(_dereq_,module,exports){function Socket(io,nsp){this.io=io,this.nsp=nsp,this.json=this,this.ids=0,this.acks={},this.receiveBuffer=[],this.sendBuffer=[],this.connected=!1,this.disconnected=!0,this.io.autoConnect&&this.open()}var parser=_dereq_("socket.io-parser"),Emitter=_dereq_("component-emitter"),toArray=_dereq_("to-array"),on=_dereq_("./on"),bind=_dereq_("component-bind"),debug=_dereq_("debug")("socket.io-client:socket"),hasBin=_dereq_("has-binary");module.exports=Socket;var events={connect:1,connect_error:1,connect_timeout:1,connecting:1,disconnect:1,error:1,reconnect:1,reconnect_attempt:1,reconnect_failed:1,reconnect_error:1,reconnecting:1,ping:1,pong:1},emit=Emitter.prototype.emit;Emitter(Socket.prototype),Socket.prototype.subEvents=function(){if(!this.subs){var io=this.io;this.subs=[on(io,"open",bind(this,"onopen")),on(io,"packet",bind(this,"onpacket")),on(io,"close",bind(this,"onclose"))]}},Socket.prototype.open=Socket.prototype.connect=function(){return this.connected?this:(this.subEvents(),this.io.open(),"open"==this.io.readyState&&this.onopen(),this.emit("connecting"),this)},Socket.prototype.send=function(){var args=toArray(arguments);return args.unshift("message"),this.emit.apply(this,args),this},Socket.prototype.emit=function(ev){if(events.hasOwnProperty(ev))return emit.apply(this,arguments),this;var args=toArray(arguments),parserType=parser.EVENT;hasBin(args)&&(parserType=parser.BINARY_EVENT);var packet={type:parserType,data:args};return packet.options={},packet.options.compress=!this.flags||!1!==this.flags.compress,"function"==typeof args[args.length-1]&&(debug("emitting packet with ack id %d",this.ids),this.acks[this.ids]=args.pop(),packet.id=this.ids++),this.connected?this.packet(packet):this.sendBuffer.push(packet),delete this.flags,this},Socket.prototype.packet=function(packet){packet.nsp=this.nsp,this.io.packet(packet)},Socket.prototype.onopen=function(){debug("transport is open - connecting"),"/"!=this.nsp&&this.packet({type:parser.CONNECT})},Socket.prototype.onclose=function(reason){debug("close (%s)",reason),this.connected=!1,this.disconnected=!0,delete this.id,this.emit("disconnect",reason)},Socket.prototype.onpacket=function(packet){if(packet.nsp==this.nsp)switch(packet.type){case parser.CONNECT:this.onconnect();break;case parser.EVENT:case parser.BINARY_EVENT:this.onevent(packet);break;case parser.ACK:case parser.BINARY_ACK:this.onack(packet);break;case parser.DISCONNECT:this.ondisconnect();break;case parser.ERROR:this.emit("error",packet.data)}},Socket.prototype.onevent=function(packet){var args=packet.data||[];debug("emitting event %j",args),null!=packet.id&&(debug("attaching ack callback to event"),args.push(this.ack(packet.id))),this.connected?emit.apply(this,args):this.receiveBuffer.push(args)},Socket.prototype.ack=function(id){var self=this,sent=!1;return function(){if(!sent){sent=!0;var args=toArray(arguments);debug("sending ack %j",args);var type=hasBin(args)?parser.BINARY_ACK:parser.ACK;self.packet({type:type,id:id,data:args})}}},Socket.prototype.onack=function(packet){var ack=this.acks[packet.id];"function"==typeof ack?(debug("calling ack %s with %j",packet.id,packet.data),ack.apply(this,packet.data),delete this.acks[packet.id]):debug("bad ack %s",packet.id)},Socket.prototype.onconnect=function(){this.connected=!0,this.disconnected=!1,this.emit("connect"),this.emitBuffered()},Socket.prototype.emitBuffered=function(){var i;for(i=0;ibytes&&(end=bytes),start>=bytes||start>=end||0===bytes)return new ArrayBuffer(0);for(var abv=new Uint8Array(arraybuffer),result=new Uint8Array(end-start),i=start,ii=0;i0&&opts.jitter<=1?opts.jitter:0,this.attempts=0}module.exports=Backoff,Backoff.prototype.duration=function(){var ms=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var rand=Math.random(),deviation=Math.floor(rand*this.jitter*ms);ms=0==(1&Math.floor(10*rand))?ms-deviation:ms+deviation}return 0|Math.min(ms,this.max)},Backoff.prototype.reset=function(){this.attempts=0},Backoff.prototype.setMin=function(min){this.ms=min},Backoff.prototype.setMax=function(max){this.max=max},Backoff.prototype.setJitter=function(jitter){this.jitter=jitter}},{}],9:[function(_dereq_,module,exports){!function(){"use strict";for(var chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",lookup=new Uint8Array(256),i=0;i>2],base64+=chars[(3&bytes[i])<<4|bytes[i+1]>>4],base64+=chars[(15&bytes[i+1])<<2|bytes[i+2]>>6],base64+=chars[63&bytes[i+2]];return len%3==2?base64=base64.substring(0,base64.length-1)+"=":len%3==1&&(base64=base64.substring(0,base64.length-2)+"=="),base64},exports.decode=function(base64){var i,encoded1,encoded2,encoded3,encoded4,bufferLength=.75*base64.length,len=base64.length,p=0;"="===base64[base64.length-1]&&(bufferLength--,"="===base64[base64.length-2]&&bufferLength--);var arraybuffer=new ArrayBuffer(bufferLength),bytes=new Uint8Array(arraybuffer);for(i=0;i>4,bytes[p++]=(15&encoded2)<<4|encoded3>>2,bytes[p++]=(3&encoded3)<<6|63&encoded4;return arraybuffer}}()},{}],10:[function(_dereq_,module,exports){(function(global){function mapArrayBufferViews(ary){for(var i=0;i=31}function formatArgs(){var args=arguments,useColors=this.useColors;if(args[0]=(useColors?"%c":"")+this.namespace+(useColors?" %c":" ")+args[0]+(useColors?"%c ":" ")+"+"+exports.humanize(this.diff),!useColors)return args;var c="color: "+this.color;args=[args[0],c,"color: inherit"].concat(Array.prototype.slice.call(args,1));var index=0,lastC=0;return args[0].replace(/%[a-z%]/g,function(match){"%%"!==match&&(index++,"%c"===match&&(lastC=index))}),args.splice(lastC,0,c),args}function log(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function save(namespaces){try{null==namespaces?exports.storage.removeItem("debug"):exports.storage.debug=namespaces}catch(e){}}function load(){var r;try{r=exports.storage.debug}catch(e){}return r}function localstorage(){try{return window.localStorage}catch(e){}}exports=module.exports=_dereq_("./debug"),exports.log=log,exports.formatArgs=formatArgs,exports.save=save,exports.load=load,exports.useColors=useColors,exports.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:localstorage(),exports.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],exports.formatters.j=function(v){return JSON.stringify(v)},exports.enable(load())},{"./debug":15}],15:[function(_dereq_,module,exports){function selectColor(){return exports.colors[prevColor++%exports.colors.length]}function debug(namespace){function disabled(){}function enabled(){var self=enabled,curr=+new Date,ms=curr-(prevTime||curr);self.diff=ms,self.prev=prevTime,self.curr=curr,prevTime=curr,null==self.useColors&&(self.useColors=exports.useColors()),null==self.color&&self.useColors&&(self.color=selectColor());var args=Array.prototype.slice.call(arguments);args[0]=exports.coerce(args[0]),"string"!=typeof args[0]&&(args=["%o"].concat(args));var index=0;args[0]=args[0].replace(/%([a-z%])/g,function(match,format){if("%%"===match)return match;index++;var formatter=exports.formatters[format];if("function"==typeof formatter){var val=args[index];match=formatter.call(self,val),args.splice(index,1),index--}return match}),"function"==typeof exports.formatArgs&&(args=exports.formatArgs.apply(self,args)),(enabled.log||exports.log||console.log.bind(console)).apply(self,args)}disabled.enabled=!1,enabled.enabled=!0;var fn=exports.enabled(namespace)?enabled:disabled;return fn.namespace=namespace,fn}function enable(namespaces){exports.save(namespaces);for(var split=(namespaces||"").split(/[\s,]+/),len=split.length,i=0;i0&&(this.extraHeaders=opts.extraHeaders),this.open()}function clone(obj){var o={};for(var i in obj)obj.hasOwnProperty(i)&&(o[i]=obj[i]);return o}var transports=_dereq_("./transports"),Emitter=_dereq_("component-emitter"),debug=_dereq_("debug")("engine.io-client:socket"),index=_dereq_("indexof"),parser=_dereq_("engine.io-parser"),parseuri=_dereq_("parseuri"),parsejson=_dereq_("parsejson"),parseqs=_dereq_("parseqs");module.exports=Socket,Socket.priorWebsocketSuccess=!1,Emitter(Socket.prototype),Socket.protocol=parser.protocol,Socket.Socket=Socket,Socket.Transport=_dereq_("./transport"),Socket.transports=_dereq_("./transports"),Socket.parser=_dereq_("engine.io-parser"),Socket.prototype.createTransport=function(name){debug('creating transport "%s"',name);var query=clone(this.query);return query.EIO=parser.protocol,query.transport=name,this.id&&(query.sid=this.id),new transports[name]({agent:this.agent,hostname:this.hostname,port:this.port,secure:this.secure,path:this.path,query:query,forceJSONP:this.forceJSONP,jsonp:this.jsonp,forceBase64:this.forceBase64,enablesXDR:this.enablesXDR,timestampRequests:this.timestampRequests,timestampParam:this.timestampParam,policyPort:this.policyPort,socket:this,pfx:this.pfx,key:this.key,passphrase:this.passphrase,cert:this.cert,ca:this.ca,ciphers:this.ciphers,rejectUnauthorized:this.rejectUnauthorized,perMessageDeflate:this.perMessageDeflate,extraHeaders:this.extraHeaders})},Socket.prototype.open=function(){var transport;if(this.rememberUpgrade&&Socket.priorWebsocketSuccess&&-1!=this.transports.indexOf("websocket"))transport="websocket";else{if(0===this.transports.length){var self=this;return void setTimeout(function(){self.emit("error","No transports available")},0)}transport=this.transports[0]}this.readyState="opening";try{transport=this.createTransport(transport)}catch(e){return this.transports.shift(),void this.open()}transport.open(),this.setTransport(transport)},Socket.prototype.setTransport=function(transport){debug("setting transport %s",transport.name);var self=this;this.transport&&(debug("clearing existing transport %s",this.transport.name),this.transport.removeAllListeners()),this.transport=transport,transport.on("drain",function(){self.onDrain()}).on("packet",function(packet){self.onPacket(packet)}).on("error",function(e){self.onError(e)}).on("close",function(){self.onClose("transport close")})},Socket.prototype.probe=function(name){function onTransportOpen(){if(self.onlyBinaryUpgrades){var upgradeLosesBinary=!this.supportsBinary&&self.transport.supportsBinary;failed=failed||upgradeLosesBinary}failed||(debug('probe transport "%s" opened',name),transport.send([{type:"ping",data:"probe"}]),transport.once("packet",function(msg){if(!failed)if("pong"==msg.type&&"probe"==msg.data){if(debug('probe transport "%s" pong',name),self.upgrading=!0,self.emit("upgrading",transport),!transport)return;Socket.priorWebsocketSuccess="websocket"==transport.name,debug('pausing current transport "%s"',self.transport.name),self.transport.pause(function(){failed||"closed"!=self.readyState&&(debug("changing transport and sending upgrade packet"),cleanup(),self.setTransport(transport),transport.send([{type:"upgrade"}]),self.emit("upgrade",transport),transport=null,self.upgrading=!1,self.flush())})}else{debug('probe transport "%s" failed',name);var err=new Error("probe error");err.transport=transport.name,self.emit("upgradeError",err)}}))}function freezeTransport(){failed||(failed=!0,cleanup(),transport.close(),transport=null)}function onerror(err){var error=new Error("probe error: "+err);error.transport=transport.name,freezeTransport(),debug('probe transport "%s" failed because of error: %s',name,err),self.emit("upgradeError",error)}function onTransportClose(){onerror("transport closed")}function onclose(){onerror("socket closed")}function onupgrade(to){transport&&to.name!=transport.name&&(debug('"%s" works - aborting "%s"',to.name,transport.name),freezeTransport())}function cleanup(){transport.removeListener("open",onTransportOpen),transport.removeListener("error",onerror),transport.removeListener("close",onTransportClose),self.removeListener("close",onclose),self.removeListener("upgrading",onupgrade)}debug('probing transport "%s"',name);var transport=this.createTransport(name,{probe:1}),failed=!1,self=this;Socket.priorWebsocketSuccess=!1,transport.once("open",onTransportOpen),transport.once("error",onerror),transport.once("close",onTransportClose),this.once("close",onclose),this.once("upgrading",onupgrade),transport.open()},Socket.prototype.onOpen=function(){if(debug("socket open"),this.readyState="open",Socket.priorWebsocketSuccess="websocket"==this.transport.name,this.emit("open"),this.flush(),"open"==this.readyState&&this.upgrade&&this.transport.pause){debug("starting upgrade probes");for(var i=0,l=this.upgrades.length;i';iframe=document.createElement(html)}catch(e){iframe=document.createElement("iframe"),iframe.name=self.iframeId,iframe.src="javascript:0"}iframe.id=self.iframeId,self.form.appendChild(iframe),self.iframe=iframe}var self=this;if(!this.form){var iframe,form=document.createElement("form"),area=document.createElement("textarea"),id=this.iframeId="eio_iframe_"+this.index;form.className="socketio",form.style.position="absolute",form.style.top="-1000px",form.style.left="-1000px",form.target=id,form.method="POST",form.setAttribute("accept-charset","utf-8"),area.name="d",form.appendChild(area),document.body.appendChild(form),this.form=form,this.area=area}this.form.action=this.uri(),initIframe(),data=data.replace(rEscapedNewline,"\\\n"),this.area.value=data.replace(rNewline,"\\n");try{this.form.submit()}catch(e){}this.iframe.attachEvent?this.iframe.onreadystatechange=function(){"complete"==self.iframe.readyState&&complete()}:this.iframe.onload=complete}}).call(this,"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{})},{"./polling":23,"component-inherit":13}],22:[function(_dereq_,module,exports){(function(global){function empty(){}function XHR(opts){if(Polling.call(this,opts),global.location){var isSSL="https:"==location.protocol,port=location.port;port||(port=isSSL?443:80),this.xd=opts.hostname!=global.location.hostname||port!=opts.port,this.xs=opts.secure!=isSSL}else this.extraHeaders=opts.extraHeaders}function Request(opts){this.method=opts.method||"GET",this.uri=opts.uri,this.xd=!!opts.xd,this.xs=!!opts.xs,this.async=!1!==opts.async,this.data=void 0!=opts.data?opts.data:null,this.agent=opts.agent,this.isBinary=opts.isBinary,this.supportsBinary=opts.supportsBinary,this.enablesXDR=opts.enablesXDR,this.pfx=opts.pfx,this.key=opts.key,this.passphrase=opts.passphrase,this.cert=opts.cert,this.ca=opts.ca,this.ciphers=opts.ciphers,this.rejectUnauthorized=opts.rejectUnauthorized,this.extraHeaders=opts.extraHeaders,this.create()}function unloadHandler(){for(var i in Request.requests)Request.requests.hasOwnProperty(i)&&Request.requests[i].abort()}var XMLHttpRequest=_dereq_("xmlhttprequest-ssl"),Polling=_dereq_("./polling"),Emitter=_dereq_("component-emitter"),inherit=_dereq_("component-inherit"),debug=_dereq_("debug")("engine.io-client:polling-xhr");module.exports=XHR,module.exports.Request=Request,inherit(XHR,Polling),XHR.prototype.supportsBinary=!0,XHR.prototype.request=function(opts){return opts=opts||{},opts.uri=this.uri(),opts.xd=this.xd,opts.xs=this.xs,opts.agent=this.agent||!1,opts.supportsBinary=this.supportsBinary,opts.enablesXDR=this.enablesXDR,opts.pfx=this.pfx,opts.key=this.key,opts.passphrase=this.passphrase,opts.cert=this.cert,opts.ca=this.ca,opts.ciphers=this.ciphers,opts.rejectUnauthorized=this.rejectUnauthorized,opts.extraHeaders=this.extraHeaders,new Request(opts)},XHR.prototype.doWrite=function(data,fn){var isBinary="string"!=typeof data&&void 0!==data,req=this.request({method:"POST",data:data,isBinary:isBinary}),self=this;req.on("success",fn),req.on("error",function(err){self.onError("xhr post error",err)}),this.sendXhr=req},XHR.prototype.doPoll=function(){debug("xhr poll");var req=this.request(),self=this;req.on("data",function(data){self.onData(data)}),req.on("error",function(err){self.onError("xhr poll error",err)}),this.pollXhr=req},Emitter(Request.prototype),Request.prototype.create=function(){var opts={agent:this.agent,xdomain:this.xd,xscheme:this.xs,enablesXDR:this.enablesXDR};opts.pfx=this.pfx,opts.key=this.key,opts.passphrase=this.passphrase,opts.cert=this.cert,opts.ca=this.ca,opts.ciphers=this.ciphers,opts.rejectUnauthorized=this.rejectUnauthorized;var xhr=this.xhr=new XMLHttpRequest(opts),self=this;try{debug("xhr open %s: %s",this.method,this.uri),xhr.open(this.method,this.uri,this.async);try{if(this.extraHeaders){xhr.setDisableHeaderCheck(!0);for(var i in this.extraHeaders)this.extraHeaders.hasOwnProperty(i)&&xhr.setRequestHeader(i,this.extraHeaders[i])}}catch(e){}if(this.supportsBinary&&(xhr.responseType="arraybuffer"),"POST"==this.method)try{this.isBinary?xhr.setRequestHeader("Content-type","application/octet-stream"):xhr.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(e){}"withCredentials"in xhr&&(xhr.withCredentials=!0),this.hasXDR()?(xhr.onload=function(){self.onLoad()},xhr.onerror=function(){self.onError(xhr.responseText)}):xhr.onreadystatechange=function(){4==xhr.readyState&&(200==xhr.status||1223==xhr.status?self.onLoad():setTimeout(function(){self.onError(xhr.status)},0))},debug("xhr data %s",this.data),xhr.send(this.data)}catch(e){return void setTimeout(function(){self.onError(e)},0)}global.document&&(this.index=Request.requestsCount++,Request.requests[this.index]=this)},Request.prototype.onSuccess=function(){this.emit("success"),this.cleanup()},Request.prototype.onData=function(data){this.emit("data",data),this.onSuccess()},Request.prototype.onError=function(err){this.emit("error",err),this.cleanup(!0)},Request.prototype.cleanup=function(fromError){if(void 0!==this.xhr&&null!==this.xhr){if(this.hasXDR()?this.xhr.onload=this.xhr.onerror=empty:this.xhr.onreadystatechange=empty,fromError)try{this.xhr.abort()}catch(e){}global.document&&delete Request.requests[this.index],this.xhr=null}},Request.prototype.onLoad=function(){var data;try{var contentType;try{contentType=this.xhr.getResponseHeader("Content-Type").split(";")[0]}catch(e){}if("application/octet-stream"===contentType)data=this.xhr.response;else if(this.supportsBinary)try{data=String.fromCharCode.apply(null,new Uint8Array(this.xhr.response))}catch(e){for(var ui8Arr=new Uint8Array(this.xhr.response),dataArray=[],idx=0,length=ui8Arr.length;idx1?{type:packetslist[type],data:data.substring(1)}:{type:packetslist[type]}:err}var asArray=new Uint8Array(data),type=asArray[0],rest=sliceBuffer(data,1);return Blob&&"blob"===binaryType&&(rest=new Blob([rest])),{type:packetslist[type],data:rest}},exports.decodeBase64Packet=function(msg,binaryType){var type=packetslist[msg.charAt(0)];if(!global.ArrayBuffer)return{type:type,data:{base64:!0,data:msg.substr(1)}};var data=base64encoder.decode(msg.substr(1));return"blob"===binaryType&&Blob&&(data=new Blob([data])),{type:type,data:data}},exports.encodePayload=function(packets,supportsBinary,callback){function setLengthHeader(message){return message.length+":"+message}function encodeOne(packet,doneCallback){exports.encodePacket(packet,!!isBinary&&supportsBinary,!0,function(message){doneCallback(null,setLengthHeader(message))})}"function"==typeof supportsBinary&&(callback=supportsBinary,supportsBinary=null);var isBinary=hasBinary(packets);return supportsBinary&&isBinary?Blob&&!dontSendBlobs?exports.encodePayloadAsBlob(packets,callback):exports.encodePayloadAsArrayBuffer(packets,callback):packets.length?void map(packets,encodeOne,function(err,results){return callback(results.join(""))}):callback("0:")},exports.decodePayload=function(data,binaryType,callback){if("string"!=typeof data)return exports.decodePayloadAsBinary(data,binaryType,callback);"function"==typeof binaryType&&(callback=binaryType,binaryType=null);var packet;if(""==data)return callback(err,0,1);for(var n,msg,length="",i=0,l=data.length;i0;){for(var tailArray=new Uint8Array(bufferTail),isString=0===tailArray[0],msgLength="",i=1;255!=tailArray[i];i++){if(msgLength.length>310){numberTooLong=!0;break}msgLength+=tailArray[i]}if(numberTooLong)return callback(err,0,1);bufferTail=sliceBuffer(bufferTail,2+msgLength.length),msgLength=parseInt(msgLength);var msg=sliceBuffer(bufferTail,0,msgLength);if(isString)try{msg=String.fromCharCode.apply(null,new Uint8Array(msg))}catch(e){var typed=new Uint8Array(msg);msg="";for(var i=0;i1)))/4)-floor((year-1901+month)/100)+floor((year-1601+month)/400)};if((isProperty=objectProto.hasOwnProperty)||(isProperty=function(property){var constructor,members={};return(members.__proto__=null,members.__proto__={toString:1},members).toString!=getClass?isProperty=function(property){var original=this.__proto__,result=property in(this.__proto__=null,this);return this.__proto__=original,result}:(constructor=members.constructor,isProperty=function(property){var parent=(this.constructor||constructor).prototype;return property in this&&!(property in parent&&this[property]===parent[property])}),members=null,isProperty.call(this,property)}),forEach=function(object,callback){var Properties,members,property,size=0;(Properties=function(){this.valueOf=0}).prototype.valueOf=0,members=new Properties;for(property in members)isProperty.call(members,property)&&size++;return Properties=members=null,size?forEach=2==size?function(object,callback){var property,members={},isFunction=getClass.call(object)==functionClass;for(property in object)isFunction&&"prototype"==property||isProperty.call(members,property)||!(members[property]=1)||!isProperty.call(object,property)||callback(property)}:function(object,callback){var property,isConstructor,isFunction=getClass.call(object)==functionClass;for(property in object)isFunction&&"prototype"==property||!isProperty.call(object,property)||(isConstructor="constructor"===property)||callback(property);(isConstructor||isProperty.call(object,property="constructor"))&&callback(property)}:(members=["valueOf","toString","toLocaleString","propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"],forEach=function(object,callback){var property,length,isFunction=getClass.call(object)==functionClass,hasProperty=!isFunction&&"function"!=typeof object.constructor&&objectTypes[typeof object.hasOwnProperty]&&object.hasOwnProperty||isProperty;for(property in object)isFunction&&"prototype"==property||!hasProperty.call(object,property)||callback(property);for(length=members.length;property=members[--length];hasProperty.call(object,property)&&callback(property));}),forEach(object,callback)},!has("json-stringify")){var Escapes={92:"\\\\",34:'\\"',8:"\\b",12:"\\f",10:"\\n",13:"\\r",9:"\\t"},leadingZeroes="000000",toPaddedString=function(width,value){return(leadingZeroes+(value||0)).slice(-width)},unicodePrefix="\\u00",quote=function(value){for(var result='"',index=0,length=value.length,useCharIndex=!charIndexBuggy||length>10,symbols=useCharIndex&&(charIndexBuggy?value.split(""):value);index-1/0&&value<1/0){if(getDay){for(date=floor(value/864e5),year=floor(date/365.2425)+1970-1;getDay(year+1,0)<=date;year++);for(month=floor((date-getDay(year,0))/30.42);getDay(year,month+1)<=date;month++);date=1+date-getDay(year,month),time=(value%864e5+864e5)%864e5,hours=floor(time/36e5)%24,minutes=floor(time/6e4)%60,seconds=floor(time/1e3)%60,milliseconds=time%1e3}else year=value.getUTCFullYear(),month=value.getUTCMonth(),date=value.getUTCDate(),hours=value.getUTCHours(),minutes=value.getUTCMinutes(),seconds=value.getUTCSeconds(),milliseconds=value.getUTCMilliseconds();value=(year<=0||year>=1e4?(year<0?"-":"+")+toPaddedString(6,year<0?-year:year):toPaddedString(4,year))+"-"+toPaddedString(2,month+1)+"-"+toPaddedString(2,date)+"T"+toPaddedString(2,hours)+":"+toPaddedString(2,minutes)+":"+toPaddedString(2,seconds)+"."+toPaddedString(3,milliseconds)+"Z"}else value=null;if(callback&&(value=callback.call(object,property,value)),null===value)return"null";if((className=getClass.call(value))==booleanClass)return""+value;if(className==numberClass)return value>-1/0&&value<1/0?""+value:"null";if(className==stringClass)return quote(""+value);if("object"==typeof value){for(length=stack.length;length--;)if(stack[length]===value)throw TypeError();if(stack.push(value),results=[],prefix=indentation,indentation+=whitespace,className==arrayClass){for(index=0,length=value.length;index0)for(whitespace="",width>10&&(width=10);whitespace.length=48&&charCode<=57||charCode>=97&&charCode<=102||charCode>=65&&charCode<=70||abort();value+=fromCharCode("0x"+source.slice(begin,Index));break;default:abort()}else{if(34==charCode)break;for(charCode=source.charCodeAt(Index),begin=Index;charCode>=32&&92!=charCode&&34!=charCode;)charCode=source.charCodeAt(++Index);value+=source.slice(begin,Index)}if(34==source.charCodeAt(Index))return Index++,value;abort();default:if(begin=Index,45==charCode&&(isSigned=!0,charCode=source.charCodeAt(++Index)),charCode>=48&&charCode<=57){for(48==charCode&&(charCode=source.charCodeAt(Index+1))>=48&&charCode<=57&&abort(),isSigned=!1;Index=48&&charCode<=57;Index++);if(46==source.charCodeAt(Index)){for(position=++Index;position=48&&charCode<=57;position++);position==Index&&abort(),Index=position}if(101==(charCode=source.charCodeAt(Index))||69==charCode){for(charCode=source.charCodeAt(++Index),43!=charCode&&45!=charCode||Index++,position=Index;position=48&&charCode<=57;position++);position==Index&&abort(),Index=position}return+source.slice(begin,Index)}if(isSigned&&abort(),"true"==source.slice(Index,Index+4))return Index+=4,!0;if("false"==source.slice(Index,Index+5))return Index+=5,!1;if("null"==source.slice(Index,Index+4))return Index+=4,null;abort()}return"$"},get=function(value){var results,hasMembers;if("$"==value&&abort(),"string"==typeof value){if("@"==(charIndexBuggy?value.charAt(0):value[0]))return value.slice(1);if("["==value){for(results=[];"]"!=(value=lex());hasMembers||(hasMembers=!0))hasMembers&&(","==value?"]"==(value=lex())&&abort():abort()),","==value&&abort(),results.push(get(value));return results}if("{"==value){for(results={};"}"!=(value=lex());hasMembers||(hasMembers=!0))hasMembers&&(","==value?"}"==(value=lex())&&abort():abort()),","!=value&&"string"==typeof value&&"@"==(charIndexBuggy?value.charAt(0):value[0])&&":"==lex()||abort(),results[value.slice(1)]=get(lex());return results}abort()}return value},update=function(source,property,callback){var element=walk(source,property,callback);element===undef?delete source[property]:source[property]=element},walk=function(source,property,callback){var length,value=source[property];if("object"==typeof value&&value)if(getClass.call(value)==arrayClass)for(length=value.length;length--;)update(value,length,callback);else forEach(value,function(property){update(value,property,callback)});return callback.call(source,property,value)};exports.parse=function(source,callback){var result,value;return Index=0,Source=""+source,result=get(lex()),"$"!=lex()&&abort(),Index=Source=null,callback&&getClass.call(callback)==functionClass?walk((value={},value[""]=result,value),"",callback):result}}}return exports.runInContext=runInContext,exports}var isLoader="function"==typeof define&&define.amd,objectTypes={function:!0,object:!0},freeExports=objectTypes[typeof exports]&&exports&&!exports.nodeType&&exports,root=objectTypes[typeof window]&&window||this,freeGlobal=freeExports&&objectTypes[typeof module]&&module&&!module.nodeType&&"object"==typeof global&&global;if(!freeGlobal||freeGlobal.global!==freeGlobal&&freeGlobal.window!==freeGlobal&&freeGlobal.self!==freeGlobal||(root=freeGlobal),freeExports&&!isLoader)runInContext(root,freeExports);else{var nativeJSON=root.JSON,previousJSON=root.JSON3,isRestored=!1,JSON3=runInContext(root,root.JSON3={noConflict:function(){return isRestored||(isRestored=!0,root.JSON=nativeJSON,root.JSON3=previousJSON,nativeJSON=previousJSON=null),JSON3}});root.JSON={parse:JSON3.parse,stringify:JSON3.stringify}}isLoader&&define(function(){return JSON3})}).call(this)}).call(this,"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{})},{}],35:[function(_dereq_,module,exports){function parse(str){if(str=""+str,!(str.length>1e4)){var match=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str);if(match){var n=parseFloat(match[1]);switch((match[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return n*y;case"days":case"day":case"d":return n*d;case"hours":case"hour":case"hrs":case"hr":case"h":return n*h;case"minutes":case"minute":case"mins":case"min":case"m":return n*m;case"seconds":case"second":case"secs":case"sec":case"s":return n*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n}}}}function short(ms){return ms>=d?Math.round(ms/d)+"d":ms>=h?Math.round(ms/h)+"h":ms>=m?Math.round(ms/m)+"m":ms>=s?Math.round(ms/s)+"s":ms+"ms"}function long(ms){return plural(ms,d,"day")||plural(ms,h,"hour")||plural(ms,m,"minute")||plural(ms,s,"second")||ms+" ms"}function plural(ms,n,name){if(!(ms=55296&&value<=56319&&counter65535&&(value-=65536,output+=stringFromCharCode(value>>>10&1023|55296),value=56320|1023&value),output+=stringFromCharCode(value);return output}function checkScalarValue(codePoint){if(codePoint>=55296&&codePoint<=57343)throw Error("Lone surrogate U+"+codePoint.toString(16).toUpperCase()+" is not a scalar value")}function createByte(codePoint,shift){return stringFromCharCode(codePoint>>shift&63|128)}function encodeCodePoint(codePoint){if(0==(4294967168&codePoint))return stringFromCharCode(codePoint);var symbol="";return 0==(4294965248&codePoint)?symbol=stringFromCharCode(codePoint>>6&31|192):0==(4294901760&codePoint)?(checkScalarValue(codePoint),symbol=stringFromCharCode(codePoint>>12&15|224),symbol+=createByte(codePoint,6)):0==(4292870144&codePoint)&&(symbol=stringFromCharCode(codePoint>>18&7|240),symbol+=createByte(codePoint,12),symbol+=createByte(codePoint,6)),symbol+=stringFromCharCode(63&codePoint|128)}function utf8encode(string){for(var codePoint,codePoints=ucs2decode(string),length=codePoints.length,index=-1,byteString="";++index=byteCount)throw Error("Invalid byte index");var continuationByte=255&byteArray[byteIndex];if(byteIndex++,128==(192&continuationByte))return 63&continuationByte;throw Error("Invalid continuation byte")}function decodeSymbol(){var byte1,byte2,byte3,byte4,codePoint;if(byteIndex>byteCount)throw Error("Invalid byte index");if(byteIndex==byteCount)return!1;if(byte1=255&byteArray[byteIndex],byteIndex++,0==(128&byte1))return byte1;if(192==(224&byte1)){var byte2=readContinuationByte();if((codePoint=(31&byte1)<<6|byte2)>=128)return codePoint;throw Error("Invalid continuation byte")}if(224==(240&byte1)){if(byte2=readContinuationByte(),byte3=readContinuationByte(),(codePoint=(15&byte1)<<12|byte2<<6|byte3)>=2048)return checkScalarValue(codePoint),codePoint;throw Error("Invalid continuation byte")}if(240==(248&byte1)&&(byte2=readContinuationByte(),byte3=readContinuationByte(),byte4=readContinuationByte(),(codePoint=(15&byte1)<<18|byte2<<12|byte3<<6|byte4)>=65536&&codePoint<=1114111))return codePoint;throw Error("Invalid UTF-8 detected")}function utf8decode(byteString){byteArray=ucs2decode(byteString),byteCount=byteArray.length,byteIndex=0;for(var tmp,codePoints=[];!1!==(tmp=decodeSymbol());)codePoints.push(tmp);return ucs2encode(codePoints)}var freeExports="object"==typeof exports&&exports,freeModule="object"==typeof module&&module&&module.exports==freeExports&&module,freeGlobal="object"==typeof global&&global;freeGlobal.global!==freeGlobal&&freeGlobal.window!==freeGlobal||(root=freeGlobal);var byteArray,byteCount,byteIndex,stringFromCharCode=String.fromCharCode,utf8={version:"2.0.0",encode:utf8encode,decode:utf8decode};if("function"==typeof define&&"object"==typeof define.amd&&define.amd)define(function(){return utf8});else if(freeExports&&!freeExports.nodeType)if(freeModule)freeModule.exports=utf8;else{var object={},hasOwnProperty=object.hasOwnProperty;for(var key in utf8)hasOwnProperty.call(utf8,key)&&(freeExports[key]=utf8[key])}else root.utf8=utf8}(this)}).call(this,"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{})},{}],45:[function(_dereq_,module,exports){"use strict";function encode(num){var encoded="";do{encoded=alphabet[num%length]+encoded,num=Math.floor(num/length)}while(num>0);return encoded}function decode(str){var decoded=0;for(i=0;i0&&(console.warn("Timeout for addRemoteCandidate. Consider sending an end-of-candidates notification"),transceiver.iceTransport.addRemoteCandidate({}))})},4e3),new Promise(function(resolve){args.length>1&&"function"==typeof args[1]&&args[1].apply(null),resolve()})},RTCPeerConnection.prototype.close=function(){this.transceivers.forEach(function(transceiver){transceiver.iceTransport&&transceiver.iceTransport.stop(),transceiver.dtlsTransport&&transceiver.dtlsTransport.stop(),transceiver.rtpSender&&transceiver.rtpSender.stop(),transceiver.rtpReceiver&&transceiver.rtpReceiver.stop()}),this._updateSignalingState("closed")},RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event("signalingstatechange");this.dispatchEvent(event),null!==this.onsignalingstatechange&&this.onsignalingstatechange(event)},RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var self=this;"stable"===this.signalingState&&!0!==this.needNegotiation&&(this.needNegotiation=!0,window.setTimeout(function(){if(!1!==self.needNegotiation){self.needNegotiation=!1;var event=new Event("negotiationneeded");self.dispatchEvent(event),null!==self.onnegotiationneeded&&self.onnegotiationneeded(event)}},0))},RTCPeerConnection.prototype._updateConnectionState=function(){var newState,self=this,states={new:0,closed:0,connecting:0,checking:0,connected:0,completed:0,disconnected:0,failed:0};if(this.transceivers.forEach(function(transceiver){states[transceiver.iceTransport.state]++,states[transceiver.dtlsTransport.state]++}),states.connected+=states.completed,newState="new",states.failed>0?newState="failed":states.connecting>0||states.checking>0?newState="connecting":states.disconnected>0?newState="disconnected":states.new>0?newState="new":(states.connected>0||states.completed>0)&&(newState="connected"),newState!==self.iceConnectionState){self.iceConnectionState=newState;var event=new Event("iceconnectionstatechange");this.dispatchEvent(event),null!==this.oniceconnectionstatechange&&this.oniceconnectionstatechange(event)}},RTCPeerConnection.prototype.createOffer=function(){var offerOptions,self=this,args=arguments;1===arguments.length&&"function"!=typeof arguments[0]?offerOptions=arguments[0]:3===arguments.length&&(offerOptions=arguments[2]);var numAudioTracks=this.transceivers.filter(function(t){return"audio"===t.kind}).length,numVideoTracks=this.transceivers.filter(function(t){return"video"===t.kind}).length;if(offerOptions){if(offerOptions.mandatory||offerOptions.optional)throw new TypeError("Legacy mandatory/optional constraints not supported.");void 0!==offerOptions.offerToReceiveAudio&&(numAudioTracks=!0===offerOptions.offerToReceiveAudio?1:!1===offerOptions.offerToReceiveAudio?0:offerOptions.offerToReceiveAudio),void 0!==offerOptions.offerToReceiveVideo&&(numVideoTracks=!0===offerOptions.offerToReceiveVideo?1:!1===offerOptions.offerToReceiveVideo?0:offerOptions.offerToReceiveVideo)}for(this.transceivers.forEach(function(transceiver){"audio"===transceiver.kind?--numAudioTracks<0&&(transceiver.wantReceive=!1):"video"===transceiver.kind&&--numVideoTracks<0&&(transceiver.wantReceive=!1)});numAudioTracks>0||numVideoTracks>0;)numAudioTracks>0&&(this._createTransceiver("audio"),numAudioTracks--),numVideoTracks>0&&(this._createTransceiver("video"),numVideoTracks--);var sdp=SDPUtils.writeSessionBoilerplate(this._sdpSessionId,this._sdpSessionVersion++);this.transceivers.forEach(function(transceiver,sdpMLineIndex){var track=transceiver.track,kind=transceiver.kind,mid=SDPUtils.generateIdentifier();transceiver.mid=mid,transceiver.iceGatherer||(transceiver.iceGatherer=self._createIceGatherer(sdpMLineIndex,self.usingBundle));var localCapabilities=window.RTCRtpSender.getCapabilities(kind);edgeVersion<15019&&(localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return"rtx"!==codec.name})),localCapabilities.codecs.forEach(function(codec){"H264"===codec.name&&void 0===codec.parameters["level-asymmetry-allowed"]&&(codec.parameters["level-asymmetry-allowed"]="1")});var sendEncodingParameters=[{ssrc:1001*(2*sdpMLineIndex+1)}];track&&edgeVersion>=15019&&"video"===kind&&(sendEncodingParameters[0].rtx={ssrc:1001*(2*sdpMLineIndex+1)+1}),transceiver.wantReceive&&(transceiver.rtpReceiver=new window.RTCRtpReceiver(transceiver.dtlsTransport,kind)),transceiver.localCapabilities=localCapabilities,transceiver.sendEncodingParameters=sendEncodingParameters}),"max-compat"!==this._config.bundlePolicy&&(sdp+="a=group:BUNDLE "+this.transceivers.map(function(t){return t.mid}).join(" ")+"\r\n"),sdp+="a=ice-options:trickle\r\n",this.transceivers.forEach(function(transceiver,sdpMLineIndex){sdp+=writeMediaSection(transceiver,transceiver.localCapabilities,"offer",transceiver.stream),sdp+="a=rtcp-rsize\r\n",!transceiver.iceGatherer||"new"===self.iceGatheringState||0!==sdpMLineIndex&&self.usingBundle||(transceiver.iceGatherer.getLocalCandidates().forEach(function(cand){cand.component=1,sdp+="a="+SDPUtils.writeCandidate(cand)+"\r\n"}),"completed"===transceiver.iceGatherer.state&&(sdp+="a=end-of-candidates\r\n"))});var desc=new window.RTCSessionDescription({type:"offer",sdp:sdp});return new Promise(function(resolve){if(args.length>0&&"function"==typeof args[0])return args[0].apply(null,[desc]),void resolve();resolve(desc)})},RTCPeerConnection.prototype.createAnswer=function(){var args=arguments,sdp=SDPUtils.writeSessionBoilerplate(this._sdpSessionId,this._sdpSessionVersion++);this.usingBundle&&(sdp+="a=group:BUNDLE "+this.transceivers.map(function(t){return t.mid}).join(" ")+"\r\n");var mediaSectionsInOffer=SDPUtils.splitSections(this.remoteDescription.sdp).length-1;this.transceivers.forEach(function(transceiver,sdpMLineIndex){if(!(sdpMLineIndex+1>mediaSectionsInOffer)){if(transceiver.isDatachannel)return void(sdp+="m=application 0 DTLS/SCTP 5000\r\nc=IN IP4 0.0.0.0\r\na=mid:"+transceiver.mid+"\r\n");if(transceiver.stream){var localTrack;"audio"===transceiver.kind?localTrack=transceiver.stream.getAudioTracks()[0]:"video"===transceiver.kind&&(localTrack=transceiver.stream.getVideoTracks()[0]),localTrack&&edgeVersion>=15019&&"video"===transceiver.kind&&(transceiver.sendEncodingParameters[0].rtx={ssrc:1001*(2*sdpMLineIndex+2)+1})}var commonCapabilities=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);!commonCapabilities.codecs.filter(function(c){return"rtx"===c.name.toLowerCase()}).length&&transceiver.sendEncodingParameters[0].rtx&&delete transceiver.sendEncodingParameters[0].rtx,sdp+=writeMediaSection(transceiver,commonCapabilities,"answer",transceiver.stream),transceiver.rtcpParameters&&transceiver.rtcpParameters.reducedSize&&(sdp+="a=rtcp-rsize\r\n")}});var desc=new window.RTCSessionDescription({type:"answer",sdp:sdp});return new Promise(function(resolve){if(args.length>0&&"function"==typeof args[0])return args[0].apply(null,[desc]),void resolve();resolve(desc)})},RTCPeerConnection.prototype.addIceCandidate=function(candidate){var err,sections;if(candidate&&""!==candidate.candidate){if(!candidate.sdpMLineIndex&&!candidate.sdpMid)throw new TypeError("sdpMLineIndex or sdpMid required");if(this.remoteDescription){var sdpMLineIndex=candidate.sdpMLineIndex;if(candidate.sdpMid)for(var i=0;i0?SDPUtils.parseCandidate(candidate.candidate):{};if("tcp"===cand.protocol&&(0===cand.port||9===cand.port))return Promise.resolve();if(cand.component&&1!==cand.component)return Promise.resolve();(0===sdpMLineIndex||sdpMLineIndex>0&&transceiver.iceTransport!==this.transceivers[0].iceTransport)&&transceiver.iceTransport.addRemoteCandidate(cand);var candidateString=candidate.candidate.trim();0===candidateString.indexOf("a=")&&(candidateString=candidateString.substr(2)),sections=SDPUtils.splitSections(this.remoteDescription.sdp),sections[sdpMLineIndex+1]+="a="+(cand.type?candidateString:"end-of-candidates")+"\r\n",this.remoteDescription.sdp=sections.join("")}else err=new Error("Can not add ICE candidate"),err.name="OperationError"}else err=new Error("Can not add ICE candidate without a remote description"),err.name="InvalidStateError"}else for(var j=0;j2&&"function"==typeof args[2]&&args[2].apply(null,[err]),reject(err)):(args.length>1&&"function"==typeof args[1]&&args[1].apply(null),resolve())})},RTCPeerConnection.prototype.getStats=function(){var promises=[];this.transceivers.forEach(function(transceiver){["rtpSender","rtpReceiver","iceGatherer","iceTransport","dtlsTransport"].forEach(function(method){transceiver[method]&&promises.push(transceiver[method].getStats())})});var cb=arguments.length>1&&"function"==typeof arguments[1]&&arguments[1],fixStatsType=function(stat){return{inboundrtp:"inbound-rtp",outboundrtp:"outbound-rtp",candidatepair:"candidate-pair",localcandidate:"local-candidate",remotecandidate:"remote-candidate"}[stat.type]||stat.type};return new Promise(function(resolve){var results=new Map;Promise.all(promises).then(function(res){res.forEach(function(result){Object.keys(result).forEach(function(id){result[id].type=fixStatsType(result[id]),results.set(id,result[id])})}),cb&&cb.apply(null,results),resolve(results)})})},RTCPeerConnection}},{sdp:2}],2:[function(requirecopy,module,exports){"use strict";var SDPUtils={};SDPUtils.generateIdentifier=function(){return Math.random().toString(36).substr(2,10)},SDPUtils.localCName=SDPUtils.generateIdentifier(),SDPUtils.splitLines=function(blob){return blob.trim().split("\n").map(function(line){return line.trim()})},SDPUtils.splitSections=function(blob){return blob.split("\nm=").map(function(part,index){return(index>0?"m="+part:part).trim()+"\r\n"})},SDPUtils.matchPrefix=function(blob,prefix){return SDPUtils.splitLines(blob).filter(function(line){return 0===line.indexOf(prefix)})},SDPUtils.parseCandidate=function(line){var parts;parts=0===line.indexOf("a=candidate:")?line.substring(12).split(" "):line.substring(10).split(" ");for(var candidate={foundation:parts[0],component:parseInt(parts[1],10),protocol:parts[2].toLowerCase(),priority:parseInt(parts[3],10),ip:parts[4],port:parseInt(parts[5],10),type:parts[7]},i=8;i0?parts[0].split("/")[1]:"sendrecv",uri:parts[1]}},SDPUtils.writeExtmap=function(headerExtension){return"a=extmap:"+(headerExtension.id||headerExtension.preferredId)+(headerExtension.direction&&"sendrecv"!==headerExtension.direction?"/"+headerExtension.direction:"")+" "+headerExtension.uri+"\r\n"},SDPUtils.parseFmtp=function(line){for(var kv,parsed={},parts=line.substr(line.indexOf(" ")+1).split(";"),j=0;j-1?(parts.attribute=line.substr(sp+1,colon-sp-1),parts.value=line.substr(colon+1)):parts.attribute=line.substr(sp+1),parts},SDPUtils.getMid=function(mediaSection){var mid=SDPUtils.matchPrefix(mediaSection,"a=mid:")[0];if(mid)return mid.substr(6)},SDPUtils.parseFingerprint=function(line){var parts=line.substr(14).split(" ");return{algorithm:parts[0].toLowerCase(),value:parts[1]}},SDPUtils.getDtlsParameters=function(mediaSection,sessionpart){return{role:"auto",fingerprints:SDPUtils.matchPrefix(mediaSection+sessionpart,"a=fingerprint:").map(SDPUtils.parseFingerprint)}},SDPUtils.writeDtlsParameters=function(params,setupType){var sdp="a=setup:"+setupType+"\r\n";return params.fingerprints.forEach(function(fp){sdp+="a=fingerprint:"+fp.algorithm+" "+fp.value+"\r\n"}),sdp},SDPUtils.getIceParameters=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);return lines=lines.concat(SDPUtils.splitLines(sessionpart)),{usernameFragment:lines.filter(function(line){return 0===line.indexOf("a=ice-ufrag:")})[0].substr(12),password:lines.filter(function(line){return 0===line.indexOf("a=ice-pwd:")})[0].substr(10)}},SDPUtils.writeIceParameters=function(params){return"a=ice-ufrag:"+params.usernameFragment+"\r\na=ice-pwd:"+params.password+"\r\n"},SDPUtils.parseRtpParameters=function(mediaSection){for(var description={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]},lines=SDPUtils.splitLines(mediaSection),mline=lines[0].split(" "),i=3;i0?"9":"0",sdp+=" UDP/TLS/RTP/SAVPF ",sdp+=caps.codecs.map(function(codec){return void 0!==codec.preferredPayloadType?codec.preferredPayloadType:codec.payloadType}).join(" ")+"\r\n",sdp+="c=IN IP4 0.0.0.0\r\n",sdp+="a=rtcp:9 IN IP4 0.0.0.0\r\n",caps.codecs.forEach(function(codec){sdp+=SDPUtils.writeRtpMap(codec),sdp+=SDPUtils.writeFmtp(codec),sdp+=SDPUtils.writeRtcpFb(codec)});var maxptime=0;return caps.codecs.forEach(function(codec){codec.maxptime>maxptime&&(maxptime=codec.maxptime)}),maxptime>0&&(sdp+="a=maxptime:"+maxptime+"\r\n"),sdp+="a=rtcp-mux\r\n",caps.headerExtensions.forEach(function(extension){sdp+=SDPUtils.writeExtmap(extension)}),sdp},SDPUtils.parseRtpEncodingParameters=function(mediaSection){var secondarySsrc,encodingParameters=[],description=SDPUtils.parseRtpParameters(mediaSection),hasRed=-1!==description.fecMechanisms.indexOf("RED"),hasUlpfec=-1!==description.fecMechanisms.indexOf("ULPFEC"),ssrcs=SDPUtils.matchPrefix(mediaSection,"a=ssrc:").map(function(line){return SDPUtils.parseSsrcMedia(line)}).filter(function(parts){return"cname"===parts.attribute}),primarySsrc=ssrcs.length>0&&ssrcs[0].ssrc,flows=SDPUtils.matchPrefix(mediaSection,"a=ssrc-group:FID").map(function(line){var parts=line.split(" ");return parts.shift(),parts.map(function(part){return parseInt(part,10)})});flows.length>0&&flows[0].length>1&&flows[0][0]===primarySsrc&&(secondarySsrc=flows[0][1]),description.codecs.forEach(function(codec){if("RTX"===codec.name.toUpperCase()&&codec.parameters.apt){var encParam={ssrc:primarySsrc,codecPayloadType:parseInt(codec.parameters.apt,10),rtx:{ssrc:secondarySsrc}};encodingParameters.push(encParam),hasRed&&(encParam=JSON.parse(JSON.stringify(encParam)),encParam.fec={ssrc:secondarySsrc,mechanism:hasUlpfec?"red+ulpfec":"red"},encodingParameters.push(encParam))}}),0===encodingParameters.length&&primarySsrc&&encodingParameters.push({ssrc:primarySsrc});var bandwidth=SDPUtils.matchPrefix(mediaSection,"b=");return bandwidth.length&&(bandwidth=0===bandwidth[0].indexOf("b=TIAS:")?parseInt(bandwidth[0].substr(7),10):0===bandwidth[0].indexOf("b=AS:")?1e3*parseInt(bandwidth[0].substr(5),10)*.95-16e3:void 0,encodingParameters.forEach(function(params){params.maxBitrate=bandwidth})),encodingParameters},SDPUtils.parseRtcpParameters=function(mediaSection){var rtcpParameters={},remoteSsrc=SDPUtils.matchPrefix(mediaSection,"a=ssrc:").map(function(line){return SDPUtils.parseSsrcMedia(line)}).filter(function(obj){return"cname"===obj.attribute})[0];remoteSsrc&&(rtcpParameters.cname=remoteSsrc.value,rtcpParameters.ssrc=remoteSsrc.ssrc);var rsize=SDPUtils.matchPrefix(mediaSection,"a=rtcp-rsize");rtcpParameters.reducedSize=rsize.length>0,rtcpParameters.compound=0===rsize.length;var mux=SDPUtils.matchPrefix(mediaSection,"a=rtcp-mux");return rtcpParameters.mux=mux.length>0,rtcpParameters},SDPUtils.parseMsid=function(mediaSection){var parts,spec=SDPUtils.matchPrefix(mediaSection,"a=msid:");if(1===spec.length)return parts=spec[0].substr(7).split(" "),{stream:parts[0],track:parts[1]};var planB=SDPUtils.matchPrefix(mediaSection,"a=ssrc:").map(function(line){return SDPUtils.parseSsrcMedia(line)}).filter(function(parts){return"msid"===parts.attribute});return planB.length>0?(parts=planB[0].value.split(" "),{stream:parts[0],track:parts[1]}):void 0},SDPUtils.generateSessionId=function(){return Math.random().toString().substr(2,21)},SDPUtils.writeSessionBoilerplate=function(sessId,sessVer){var version=void 0!==sessVer?sessVer:2;return"v=0\r\no=thisisadapterortc "+(sessId||SDPUtils.generateSessionId())+" "+version+" IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},SDPUtils.writeMediaSection=function(transceiver,caps,type,stream){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);if(sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters()),sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),"offer"===type?"actpass":"active"),sdp+="a=mid:"+transceiver.mid+"\r\n",transceiver.direction?sdp+="a="+transceiver.direction+"\r\n":transceiver.rtpSender&&transceiver.rtpReceiver?sdp+="a=sendrecv\r\n":transceiver.rtpSender?sdp+="a=sendonly\r\n":transceiver.rtpReceiver?sdp+="a=recvonly\r\n":sdp+="a=inactive\r\n",transceiver.rtpSender){var msid="msid:"+stream.id+" "+transceiver.rtpSender.track.id+"\r\n";sdp+="a="+msid,sdp+="a=ssrc:"+transceiver.sendEncodingParameters[0].ssrc+" "+msid,transceiver.sendEncodingParameters[0].rtx&&(sdp+="a=ssrc:"+transceiver.sendEncodingParameters[0].rtx.ssrc+" "+msid,sdp+="a=ssrc-group:FID "+transceiver.sendEncodingParameters[0].ssrc+" "+transceiver.sendEncodingParameters[0].rtx.ssrc+"\r\n")}return sdp+="a=ssrc:"+transceiver.sendEncodingParameters[0].ssrc+" cname:"+SDPUtils.localCName+"\r\n",transceiver.rtpSender&&transceiver.sendEncodingParameters[0].rtx&&(sdp+="a=ssrc:"+transceiver.sendEncodingParameters[0].rtx.ssrc+" cname:"+SDPUtils.localCName+"\r\n"),sdp},SDPUtils.getDirection=function(mediaSection,sessionpart){for(var lines=SDPUtils.splitLines(mediaSection),i=0;i0&&"function"==typeof selector)return origGetStats.apply(this,arguments);if(0===origGetStats.length&&(0===arguments.length||"function"!=typeof arguments[0]))return origGetStats.apply(this,[]);var fixChromeStats_=function(response){var standardReport={};return response.result().forEach(function(report){var standardStats={id:report.id,timestamp:report.timestamp,type:{localcandidate:"local-candidate",remotecandidate:"remote-candidate"}[report.type]||report.type};report.names().forEach(function(name){standardStats[name]=report.stat(name)}),standardReport[standardStats.id]=standardStats}),standardReport},makeMapStats=function(stats){return new Map(Object.keys(stats).map(function(key){return[key,stats[key]]}))};if(arguments.length>=2){var successCallbackWrapper_=function(response){args[1](makeMapStats(fixChromeStats_(response)))};return origGetStats.apply(this,[successCallbackWrapper_,arguments[0]])}return new Promise(function(resolve,reject){origGetStats.apply(self,[function(response){resolve(makeMapStats(fixChromeStats_(response)))},reject])}).then(successCallback,errorCallback)},browserDetails.version<51&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){var args=arguments,self=this,promise=new Promise(function(resolve,reject){nativeMethod.apply(self,[args[0],resolve,reject])});return args.length<2?promise:promise.then(function(){args[1].apply(null,[])},function(err){args.length>=3&&args[2].apply(null,[err])})}}),browserDetails.version<52&&["createOffer","createAnswer"].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){var self=this;if(arguments.length<1||1===arguments.length&&"object"==typeof arguments[0]){var opts=1===arguments.length?arguments[0]:void 0;return new Promise(function(resolve,reject){nativeMethod.apply(self,[resolve,reject,opts])})}return nativeMethod.apply(this,arguments)}}),["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){return arguments[0]=new("addIceCandidate"===method?window.RTCIceCandidate:window.RTCSessionDescription)(arguments[0]),nativeMethod.apply(this,arguments)}});var nativeAddIceCandidate=window.RTCPeerConnection.prototype.addIceCandidate;window.RTCPeerConnection.prototype.addIceCandidate=function(){return arguments[0]?nativeAddIceCandidate.apply(this,arguments):(arguments[1]&&arguments[1].apply(null),Promise.resolve())}}};module.exports={shimMediaStream:chromeShim.shimMediaStream,shimOnTrack:chromeShim.shimOnTrack,shimAddTrackRemoveTrack:chromeShim.shimAddTrackRemoveTrack,shimGetSendersWithDtmf:chromeShim.shimGetSendersWithDtmf,shimSourceObject:chromeShim.shimSourceObject,shimPeerConnection:chromeShim.shimPeerConnection,shimGetUserMedia:requirecopy("./getusermedia")}},{"../utils.js":13,"./getusermedia":6}],6:[function(requirecopy,module,exports){"use strict";var utils=requirecopy("../utils.js"),logging=utils.log;module.exports=function(window){var browserDetails=utils.detectBrowser(window),navigator=window&&window.navigator,constraintsToChrome_=function(c){if("object"!=typeof c||c.mandatory||c.optional)return c;var cc={};return Object.keys(c).forEach(function(key){if("require"!==key&&"advanced"!==key&&"mediaSource"!==key){var r="object"==typeof c[key]?c[key]:{ideal:c[key]};void 0!==r.exact&&"number"==typeof r.exact&&(r.min=r.max=r.exact);var oldname_=function(prefix,name){return prefix?prefix+name.charAt(0).toUpperCase()+name.slice(1):"deviceId"===name?"sourceId":name};if(void 0!==r.ideal){cc.optional=cc.optional||[];var oc={};"number"==typeof r.ideal?(oc[oldname_("min",key)]=r.ideal,cc.optional.push(oc),oc={},oc[oldname_("max",key)]=r.ideal,cc.optional.push(oc)):(oc[oldname_("",key)]=r.ideal,cc.optional.push(oc))}void 0!==r.exact&&"number"!=typeof r.exact?(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname_("",key)]=r.exact):["min","max"].forEach(function(mix){void 0!==r[mix]&&(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname_(mix,key)]=r[mix])})}}),c.advanced&&(cc.optional=(cc.optional||[]).concat(c.advanced)),cc},shimConstraints_=function(constraints,func){if((constraints=JSON.parse(JSON.stringify(constraints)))&&"object"==typeof constraints.audio){var remap=function(obj,a,b){a in obj&&!(b in obj)&&(obj[b]=obj[a],delete obj[a])};constraints=JSON.parse(JSON.stringify(constraints)),remap(constraints.audio,"autoGainControl","googAutoGainControl"),remap(constraints.audio,"noiseSuppression","googNoiseSuppression"),constraints.audio=constraintsToChrome_(constraints.audio)}if(constraints&&"object"==typeof constraints.video){var face=constraints.video.facingMode;face=face&&("object"==typeof face?face:{ideal:face});var getSupportedFacingModeLies=browserDetails.version<61;if(face&&("user"===face.exact||"environment"===face.exact||"user"===face.ideal||"environment"===face.ideal)&&(!navigator.mediaDevices.getSupportedConstraints||!navigator.mediaDevices.getSupportedConstraints().facingMode||getSupportedFacingModeLies)){delete constraints.video.facingMode;var matches;if("environment"===face.exact||"environment"===face.ideal?matches=["back","rear"]:"user"!==face.exact&&"user"!==face.ideal||(matches=["front"]),matches)return navigator.mediaDevices.enumerateDevices().then(function(devices){devices=devices.filter(function(d){return"videoinput"===d.kind});var dev=devices.find(function(d){return matches.some(function(match){return-1!==d.label.toLowerCase().indexOf(match)})});return!dev&&devices.length&&-1!==matches.indexOf("back")&&(dev=devices[devices.length-1]),dev&&(constraints.video.deviceId=face.exact?{exact:dev.deviceId}:{ideal:dev.deviceId}),constraints.video=constraintsToChrome_(constraints.video),logging("chrome: "+JSON.stringify(constraints)),func(constraints)})}constraints.video=constraintsToChrome_(constraints.video)}return logging("chrome: "+JSON.stringify(constraints)),func(constraints)},shimError_=function(e){return{name:{PermissionDeniedError:"NotAllowedError",InvalidStateError:"NotReadableError",DevicesNotFoundError:"NotFoundError",ConstraintNotSatisfiedError:"OverconstrainedError",TrackStartError:"NotReadableError",MediaDeviceFailedDueToShutdown:"NotReadableError",MediaDeviceKillSwitchOn:"NotReadableError"}[e.name]||e.name,message:e.message,constraint:e.constraintName,toString:function(){return this.name+(this.message&&": ")+this.message}}},getUserMedia_=function(constraints,onSuccess,onError){shimConstraints_(constraints,function(c){navigator.webkitGetUserMedia(c,onSuccess,function(e){onError&&onError(shimError_(e))})})};navigator.getUserMedia=getUserMedia_;var getUserMediaPromise_=function(constraints){return new Promise(function(resolve,reject){navigator.getUserMedia(constraints,resolve,reject)})};if(navigator.mediaDevices||(navigator.mediaDevices={getUserMedia:getUserMediaPromise_,enumerateDevices:function(){return new Promise(function(resolve){var kinds={audio:"audioinput",video:"videoinput"};return window.MediaStreamTrack.getSources(function(devices){resolve(devices.map(function(device){return{label:device.label,kind:kinds[device.kind],deviceId:device.id,groupId:""}}))})})},getSupportedConstraints:function(){return{deviceId:!0,echoCancellation:!0,facingMode:!0,frameRate:!0,height:!0,width:!0}}}),navigator.mediaDevices.getUserMedia){var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(cs){return shimConstraints_(cs,function(c){return origGetUserMedia(c).then(function(stream){if(c.audio&&!stream.getAudioTracks().length||c.video&&!stream.getVideoTracks().length)throw stream.getTracks().forEach(function(track){track.stop()}),new DOMException("","NotFoundError");return stream},function(e){return Promise.reject(shimError_(e))})})}}else navigator.mediaDevices.getUserMedia=function(constraints){return getUserMediaPromise_(constraints)};void 0===navigator.mediaDevices.addEventListener&&(navigator.mediaDevices.addEventListener=function(){logging("Dummy mediaDevices.addEventListener called.")}),void 0===navigator.mediaDevices.removeEventListener&&(navigator.mediaDevices.removeEventListener=function(){logging("Dummy mediaDevices.removeEventListener called.")})}},{"../utils.js":13}],7:[function(requirecopy,module,exports){"use strict";function wrapPeerConnectionEvent(window,eventNameToWrap,wrapper){if(window.RTCPeerConnection){var proto=window.RTCPeerConnection.prototype,nativeAddEventListener=proto.addEventListener;proto.addEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap)return nativeAddEventListener.apply(this,arguments);var wrappedCallback=function(e){cb(wrapper(e))};return this._eventMap=this._eventMap||{},this._eventMap[cb]=wrappedCallback,nativeAddEventListener.apply(this,[nativeEventName,wrappedCallback])};var nativeRemoveEventListener=proto.removeEventListener;proto.removeEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap||!this._eventMap||!this._eventMap[cb])return nativeRemoveEventListener.apply(this,arguments);var unwrappedCb=this._eventMap[cb];return delete this._eventMap[cb],nativeRemoveEventListener.apply(this,[nativeEventName,unwrappedCb])},Object.defineProperty(proto,"on"+eventNameToWrap,{get:function(){return this["_on"+eventNameToWrap]},set:function(cb){this["_on"+eventNameToWrap]&&(this.removeEventListener(eventNameToWrap,this["_on"+eventNameToWrap]),delete this["_on"+eventNameToWrap]),cb&&this.addEventListener(eventNameToWrap,this["_on"+eventNameToWrap]=cb)}})}}var SDPUtils=requirecopy("sdp");module.exports={shimRTCIceCandidate:function(window){if(!(window.RTCIceCandidate&&"foundation"in window.RTCIceCandidate.prototype)){var NativeRTCIceCandidate=window.RTCIceCandidate;window.RTCIceCandidate=function(args){"object"==typeof args&&args.candidate&&0===args.candidate.indexOf("a=")&&(args=JSON.parse(JSON.stringify(args)),args.candidate=args.candidate.substr(2));var nativeCandidate=new NativeRTCIceCandidate(args),parsedCandidate=SDPUtils.parseCandidate(args.candidate),augmentedCandidate=Object.assign(nativeCandidate,parsedCandidate);return augmentedCandidate.toJSON=function(){return{candidate:augmentedCandidate.candidate,sdpMid:augmentedCandidate.sdpMid,sdpMLineIndex:augmentedCandidate.sdpMLineIndex,usernameFragment:augmentedCandidate.usernameFragment}},augmentedCandidate},wrapPeerConnectionEvent(window,"icecandidate",function(e){return e.candidate&&Object.defineProperty(e,"candidate",{value:new window.RTCIceCandidate(e.candidate),writable:"false"}),e})}}}},{sdp:2}],8:[function(requirecopy,module,exports){"use strict";var utils=requirecopy("../utils"),shimRTCPeerConnection=requirecopy("rtcpeerconnection-shim");module.exports={shimGetUserMedia:requirecopy("./getusermedia"),shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if(window.RTCIceGatherer&&(window.RTCIceCandidate||(window.RTCIceCandidate=function(args){return args}),window.RTCSessionDescription||(window.RTCSessionDescription=function(args){return args}),browserDetails.version<15025)){var origMSTEnabled=Object.getOwnPropertyDescriptor(window.MediaStreamTrack.prototype,"enabled");Object.defineProperty(window.MediaStreamTrack.prototype,"enabled",{set:function(value){origMSTEnabled.set.call(this,value);var ev=new Event("enabled");ev.enabled=value,this.dispatchEvent(ev)}})}!window.RTCRtpSender||"dtmf"in window.RTCRtpSender.prototype||Object.defineProperty(window.RTCRtpSender.prototype,"dtmf",{get:function(){return void 0===this._dtmf&&("audio"===this.track.kind?this._dtmf=new window.RTCDtmfSender(this):"video"===this.track.kind&&(this._dtmf=null)),this._dtmf}}),window.RTCPeerConnection=shimRTCPeerConnection(window,browserDetails.version)},shimReplaceTrack:function(window){!window.RTCRtpSender||"replaceTrack"in window.RTCRtpSender.prototype||(window.RTCRtpSender.prototype.replaceTrack=window.RTCRtpSender.prototype.setTrack)}}},{"../utils":13,"./getusermedia":9,"rtcpeerconnection-shim":1}],9:[function(requirecopy,module,exports){"use strict";module.exports=function(window){var navigator=window&&window.navigator,shimError_=function(e){return{name:{PermissionDeniedError:"NotAllowedError"}[e.name]||e.name,message:e.message,constraint:e.constraint,toString:function(){return this.name}}},origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e))})}}},{}],10:[function(requirecopy,module,exports){"use strict";var utils=requirecopy("../utils"),firefoxShim={shimOnTrack:function(window){"object"!=typeof window||!window.RTCPeerConnection||"ontrack"in window.RTCPeerConnection.prototype||Object.defineProperty(window.RTCPeerConnection.prototype,"ontrack",{get:function(){return this._ontrack},set:function(f){this._ontrack&&(this.removeEventListener("track",this._ontrack),this.removeEventListener("addstream",this._ontrackpoly)),this.addEventListener("track",this._ontrack=f),this.addEventListener("addstream",this._ontrackpoly=function(e){e.stream.getTracks().forEach(function(track){var event=new Event("track");event.track=track,event.receiver={track:track},event.transceiver={receiver:event.receiver},event.streams=[e.stream],this.dispatchEvent(event)}.bind(this))}.bind(this))}}),"object"==typeof window&&window.RTCPeerConnection&&"receiver"in window.RTCTrackEvent.prototype&&!("transceiver"in window.RTCTrackEvent.prototype)&&Object.defineProperty(window.RTCTrackEvent.prototype,"transceiver",{get:function(){return{receiver:this.receiver}}})},shimSourceObject:function(window){"object"==typeof window&&(!window.HTMLMediaElement||"srcObject"in window.HTMLMediaElement.prototype||Object.defineProperty(window.HTMLMediaElement.prototype,"srcObject",{get:function(){return this.mozSrcObject},set:function(stream){this.mozSrcObject=stream}}))},shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if("object"==typeof window&&(window.RTCPeerConnection||window.mozRTCPeerConnection)){window.RTCPeerConnection||(window.RTCPeerConnection=function(pcConfig,pcConstraints){if(browserDetails.version<38&&pcConfig&&pcConfig.iceServers){for(var newIceServers=[],i=0;i55&&"autoGainControl"in navigator.mediaDevices.getSupportedConstraints())){var remap=function(obj,a,b){a in obj&&!(b in obj)&&(obj[b]=obj[a],delete obj[a])},nativeGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);if(navigator.mediaDevices.getUserMedia=function(c){return"object"==typeof c&&"object"==typeof c.audio&&(c=JSON.parse(JSON.stringify(c)),remap(c.audio,"autoGainControl","mozAutoGainControl"),remap(c.audio,"noiseSuppression","mozNoiseSuppression")),nativeGetUserMedia(c)},MediaStreamTrack&&MediaStreamTrack.prototype.getSettings){var nativeGetSettings=MediaStreamTrack.prototype.getSettings;MediaStreamTrack.prototype.getSettings=function(){var obj=nativeGetSettings.apply(this,arguments);return remap(obj,"mozAutoGainControl","autoGainControl"),remap(obj,"mozNoiseSuppression","noiseSuppression"),obj}}if(MediaStreamTrack&&MediaStreamTrack.prototype.applyConstraints){var nativeApplyConstraints=MediaStreamTrack.prototype.applyConstraints;MediaStreamTrack.prototype.applyConstraints=function(c){return"audio"===this.kind&&"object"==typeof c&&(c=JSON.parse(JSON.stringify(c)),remap(c,"autoGainControl","mozAutoGainControl"),remap(c,"noiseSuppression","mozNoiseSuppression")),nativeApplyConstraints.apply(this,[c])}}}navigator.getUserMedia=function(constraints,onSuccess,onError){if(browserDetails.version<44)return getUserMedia_(constraints,onSuccess,onError);utils.deprecated("navigator.getUserMedia","navigator.mediaDevices.getUserMedia"),navigator.mediaDevices.getUserMedia(constraints).then(onSuccess,onError)}}},{"../utils":13}],12:[function(requirecopy,module,exports){"use strict";var utils=requirecopy("../utils"),safariShim={shimLocalStreamsAPI:function(window){if("object"==typeof window&&window.RTCPeerConnection){if("getLocalStreams"in window.RTCPeerConnection.prototype||(window.RTCPeerConnection.prototype.getLocalStreams=function(){return this._localStreams||(this._localStreams=[]),this._localStreams}),"getStreamById"in window.RTCPeerConnection.prototype||(window.RTCPeerConnection.prototype.getStreamById=function(id){var result=null;return this._localStreams&&this._localStreams.forEach(function(stream){stream.id===id&&(result=stream)}),this._remoteStreams&&this._remoteStreams.forEach(function(stream){stream.id===id&&(result=stream)}),result}),!("addStream"in window.RTCPeerConnection.prototype)){var _addTrack=window.RTCPeerConnection.prototype.addTrack;window.RTCPeerConnection.prototype.addStream=function(stream){this._localStreams||(this._localStreams=[]),-1===this._localStreams.indexOf(stream)&&this._localStreams.push(stream);var self=this;stream.getTracks().forEach(function(track){_addTrack.call(self,track,stream)})},window.RTCPeerConnection.prototype.addTrack=function(track,stream){stream&&(this._localStreams?-1===this._localStreams.indexOf(stream)&&this._localStreams.push(stream):this._localStreams=[stream]),_addTrack.call(this,track,stream)}}"removeStream"in window.RTCPeerConnection.prototype||(window.RTCPeerConnection.prototype.removeStream=function(stream){this._localStreams||(this._localStreams=[]);var index=this._localStreams.indexOf(stream);if(-1!==index){this._localStreams.splice(index,1);var self=this,tracks=stream.getTracks();this.getSenders().forEach(function(sender){-1!==tracks.indexOf(sender.track)&&self.removeTrack(sender)})}})}},shimRemoteStreamsAPI:function(window){"object"==typeof window&&window.RTCPeerConnection&&("getRemoteStreams"in window.RTCPeerConnection.prototype||(window.RTCPeerConnection.prototype.getRemoteStreams=function(){return this._remoteStreams?this._remoteStreams:[]}),"onaddstream"in window.RTCPeerConnection.prototype||Object.defineProperty(window.RTCPeerConnection.prototype,"onaddstream",{get:function(){return this._onaddstream},set:function(f){this._onaddstream&&(this.removeEventListener("addstream",this._onaddstream),this.removeEventListener("track",this._onaddstreampoly)),this.addEventListener("addstream",this._onaddstream=f),this.addEventListener("track",this._onaddstreampoly=function(e){var stream=e.streams[0];if(this._remoteStreams||(this._remoteStreams=[]),!(this._remoteStreams.indexOf(stream)>=0)){this._remoteStreams.push(stream);var event=new Event("addstream");event.stream=e.streams[0],this.dispatchEvent(event)}}.bind(this))}}))},shimCallbacksAPI:function(window){if("object"==typeof window&&window.RTCPeerConnection){var prototype=window.RTCPeerConnection.prototype,createOffer=prototype.createOffer,createAnswer=prototype.createAnswer,setLocalDescription=prototype.setLocalDescription,setRemoteDescription=prototype.setRemoteDescription,addIceCandidate=prototype.addIceCandidate;prototype.createOffer=function(successCallback,failureCallback){
var options=arguments.length>=2?arguments[2]:arguments[0],promise=createOffer.apply(this,[options]);return failureCallback?(promise.then(successCallback,failureCallback),Promise.resolve()):promise},prototype.createAnswer=function(successCallback,failureCallback){var options=arguments.length>=2?arguments[2]:arguments[0],promise=createAnswer.apply(this,[options]);return failureCallback?(promise.then(successCallback,failureCallback),Promise.resolve()):promise};var withCallback=function(description,successCallback,failureCallback){var promise=setLocalDescription.apply(this,[description]);return failureCallback?(promise.then(successCallback,failureCallback),Promise.resolve()):promise};prototype.setLocalDescription=withCallback,withCallback=function(description,successCallback,failureCallback){var promise=setRemoteDescription.apply(this,[description]);return failureCallback?(promise.then(successCallback,failureCallback),Promise.resolve()):promise},prototype.setRemoteDescription=withCallback,withCallback=function(candidate,successCallback,failureCallback){var promise=addIceCandidate.apply(this,[candidate]);return failureCallback?(promise.then(successCallback,failureCallback),Promise.resolve()):promise},prototype.addIceCandidate=withCallback}},shimGetUserMedia:function(window){var navigator=window&&window.navigator;navigator.getUserMedia||(navigator.webkitGetUserMedia?navigator.getUserMedia=navigator.webkitGetUserMedia.bind(navigator):navigator.mediaDevices&&navigator.mediaDevices.getUserMedia&&(navigator.getUserMedia=function(constraints,cb,errcb){navigator.mediaDevices.getUserMedia(constraints).then(cb,errcb)}.bind(navigator)))},shimRTCIceServerUrls:function(window){var OrigPeerConnection=window.RTCPeerConnection;window.RTCPeerConnection=function(pcConfig,pcConstraints){if(pcConfig&&pcConfig.iceServers){for(var newIceServers=[],i=0;i=pos&&parseInt(match[pos],10)},detectBrowser:function(window){var navigator=window&&window.navigator,result={};if(result.browser=null,result.version=null,void 0===window||!window.navigator)return result.browser="Not a browser.",result;if(navigator.mozGetUserMedia)result.browser="firefox",result.version=this.extractVersion(navigator.userAgent,/Firefox\/(\d+)\./,1);else if(navigator.webkitGetUserMedia)if(window.webkitRTCPeerConnection)result.browser="chrome",result.version=this.extractVersion(navigator.userAgent,/Chrom(e|ium)\/(\d+)\./,2);else{if(!navigator.userAgent.match(/Version\/(\d+).(\d+)/))return result.browser="Unsupported webkit-based browser with GUM support but no WebRTC support.",result;result.browser="safari",result.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/(\d+)\./,1)}else if(navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))result.browser="edge",result.version=this.extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2);else{if(!navigator.mediaDevices||!navigator.userAgent.match(/AppleWebKit\/(\d+)\./))return result.browser="Not a supported browser.",result;result.browser="safari",result.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/(\d+)\./,1)}return result},shimCreateObjectURL:function(window){var URL=window&&window.URL;if("object"==typeof window&&window.HTMLMediaElement&&"srcObject"in window.HTMLMediaElement.prototype&&URL.createObjectURL&&URL.revokeObjectURL){var nativeCreateObjectURL=URL.createObjectURL.bind(URL),nativeRevokeObjectURL=URL.revokeObjectURL.bind(URL),streams=new Map,newId=0;URL.createObjectURL=function(stream){if("getTracks"in stream){var url="polyblob:"+ ++newId;return streams.set(url,stream),utils.deprecated("URL.createObjectURL(stream)","elem.srcObject = stream"),url}return nativeCreateObjectURL(stream)},URL.revokeObjectURL=function(url){nativeRevokeObjectURL(url),streams.delete(url)};var dsc=Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype,"src");Object.defineProperty(window.HTMLMediaElement.prototype,"src",{get:function(){return dsc.get.apply(this)},set:function(url){return this.srcObject=streams.get(url)||null,dsc.set.apply(this,[url])}});var nativeSetAttribute=window.HTMLMediaElement.prototype.setAttribute;window.HTMLMediaElement.prototype.setAttribute=function(){return 2===arguments.length&&"src"===(""+arguments[0]).toLowerCase()&&(this.srcObject=streams.get(arguments[1])||null),nativeSetAttribute.apply(this,arguments)}}}};module.exports={log:utils.log,deprecated:utils.deprecated,disableLog:utils.disableLog,disableWarnings:utils.disableWarnings,extractVersion:utils.extractVersion,shimCreateObjectURL:utils.shimCreateObjectURL,detectBrowser:utils.detectBrowser.bind(utils)}},{}]},{},[3])(3)}),navigator.mozGetUserMedia?(MediaStreamTrack.getSources=function(successCb){setTimeout(function(){successCb([{kind:"audio",id:"default",label:"",facing:""},{kind:"video",id:"default",label:"",facing:""}])},0)},attachMediaStream=function(element,stream){return element.srcObject=stream,element},reattachMediaStream=function(to,from){return to.srcObject=from.srcObject,to},createIceServer=function(url,username,password){console.warn("createIceServer is deprecated. It should be replaced with an application level implementation.");var iceServer=null,urlParts=url.split(":");if(0===urlParts[0].indexOf("stun"))iceServer={urls:[url]};else if(0===urlParts[0].indexOf("turn"))if(AdapterJS.webrtcDetectedVersion<27){var turnUrlParts=url.split("?");1!==turnUrlParts.length&&0!==turnUrlParts[1].indexOf("transport=udp")||(iceServer={urls:[turnUrlParts[0]],credential:password,username:username})}else iceServer={urls:[url],credential:password,username:username};return iceServer},createIceServers=function(urls,username,password){console.warn("createIceServers is deprecated. It should be replaced with an application level implementation.");var iceServers=[];for(i=0;i=43?element.srcObject=stream:void 0!==element.src?element.src=URL.createObjectURL(stream):console.error("Error attaching stream to element."),element},reattachMediaStream=function(to,from){return AdapterJS.webrtcDetectedVersion>=43?to.srcObject=from.srcObject:to.src=from.src,to},createIceServer=function(url,username,password){console.warn("createIceServer is deprecated. It should be replaced with an application level implementation.");var iceServer=null,urlParts=url.split(":");return 0===urlParts[0].indexOf("stun")?iceServer={url:url}:0===urlParts[0].indexOf("turn")&&(iceServer={url:url,credential:password,username:username}),iceServer},createIceServers=function(urls,username,password){console.warn("createIceServers is deprecated. It should be replaced with an application level implementation.");var iceServers=[];if(AdapterJS.webrtcDetectedVersion>=34)iceServers={urls:urls,credential:password,username:username};else for(i=0;i38?element.srcObject=stream:void 0!==element.src&&(element.src=URL.createObjectURL(stream))}),attachMediaStream=function(element,stream){return"chrome"!==AdapterJS.webrtcDetectedBrowser&&"opera"!==AdapterJS.webrtcDetectedBrowser||stream?attachMediaStream_base(element,stream):element.src="",element},reattachMediaStream_base=reattachMediaStream,reattachMediaStream=function(to,from){return reattachMediaStream_base(to,from),to},window.attachMediaStream=attachMediaStream,window.reattachMediaStream=reattachMediaStream,window.getUserMedia=function(constraints,onSuccess,onFailure){navigator.getUserMedia(constraints,onSuccess,onFailure)},AdapterJS.attachMediaStream=attachMediaStream,AdapterJS.reattachMediaStream=reattachMediaStream,AdapterJS.getUserMedia=getUserMedia,"undefined"==typeof Promise&&(requestUserMedia=null),AdapterJS.maybeThroughWebRTCReady()):("object"==typeof console&&"function"==typeof console.log||(console={}||console,console.log=function(arg){},console.info=function(arg){},console.error=function(arg){},console.dir=function(arg){},console.exception=function(arg){},console.trace=function(arg){},console.warn=function(arg){},console.count=function(arg){},console.debug=function(arg){},console.count=function(arg){},console.time=function(arg){},console.timeEnd=function(arg){},console.group=function(arg){},console.groupCollapsed=function(arg){},console.groupEnd=function(arg){}),AdapterJS.WebRTCPlugin.WaitForPluginReady=function(){for(;AdapterJS.WebRTCPlugin.pluginState!==AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY;);},AdapterJS.WebRTCPlugin.callWhenPluginReady=function(callback){if(AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY)callback();else var checkPluginReadyState=setInterval(function(){AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY&&(clearInterval(checkPluginReadyState),callback())},100)},AdapterJS.WebRTCPlugin.setLogLevel=function(logLevel){AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){AdapterJS.WebRTCPlugin.plugin.setLogLevel(logLevel)})},AdapterJS.WebRTCPlugin.injectPlugin=function(){if(("interactive"===document.readyState||"complete"===document.readyState)&&AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING){if(AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTING,"IE"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion<=10){var frag=document.createDocumentFragment();for(AdapterJS.WebRTCPlugin.plugin=document.createElement("div"),AdapterJS.WebRTCPlugin.plugin.innerHTML='";AdapterJS.WebRTCPlugin.plugin.firstChild;)frag.appendChild(AdapterJS.WebRTCPlugin.plugin.firstChild);document.body.appendChild(frag),AdapterJS.WebRTCPlugin.plugin=document.getElementById(AdapterJS.WebRTCPlugin.pluginInfo.pluginId)}else AdapterJS.WebRTCPlugin.plugin=document.createElement("object"),AdapterJS.WebRTCPlugin.plugin.id=AdapterJS.WebRTCPlugin.pluginInfo.pluginId,"IE"===AdapterJS.webrtcDetectedBrowser?(AdapterJS.WebRTCPlugin.plugin.width="1px",AdapterJS.WebRTCPlugin.plugin.height="1px"):(AdapterJS.WebRTCPlugin.plugin.width="0px",AdapterJS.WebRTCPlugin.plugin.height="0px"),AdapterJS.WebRTCPlugin.plugin.type=AdapterJS.WebRTCPlugin.pluginInfo.type,AdapterJS.WebRTCPlugin.plugin.innerHTML=' '+(AdapterJS.options.getAllCams?'':"")+'',document.body.appendChild(AdapterJS.WebRTCPlugin.plugin);AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTED}},AdapterJS.WebRTCPlugin.isPluginInstalled=function(comName,plugName,plugType,installedCb,notInstalledCb){if("IE"!==AdapterJS.webrtcDetectedBrowser){for(var pluginArray=navigator.mimeTypes,i=0;i=0)return void installedCb();notInstalledCb()}else{try{new ActiveXObject(comName+"."+plugName)}catch(e){return void notInstalledCb()}installedCb()}},AdapterJS.WebRTCPlugin.defineWebRTCInterface=function(){if(AdapterJS.WebRTCPlugin.pluginState===AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY)return void console.error("AdapterJS - WebRTC interface has already been defined");AdapterJS.WebRTCPlugin.pluginState=AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING,AdapterJS.isDefined=function(variable){return null!==variable&&void 0!==variable},createIceServer=function(url,username,password){var iceServer=null,urlParts=url.split(":");return 0===urlParts[0].indexOf("stun")?iceServer={url:url,hasCredentials:!1}:0===urlParts[0].indexOf("turn")&&(iceServer={url:url,hasCredentials:!0,credential:password,username:username}),iceServer},createIceServers=function(urls,username,password){for(var iceServers=[],i=0;i1)return iceServers&&(servers.iceServers=iceServers),AdapterJS.WebRTCPlugin.plugin.PeerConnection(servers);var mandatory=constraints&&constraints.mandatory?constraints.mandatory:null,optional=constraints&&constraints.optional?constraints.optional:null;return AdapterJS.WebRTCPlugin.plugin.PeerConnection(AdapterJS.WebRTCPlugin.pageId,iceServers,mandatory,optional)},MediaStreamTrack=function(){},MediaStreamTrack.getSources=function(callback){AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){AdapterJS.WebRTCPlugin.plugin.GetSources(callback)})};var constraintsToPlugin=function(c){if("object"!=typeof c||c.mandatory||c.optional)return c;var cc={};return Object.keys(c).forEach(function(key){if("require"!==key&&"advanced"!==key){if("string"==typeof c[key])return void(cc[key]=c[key]);var r="object"==typeof c[key]?c[key]:{ideal:c[key]};void 0!==r.exact&&"number"==typeof r.exact&&(r.min=r.max=r.exact);var oldname=function(prefix,name){return prefix?prefix+name.charAt(0).toUpperCase()+name.slice(1):"deviceId"===name?"sourceId":name};if("sourceId"===oldname("",key)&&void 0!==r.exact&&(r.ideal=r.exact,r.exact=void 0),void 0!==r.ideal){cc.optional=cc.optional||[];var oc={};"number"==typeof r.ideal?(oc[oldname("min",key)]=r.ideal,cc.optional.push(oc),oc={},oc[oldname("max",key)]=r.ideal,cc.optional.push(oc)):(oc[oldname("",key)]=r.ideal,cc.optional.push(oc))}void 0!==r.exact&&"number"!=typeof r.exact?(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname("",key)]=r.exact):["min","max"].forEach(function(mix){void 0!==r[mix]&&(cc.mandatory=cc.mandatory||{},cc.mandatory[oldname(mix,key)]=r[mix])})}}),c.advanced&&(cc.optional=(cc.optional||[]).concat(c.advanced)),cc};getUserMedia=function(constraints,successCallback,failureCallback){var cc={};cc.audio=!!constraints.audio&&constraintsToPlugin(constraints.audio),cc.video=!!constraints.video&&constraintsToPlugin(constraints.video),AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){AdapterJS.WebRTCPlugin.plugin.getUserMedia(cc,successCallback,failureCallback)})},window.navigator.getUserMedia=getUserMedia,"undefined"!=typeof Promise&&(requestUserMedia=function(constraints){return new Promise(function(resolve,reject){try{getUserMedia(constraints,resolve,reject)}catch(error){reject(error)}})},navigator.mediaDevices={getUserMedia:requestUserMedia,enumerateDevices:function(){return new Promise(function(resolve){var kinds={audio:"audioinput",video:"videoinput"};return MediaStreamTrack.getSources(function(devices){resolve(devices.map(function(device){return{label:device.label,kind:kinds[device.kind],id:device.id,deviceId:device.id,groupId:""}}))})})}}),attachMediaStream=function(element,stream){if(element&&element.parentNode){var streamId;null===stream?streamId="":(void 0!==stream.enableSoundTracks&&stream.enableSoundTracks(!0),streamId=stream.id);var elementId=0===element.id.length?Math.random().toString(36).slice(2):element.id,nodeName=element.nodeName.toLowerCase();if("object"!==nodeName){var tag;switch(nodeName){case"audio":tag=AdapterJS.WebRTCPlugin.TAGS.AUDIO;break;case"video":tag=AdapterJS.WebRTCPlugin.TAGS.VIDEO;break;default:tag=AdapterJS.WebRTCPlugin.TAGS.NONE}var frag=document.createDocumentFragment(),temp=document.createElement("div"),classHTML="";for(element.className?classHTML='class="'+element.className+'" ':element.attributes&&element.attributes.class&&(classHTML='class="'+element.attributes.class.value+'" '),temp.innerHTML='';temp.firstChild;)frag.appendChild(temp.firstChild);var height="",width="";element.clientWidth||element.clientHeight?(width=element.clientWidth,height=element.clientHeight):(element.width||element.height)&&(width=element.width,height=element.height),element.parentNode.insertBefore(frag,element),frag=document.getElementById(elementId),frag.width=width,frag.height=height,element.parentNode.removeChild(element)}else{for(var children=element.children,i=0;i!==children.length;++i)if("streamId"===children[i].name){children[i].value=streamId;break}element.setStreamId(streamId)}var newElement=document.getElementById(elementId);return AdapterJS.forwardEventHandlers(newElement,element,Object.getPrototypeOf(element)),newElement}},reattachMediaStream=function(to,from){for(var stream=null,children=from.children,i=0;i!==children.length;++i)if("streamId"===children[i].name){AdapterJS.WebRTCPlugin.WaitForPluginReady(),stream=AdapterJS.WebRTCPlugin.plugin.getStreamWithId(AdapterJS.WebRTCPlugin.pageId,children[i].value);break}if(null!==stream)return attachMediaStream(to,stream);console.log("Could not find the stream associated with this element")},window.attachMediaStream=attachMediaStream,window.reattachMediaStream=reattachMediaStream,window.getUserMedia=getUserMedia,AdapterJS.attachMediaStream=attachMediaStream,AdapterJS.reattachMediaStream=reattachMediaStream,AdapterJS.getUserMedia=getUserMedia,AdapterJS.forwardEventHandlers=function(destElem,srcElem,prototype){var properties=Object.getOwnPropertyNames(prototype);for(var prop in properties)if(prop){var propName=properties[prop];"function"==typeof propName.slice&&"on"===propName.slice(0,2)&&"function"==typeof srcElem[propName]&&AdapterJS.addEvent(destElem,propName.slice(2),srcElem[propName])}var subPrototype=Object.getPrototypeOf(prototype);subPrototype&&AdapterJS.forwardEventHandlers(destElem,srcElem,subPrototype)},RTCIceCandidate=function(candidate){return candidate.sdpMid||(candidate.sdpMid=""),AdapterJS.WebRTCPlugin.WaitForPluginReady(),AdapterJS.WebRTCPlugin.plugin.ConstructIceCandidate(candidate.sdpMid,candidate.sdpMLineIndex,candidate.candidate)},AdapterJS.addEvent(document,"readystatechange",AdapterJS.WebRTCPlugin.injectPlugin),AdapterJS.WebRTCPlugin.injectPlugin()},AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb=AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb||function(){AdapterJS.addEvent(document,"readystatechange",AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCbPriv),AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCbPriv()},AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCbPriv=function(){if(!AdapterJS.options.hidePluginInstallPrompt){var downloadLink=AdapterJS.WebRTCPlugin.pluginInfo.downloadLink;if(downloadLink){var popupString;popupString=AdapterJS.WebRTCPlugin.pluginInfo.portalLink?'This website requires you to install the '+AdapterJS.WebRTCPlugin.pluginInfo.companyName+" WebRTC Plugin to work on this browser.":AdapterJS.TEXT.PLUGIN.REQUIRE_INSTALLATION,AdapterJS.renderNotificationBar(popupString,AdapterJS.TEXT.PLUGIN.BUTTON,function(){window.open(downloadLink,"_top");var pluginInstallInterval=setInterval(function(){"IE"!==AdapterJS.webrtcDetectedBrowser&&navigator.plugins.refresh(!1),AdapterJS.WebRTCPlugin.isPluginInstalled(AdapterJS.WebRTCPlugin.pluginInfo.prefix,AdapterJS.WebRTCPlugin.pluginInfo.plugName,AdapterJS.WebRTCPlugin.pluginInfo.type,function(){clearInterval(pluginInstallInterval),AdapterJS.WebRTCPlugin.defineWebRTCInterface()},function(){})},500)})}else AdapterJS.renderNotificationBar(AdapterJS.TEXT.PLUGIN.NOT_SUPPORTED)}},AdapterJS.WebRTCPlugin.isPluginInstalled(AdapterJS.WebRTCPlugin.pluginInfo.prefix,AdapterJS.WebRTCPlugin.pluginInfo.plugName,AdapterJS.WebRTCPlugin.pluginInfo.type,AdapterJS.WebRTCPlugin.defineWebRTCInterface,AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb)),"undefined"!=typeof exports&&(module.exports=AdapterJS),AdapterJS.TEXT.EXTENSION={REQUIRE_INSTALLATION_FF:"To enable screensharing you need to install the Skylink WebRTC tools Firefox Add-on.",REQUIRE_INSTALLATION_CHROME:"To enable screensharing you need to install the Skylink WebRTC tools Chrome Extension.",REQUIRE_REFRESH:"Please refresh this page after the Skylink WebRTC tools extension has been installed.",BUTTON_FF:"Install Now",BUTTON_CHROME:"Go to Chrome Web Store"},AdapterJS.extensionInfo=AdapterJS.extensionInfo||{chrome:{extensionId:"ljckddiekopnnjoeaiofddfhgnbdoafc",extensionLink:"https://chrome.google.com/webstore/detail/skylink-webrtc-tools/ljckddiekopnnjoeaiofddfhgnbdoafc",iframeLink:"https://cdn.temasys.com.sg/skylink/extensions/detectRTC.html"},firefox:{extensionLink:"https://addons.mozilla.org/en-US/firefox/addon/skylink-webrtc-tools/"},opera:{extensionId:null,extensionLink:null}},AdapterJS._mediaSourcePolyfillIsDefined=!1,AdapterJS._defineMediaSourcePolyfill=function(){if(!AdapterJS._mediaSourcePolyfillIsDefined){AdapterJS._mediaSourcePolyfillIsDefined=!0;var baseGetUserMedia=null,clone=function(obj){if(null===obj||"object"!=typeof obj)return obj;var copy=obj.constructor();for(var attr in obj)obj.hasOwnProperty(attr)&&(copy[attr]=obj[attr]);return copy},checkIfConstraintsIsValid=function(constraints,successCb,failureCb){if(!constraints||"object"!=typeof constraints)throw new Error("GetUserMedia: (constraints, .., ..) argument required");if("function"!=typeof successCb)throw new Error("GetUserMedia: (.., successCb, ..) argument required");if("function"!=typeof failureCb)throw new Error("GetUserMedia: (.., .., failureCb) argument required")};if("moz"===AdapterJS.webrtcDetectedType)baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(checkIfConstraintsIsValid(constraints,successCb,failureCb),constraints.video&&"object"==typeof constraints.video&&constraints.video.hasOwnProperty("mediaSource")){var updatedConstraints=clone(constraints),mediaSourcesList=["screen","window","application","browser","camera"],useExtensionErrors=["NotAllowedError","PermissionDeniedError","SecurityError"];if(Array.isArray(updatedConstraints.video.mediaSource)){for(var i=0;i-1){updatedConstraints.video.mediaSource=updatedConstraints.video.mediaSource[i];break}i++}updatedConstraints.video.mediaSource="string"==typeof updatedConstraints.video.mediaSource?updatedConstraints.video.mediaSource:null}if(-1===mediaSourcesList.indexOf(updatedConstraints.video.mediaSource))return void failureCb(new Error('GetUserMedia: Only "screen" and "window" are supported as mediaSource constraints'));var checkIfReady=setInterval(function(){"complete"===document.readyState&&(clearInterval(checkIfReady),updatedConstraints.video.mozMediaSource=updatedConstraints.video.mediaSource,baseGetUserMedia(updatedConstraints,successCb,function(error){useExtensionErrors.indexOf(error.name)>-1&&AdapterJS.webrtcDetectedVersion<52&&"https:"===window.parent.location.protocol?AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_FF,AdapterJS.TEXT.EXTENSION.BUTTON_FF,function(e){window.open(AdapterJS.extensionInfo.firefox.extensionLink,"_blank"),e.target&&e.target.parentElement&&e.target.nextElementSibling&&e.target.nextElementSibling.click&&e.target.nextElementSibling.click(),AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION?AdapterJS.TEXT.EXTENSION.REQUIRE_REFRESH:AdapterJS.TEXT.REFRESH.REQUIRE_REFRESH,AdapterJS.TEXT.REFRESH.BUTTON,function(){window.open("javascript:location.reload()","_top")})}):failureCb(error)}))},1)}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=window.getUserMedia=navigator.getUserMedia;else if("webkit"===AdapterJS.webrtcDetectedType){baseGetUserMedia=window.navigator.getUserMedia;var iframe=document.createElement("iframe");if(navigator.getUserMedia=function(constraints,successCb,failureCb){if(checkIfConstraintsIsValid(constraints,successCb,failureCb),constraints.video&&"object"==typeof constraints.video&&constraints.video.hasOwnProperty("mediaSource")){var updatedConstraints=clone(constraints),mediaSourcesList=["window","screen","tab","audio"];if(navigator.userAgent.toLowerCase().indexOf("android")>-1)return void((Array.isArray(updatedConstraints.video.mediaSource)?updatedConstraints.video.mediaSource.indexOf("screen")>-1:"screen"===updatedConstraints.video.mediaSource)?(updatedConstraints.video.mandatory=updatedConstraints.video.mandatory||{},updatedConstraints.video.mandatory.chromeMediaSource="screen",updatedConstraints.video.mandatory.maxHeight=window.screen.height,updatedConstraints.video.mandatory.maxWidth=window.screen.width,delete updatedConstraints.video.mediaSource,baseGetUserMedia(updatedConstraints,successCb,failureCb)):failureCb(new Error('GetUserMedia: Only "screen" are supported as mediaSource constraints for Android')));if(!("opera"===AdapterJS.webrtcDetectedBrowser?!!AdapterJS.extensionInfo.opera.extensionId:"chrome"===AdapterJS.webrtcDetectedBrowser))return void failureCb(new Error("Current browser does not support screensharing"));if("string"==typeof updatedConstraints.video.mediaSource&&mediaSourcesList.indexOf(updatedConstraints.video.mediaSource)>-1&&"audio"!==updatedConstraints.video.mediaSource)updatedConstraints.video.mediaSource=[updatedConstraints.video.mediaSource];else if(Array.isArray(updatedConstraints.video.mediaSource)){for(var i=0,outputMediaSource=[];i-1&&-1===updatedConstraints.video.mediaSource.indexOf("tab"))return void failureCb(new Error('GetUserMedia: "audio" mediaSource must be provided with ["audio", "tab"]'));if(0===updatedConstraints.video.mediaSource.length)return void failureCb(new Error('GetUserMedia: Only "screen", "window", "tab" are supported as mediaSource constraints'));updatedConstraints.video.mediaSource.indexOf("tab")>-1&&updatedConstraints.video.mediaSource.indexOf("audio")>-1&&!updatedConstraints.audio&&console.warn('Audio must be requested if "tab" and "audio" mediaSource constraints is requested');var fetchStream=function(response){response.success?(updatedConstraints.video.mandatory=updatedConstraints.video.mandatory||{},updatedConstraints.video.mandatory.chromeMediaSource="desktop",updatedConstraints.video.mandatory.maxWidth=window.screen.width>1920?window.screen.width:1920,updatedConstraints.video.mandatory.maxHeight=window.screen.height>1080?window.screen.height:1080,
-updatedConstraints.video.mandatory.chromeMediaSourceId=response.sourceId,Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("tab")>-1&&updatedConstraints.video.mediaSource.indexOf("audio")>-1&&updatedConstraints.audio&&(updatedConstraints.audio="object"==typeof updatedConstraints.audio?updatedConstraints.audio:{},updatedConstraints.audio.mandatory=updatedConstraints.audio.mandatory||{},updatedConstraints.audio.mandatory.chromeMediaSource="desktop",updatedConstraints.audio.mandatory.chromeMediaSourceId=response.sourceId),delete updatedConstraints.video.mediaSource,baseGetUserMedia(updatedConstraints,successCb,failureCb)):(response.extensionLink&&AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_CHROME,AdapterJS.TEXT.EXTENSION.BUTTON_CHROME,function(e){window.open(response.extensionLink,"_blank"),e.target&&e.target.parentElement&&e.target.nextElementSibling&&e.target.nextElementSibling.click&&e.target.nextElementSibling.click(),AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION?AdapterJS.TEXT.EXTENSION.REQUIRE_REFRESH:AdapterJS.TEXT.REFRESH.REQUIRE_REFRESH,AdapterJS.TEXT.REFRESH.BUTTON,function(){window.open("javascript:location.reload()","_top")})}),failureCb(response.error))};if(AdapterJS.extensionInfo.chrome.iframeLink&&"opera"!==AdapterJS.webrtcDetectedBrowser)iframe.getSourceId(updatedConstraints.video.mediaSource,fetchStream);else{var extensionId=AdapterJS.extensionInfo["opera"===AdapterJS.webrtcDetectedBrowser?"opera":"chrome"].extensionId,extensionLink=AdapterJS.extensionInfo["opera"===AdapterJS.webrtcDetectedBrowser?"opera":"chrome"].extensionLink,icon=document.createElement("img");icon.src="chrome-extension://"+extensionId+"/icon.png",icon.onload=function(){chrome.runtime.sendMessage(extensionId,{type:"get-version"},function(versionRes){if(!versionRes||"object"!=typeof versionRes||"send-version"!==versionRes.type)return void fetchStream({success:!1,error:new Error("Extension is disabled")});chrome.runtime.sendMessage(extensionId,{type:"get-source",sources:updatedConstraints.video.mediaSource},function(sourceRes){fetchStream(sourceRes&&"object"==typeof sourceRes?"send-source-error"===sourceRes.type?{success:!1,error:new Error("Permission denied for screen retrieval")}:{success:!0,sourceId:sourceRes.sourceId}:{success:!1,error:new Error("Retrieval failed")})})})},icon.onerror=function(){fetchStream({success:!1,error:new Error("Extension not installed"),extensionLink:extensionLink})}}}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=window.getUserMedia=navigator.getUserMedia,navigator.mediaDevices.getUserMedia=function(constraints){return new Promise(function(resolve,reject){try{window.getUserMedia(constraints,resolve,reject)}catch(error){reject(error)}})},"chrome"===AdapterJS.webrtcDetectedBrowser){var states={loaded:!1,error:!1};if(iframe)try{(document.body||document.documentElement).removeChild(iframe)}catch(e){}if(!AdapterJS.extensionInfo.chrome.iframeLink)return;iframe.onload=function(){states.loaded=!0},iframe.onerror=function(){states.error=!0},iframe.src=AdapterJS.extensionInfo.chrome.iframeLink,iframe.style.display="none";var getSourceIdFromIFrame=function(sources,cb){window.addEventListener("message",function iframeListener(evt){window.removeEventListener("message",iframeListener),cb(evt.data?"not-installed"===evt.data.chromeExtensionStatus?{success:!1,error:new Error("Extension is not installed"),extensionLink:evt.data.data||AdapterJS.extensionInfo.chrome.extensionLink}:"installed-disabled"===evt.data.chromeExtensionStatus?{success:!1,error:new Error("Extension is disabled")}:"PermissionDeniedError"===evt.data.chromeMediaSourceId?{success:!1,error:new Error("Permission denied for screen retrieval")}:evt.data.chromeMediaSourceId&&"string"==typeof evt.data.chromeMediaSourceId?{success:!0,sourceId:evt.data.chromeMediaSourceId}:{success:!1,error:new Error("Failed retrieving selected screen")}:{success:!1,error:new Error("Failed retrieving response")})}),iframe.contentWindow.postMessage({captureSourceId:!0,sources:sources,legacy:!0,extensionId:AdapterJS.extensionInfo.chrome.extensionId,extensionLink:AdapterJS.extensionInfo.chrome.extensionLink},"*")};iframe.getSourceId=function(sources,cb){if(states.error)return void cb({success:!1,error:new Error("iframe is not loaded")});if(states.loaded)getSourceIdFromIFrame(sources,cb);else var endBlocks=0,intervalChecker=setInterval(function(){states.loaded?(clearInterval(intervalChecker),getSourceIdFromIFrame(sources,cb)):50===endBlocks?(clearInterval(intervalChecker),cb({success:!1,error:new Error("iframe failed to load")})):endBlocks++},100)},(document.body||document.documentElement).appendChild(iframe)}}else"edge"===AdapterJS.webrtcDetectedBrowser?console.warn("Edge does not support screensharing feature in getUserMedia"):"AppleWebKit"===AdapterJS.webrtcDetectedType?console.warn("Safari does not support screensharing feature in getUserMedia"):"plugin"===AdapterJS.webrtcDetectedType&&(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(checkIfConstraintsIsValid(constraints,successCb,failureCb),constraints.video&&"object"==typeof constraints.video&&constraints.video.hasOwnProperty("mediaSource")){var updatedConstraints=clone(constraints);AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){if(!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature||!AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable)return void failureCb(new Error("Your version of the WebRTC plugin does not support screensharing"));if(AdapterJS.WebRTCPlugin.plugin.screensharingKeys)if(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("screen")>-1&&updatedConstraints.video.mediaSource.indexOf("window")>-1||updatedConstraints.video.mediaSource===AdapterJS.WebRTCPlugin.plugin.screensharingKey||updatedConstraints.video.mediaSource===AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screenOrWindow)updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screenOrWindow;else if(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("screen")>-1||"screen"===updatedConstraints.video.mediaSource)updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screen;else{if(!(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("window")>-1||"window"===updatedConstraints.video.mediaSource))return void failureCb(new Error('GetUserMedia: Only "screen", "window", ["screen", "window"] are supported as mediaSource constraints'));updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.window}updatedConstraints.video.optional=updatedConstraints.video.optional||[],updatedConstraints.video.optional.push({sourceId:updatedConstraints.video.mediaSource}),baseGetUserMedia(updatedConstraints,successCb,failureCb)})}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=getUserMedia=window.getUserMedia=navigator.getUserMedia,navigator.mediaDevices&&"undefined"!=typeof Promise&&(navigator.mediaDevices.getUserMedia=requestUserMedia))}},"function"!=typeof window.require&&AdapterJS._defineMediaSourcePolyfill(),function(globals){"use strict";function Skylink(){this._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._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=!1,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=this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={},this._useEdgeWebRTC=!1}!function(){Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,r=!{toString:null}.propertyIsEnumerable("toString"),e=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],o=e.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var c=[];for(var l in n)t.call(n,l)&&c.push(l);if(r)for(var p=0;o>p;p++)t.call(n,e[p])&&c.push(e[p]);return c}}())}(),function(){function t(t){return 10>t?"0"+t:t}Date.prototype.toISOString=function(){return this.getUTCFullYear()+"-"+t(this.getUTCMonth()+1)+"-"+t(this.getUTCDate())+"T"+t(this.getUTCHours())+":"+t(this.getUTCMinutes())+":"+t(this.getUTCSeconds())+"."+(this.getUTCMilliseconds()/1e3).toFixed(3).slice(2,5)+"Z"}}(),function(){"function"!=typeof Date.now&&(Date.now=function(){return(new Date).getTime()})}(),function(e,t){function n(e){var n=t[e];t[e]=function(e){return o(n(e))}}function a(t,n,a){return(a=this).attachEvent("on"+t,function(t){var t=t||e.event;t.preventDefault=t.preventDefault||function(){t.returnValue=!1},t.stopPropagation=t.stopPropagation||function(){t.cancelBubble=!0},n.call(a,t)})}function o(e,t){if(t=e.length)for(;t--;)e[t].addEventListener=a;else e.addEventListener=a;return e}e.addEventListener||(o([t,e]),"Element"in e?e.Element.prototype.addEventListener=a:(t.attachEvent("onreadystatechange",function(){o(t.all)}),n("getElementsByTagName"),n("getElementById"),n("createElement"),o(t.all)))}(window,document),function(){if("performance"in window==0&&(window.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in window.performance==0){var a=Date.now();performance.timing&&performance.timing.navigationStart&&(a=performance.timing.navigationStart),window.performance.now=function(){return Date.now()-a}}}(),window.BlobBuilder=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,Array.prototype.forEach||(Array.prototype.forEach=function(callback){var T,k;if(null==this)throw new TypeError("this is null or not defined");var O=Object(this),len=O.length>>>0;if("function"!=typeof callback)throw new TypeError(callback+" is not a function");for(arguments.length>1&&(T=arguments[1]),k=0;k"],error),void self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CREATE_ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))}self._dataChannels[peerId]?self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel.label===channelName&&(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING):(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING,self._dataChannels[peerId]={},log.debug([peerId,"RTCDataChannel",channelProp,"initializing main DataChannel"])),dataChannel.onerror=function(evt){var channelError=evt.error||evt;log.error([peerId,"RTCDataChannel",channelProp,"Datachannel has an exception ->"],channelError),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,channelError,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onbufferedamountlow=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel buffering data transfer low"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.BUFFERED_AMOUNT_LOW,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onmessage=function(event){self._processDataChannelData(event.data,peerId,channelName,channelType)};var onOpenHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has opened"]),dataChannel.bufferedAmountLowThreshold=bufferThreshold||0,self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.OPEN,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))};dataChannel.readyState===self.DATA_CHANNEL_STATE.OPEN?setTimeout(onOpenHandlerFn,1):(self._trigger("dataChannelState",dataChannel.readyState,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),dataChannel.onopen=onOpenHandlerFn);var onCloseHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has closed"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSED,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),self._peerConnections[peerId]&&self._peerConnections[peerId].remoteDescription&&self._peerConnections[peerId].remoteDescription.sdp&&(-1===self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")||self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application 0")>0)||channelType===self.DATA_CHANNEL_TYPE.MESSAGING&&setTimeout(function(){self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[peerId].localDescription&&self._peerConnections[peerId].localDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&(log.debug([peerId,"RTCDataChannel",channelProp,"Reviving Datachannel connection"]),self._createDataChannel(peerId,channelName,bufferThreshold,!0))},100)};if("firefox"===AdapterJS.webrtcDetectedBrowser){var hasTriggeredClose=!1,timeBlockAfterClosing=0;dataChannel.onclose=function(){hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())};var onFFClosed=setInterval(function(){dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSED||hasTriggeredClose||5===timeBlockAfterClosing?(clearInterval(onFFClosed),hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())):dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSING&&timeBlockAfterClosing++},1e3)}else dataChannel.onclose=onCloseHandlerFn;channelType===self.DATA_CHANNEL_TYPE.MESSAGING?self._dataChannels[peerId].main={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}:self._dataChannels[peerId][channelName]={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}},Skylink.prototype._getDataChannelBuffer=function(peerId,channelProp){if("object"==typeof peerId)return{bufferedAmountLow:"number"==typeof peerId.bufferedAmountLow?peerId.bufferedAmountLow:parseInt(peerId.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?peerId.bufferedAmountLowThreshold:parseInt(peerId.bufferedAmountLowThreshold,10)||0};if(!(this._dataChannels[peerId]&&this._dataChannels[peerId][channelProp]&&this._dataChannels[peerId][channelProp].channel))return{bufferedAmountLow:0,bufferedAmountLowThreshold:0};var channel=this._dataChannels[peerId][channelProp].channel;return{bufferedAmountLow:"number"==typeof channel.bufferedAmountLow?channel.bufferedAmountLow:parseInt(channel.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof channel.bufferedAmountLowThreshold?channel.bufferedAmountLowThreshold:parseInt(channel.bufferedAmountLowThreshold,10)||0}},Skylink.prototype._sendMessageToDataChannel=function(peerId,data,channelProp,doNotConvert){var self=this;if(channelProp&&channelProp!==peerId||(channelProp="main"),!("object"==typeof data&&data||data&&"string"==typeof data))return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping invalid data ->"],data);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Peer connection does not exists or is closed ->"],data);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Datachannel connection does not exists ->"],data);var channelName=self._dataChannels[peerId][channelProp].channelName,channelType=self._dataChannels[peerId][channelProp].channelType,readyState=self._dataChannels[peerId][channelProp].channel.readyState,messageType="object"==typeof data&&data.type===self._DC_PROTOCOL_TYPE.MESSAGE?self.DATA_CHANNEL_MESSAGE_ERROR.MESSAGE:self.DATA_CHANNEL_MESSAGE_ERROR.TRANSFER;if(readyState!==self.DATA_CHANNEL_STATE.OPEN){var notOpenError='Failed sending message as Datachannel connection state is not opened. Current readyState is "'+readyState+'"';throw log.error([peerId,"RTCDataChannel",channelProp,notOpenError+" ->"],data),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,new Error(notOpenError),channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),new Error(notOpenError)}try{doNotConvert||"object"!=typeof data?(log.debug([peerId,"RTCDataChannel",channelProp,"Sending data with size ->"],data.size||data.length||data.byteLength),self._dataChannels[peerId][channelProp].channel.send(data)):(log.debug([peerId,"RTCDataChannel",channelProp,'Sending "'+data.type+'" protocol message ->'],data),self._dataChannels[peerId][channelProp].channel.send(JSON.stringify(data)))}catch(error){throw log.error([peerId,"RTCDataChannel",channelProp,"Failed sending "+(doNotConvert||"object"!=typeof data?"data":'"'+data.type+'" protocol message')+" ->"],error),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,error,channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),error}},Skylink.prototype._closeDataChannel=function(peerId,channelProp){var self=this;if(!self._dataChannels[peerId])return void log.warn([peerId,"RTCDataChannel",channelProp||null,"Aborting closing Datachannels as Peer connection does not have Datachannel sessions"]);var closeFn=function(rChannelProp){var channelName=self._dataChannels[peerId][rChannelProp].channelName,channelType=self._dataChannels[peerId][rChannelProp].channelType;self._dataChannels[peerId][rChannelProp].readyState!==self.DATA_CHANNEL_STATE.CLOSED&&(log.debug([peerId,"RTCDataChannel",channelProp,"Closing Datachannel"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSING,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(peerId,rChannelProp)),self._dataChannels[peerId][rChannelProp].channel.close(),delete self._dataChannels[peerId][rChannelProp])};if(channelProp){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.");if(!self._enableSimultaneousTransfers)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature requires simultaneous data transfers to be enabled");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},listenToPeerFn=function(peerId,channelProp){var hasStarted=!1;sessions[peerId]=channelProp,self.once("dataStreamState",function(){},function(state,evtTransferId,evtPeerId,evtSessionInfo){if(evtTransferId===transferId&&evtPeerId===peerId){evtSessionInfo.chunk;return delete clone(evtSessionInfo).chunk,state===self.DATA_STREAM_STATE.SENDING_STARTED?void(hasStarted=!0):hasStarted&&[self.DATA_STREAM_STATE.ERROR,self.DATA_STREAM_STATE.SENDING_STOPPED].indexOf(state)>-1?(channelProp===transferId&&self._closeDataChannel(peerId,transferId),self._dataStreams[transferId]&&self._dataStreams[transferId].sessions[peerId]&&(delete self._dataStreams[transferId].sessions[peerId],0===Object.keys(self._dataStreams[transferId].sessions).length&&delete self._dataStreams[transferId]),!0):void 0}})},i=0;i-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE)};if(peersNonInterop.length>0)if(self._hasMCU)waitForChannelOpenFn("MCU",peersNonInterop);else for(var pni=0;pni0)if(self._hasMCU)startDataSessionFn("MCU","main",peersInterop);else for(var pi=0;piself._CHUNK_DATAURL_SIZE:updatedDataChunk.length>self._BINARY_FILE_SIZE)return void log.error("Failed streaming data chunk as data chunk exceeds maximum chunk limit.");var sessionInfo={chunk:updatedDataChunk,chunkSize:updatedDataChunk.size||updatedDataChunk.length||updatedDataChunk.byteLength,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){var onSendDataFn=function(buffer){self._sendMessageToDataChannel(peerId,buffer,channelProp,!0);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype.stopStreamingData=function(transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error("Failed streaming data chunk as stream session ID is not provided.");if(!(self._inRoom&&self._user&&self._user.sid))return void log.error("Failed streaming data chunk as User is not in the Room.");if(!self._dataStreams[transferId])return void log.error("Failed stopping data streaming session as it does not exists.");if(!self._dataStreams[transferId].isUpload)return void log.error("Failed stopping data streaming session as it is not sending.");if(self._hasMCU)return void log.error("Failed stopping data streaming session as MCU does not support this feature yet.");var sessionInfo={chunk:null,chunkSize:0,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:transferId,size:0,originalSize:0,dataType:"fastBinaryStop",mimeType:null,chunkType:self._dataStreams[transferId].sessionChunkType,chunkSize:0,timeout:0,isPrivate:self._dataStreams[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype._startDataTransfer=function(data,timeout,targetPeerId,sendChunksAsBinary,callback,sessionType){var self=this,transferId=(self._user?self._user.sid:"")+"_"+(new Date).getTime(),transferErrors={},transferCompleted=[],chunks=[],listOfPeers=Object.keys(self._peerConnections),sessionChunkType="string",transferInfo={name:null,size:null,chunkSize:null,chunkType:null,dataType:null,mimeType:null,direction:self.DATA_TRANSFER_TYPE.UPLOAD,timeout:60,isPrivate:!1,percentage:0};"number"==typeof timeout?transferInfo.timeout=timeout:Array.isArray(timeout)?listOfPeers=timeout:timeout&&"string"==typeof timeout?listOfPeers=[timeout]:timeout&&"boolean"==typeof timeout?sessionChunkType="binary":"function"==typeof timeout&&(callback=timeout),Array.isArray(targetPeerId)?listOfPeers=targetPeerId:targetPeerId&&"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:targetPeerId&&"boolean"==typeof targetPeerId?sessionChunkType="binary":"function"==typeof targetPeerId&&(callback=targetPeerId),sendChunksAsBinary&&"boolean"==typeof sendChunksAsBinary?sessionChunkType="binary":"function"==typeof sendChunksAsBinary&&(callback=sendChunksAsBinary),listOfPeers.indexOf("MCU")>-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeDataTransferFn=function(error){if(log.error(error),"function"==typeof callback){var transferErrors={};if(0===listOfPeers.length)transferErrors.self=new Error(error);else for(var i=0;i0){var bsChunkSize="firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_CHUNK_FILE_SIZE:self._CHUNK_FILE_SIZE,bsChunks=self._chunkBlobData(new Blob(chunks),bsChunkSize);self._dataTransfers[transferId].enforceBSInfo={chunkSize:4*Math.ceil(bsChunkSize/3),chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,size:4*Math.ceil(transferInfo.originalSize/3),chunks:bsChunks}}}for(var completeFn=function(peerId,error){transferCompleted.indexOf(peerId)>-1||(log.debug([peerId,"RTCDataChannel",transferId,"Data transfer result. Is errors present? ->"],error),transferCompleted.push(peerId),error&&(transferErrors[peerId]=new Error(error)),listOfPeers.length===transferCompleted.length&&(log.log([null,"RTCDataChannel",transferId,"Data transfer request completed"]),"function"==typeof callback&&(Object.keys(transferErrors).length>0?callback({transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),transferErrors:transferErrors,listOfPeers:listOfPeers},null):callback(null,{transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),listOfPeers:listOfPeers}))))},i=0;i0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,"main",Object.keys(self._dataTransfers[transferId].peers.main)),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,transferId,Object.keys(self._dataTransfers[transferId].peers[transferId])))},Skylink.prototype._startDataTransferToPeer=function(transferId,peerId,callback,channelProp,targetPeers){var self=this,peerConnectionStateCbFn=null,dataChannelStateCbFn=null,emitEventFn=function(cb){for(var peers=targetPeers||[peerId],i=0;i-1&&(log.warn([peerId,"RTCDataChannel",transferId,"Binary data chunks transfer is not yet supported with Peer connecting from Android, iOS and C++ SDK. Fallbacking to binary string data chunks transfer."]),size=self._dataTransfers[transferId].enforceBSInfo.size,chunkSize=self._dataTransfers[transferId].enforceBSInfo.chunkSize,chunkType="string"),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:self._dataTransfers[transferId].name,size:size,originalSize:self._dataTransfers[transferId].originalSize,dataType:self._dataTransfers[transferId].sessionType,mimeType:self._dataTransfers[transferId].mimeType,chunkType:chunkType,chunkSize:chunkSize,timeout:self._dataTransfers[transferId].timeout,isPrivate:self._dataTransfers[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp),emitEventFn(function(evtPeerId){self._trigger("incomingDataRequest",transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_UPLOAD_REQUEST,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)})};if("MCU"!==peerId){var dataTransferStateCbFn=function(state,evtTransferId,evtPeerId,transferInfo,error){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&&-1===self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)))return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel currently has an active "+self._dataStreams[streamId].sessionChunkType+" data streaming session.");var protocolVer=(self._peerInformations[peerId].agent||{}).DTProtocolVersion||"0.1.0",requireInterop=self._isLowerThanVersion(protocolVer,"0.1.2")||!self._enableSimultaneousTransfers;return self._isLowerThanVersion(protocolVer,"0.1.2")&&"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer do not support DATA_URL type of data transfers"):"MCU"!==peerId&&self._hasMCU?(channelProp=requireInterop?"main":transferId,peerConnectionStateCbFn=function(){returnErrorBeforeTransferFn("Data transfer terminated as Peer connection is not stable.")},self.once("peerConnectionState",peerConnectionStateCbFn,function(state,evtPeerId){return self._dataTransfers[transferId]?state!==self.PEER_CONNECTION_STATE.STABLE&&evtPeerId===peerId:void self.off("peerConnectionState",peerConnectionStateCbFn)}),requireInterop):(requireInterop||"main"===channelProp)&&self._dataChannels[peerId].main.transferId?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel has a data transfer in-progress."):(self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0},dataChannelStateCbFn=function(state,evtPeerId,error){self._dataTransfers[transferId].sessions[peerId].ackN>=self._dataTransfers[transferId].chunks.length-1||returnErrorBeforeTransferFn(error?error.message||error.toString():"Data transfer terminated as Peer Datachannel connection closed abruptly.")},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){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"===AdapterJS.webrtcDetectedBrowser?16384:65546:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE))))},Skylink.prototype._getTransferInfo=function(transferId,peerId,returnDataProp,hidePercentage,returnDataAtStart){if(!this._dataTransfers[transferId])return{};var transferInfo={name:this._dataTransfers[transferId].name,
-size:this._dataTransfers[transferId].size,dataType:this._dataTransfers[transferId].dataType||this.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:this._dataTransfers[transferId].mimeType||null,chunkSize:this._dataTransfers[transferId].chunkSize,chunkType:this._dataTransfers[transferId].chunkType,timeout:this._dataTransfers[transferId].timeout,isPrivate:this._dataTransfers[transferId].isPrivate,direction:this._dataTransfers[transferId].direction};if(this._dataTransfers[transferId].originalSize?transferInfo.size=this._dataTransfers[transferId].originalSize:this._dataTransfers[transferId].chunkType===this.DATA_TRANSFER_DATA_TYPE.BINARY_STRING&&(transferInfo.size=Math.ceil(3*transferInfo.size/4)),!hidePercentage){if(transferInfo.percentage=0,!this._dataTransfers[transferId].sessions[peerId])return returnDataProp&&(transferInfo.data=null),transferInfo;if(this._dataTransfers[transferId].direction===this.DATA_TRANSFER_TYPE.DOWNLOAD)this._dataTransfers[transferId].sessions[peerId].receivedSize===this._dataTransfers[transferId].sessions[peerId].size?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].receivedSize/this._dataTransfers[transferId].size*100).toFixed(2),10);else{var chunksLength=this._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?this._dataTransfers[transferId].enforceBSInfo.chunks.length:this._dataTransfers[transferId].chunks.length;this._dataTransfers[transferId].sessions[peerId].ackN===chunksLength?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].ackN/chunksLength*100).toFixed(2),10)}returnDataProp&&("number"!=typeof returnDataAtStart?100===transferInfo.percentage?transferInfo.data=this._getTransferData(transferId):transferInfo.data=null:(transferInfo.percentage=returnDataAtStart,0===returnDataAtStart&&(transferInfo.data=this._getTransferData(transferId))))}return transferInfo},Skylink.prototype._getTransferData=function(transferId){if(!this._dataTransfers[transferId])return null;if(this._dataTransfers[transferId].dataType===this.DATA_TRANSFER_SESSION_TYPE.BLOB){var mimeType={name:this._dataTransfers[transferId].name};return this._dataTransfers[transferId].mimeType&&(mimeType.type=this._dataTransfers[transferId].mimeType),new Blob(this._dataTransfers[transferId].chunks,mimeType)}return this._dataTransfers[transferId].chunks.join("")},Skylink.prototype._handleDataTransferTimeoutForPeer=function(transferId,peerId,setPeerTO){var self=this;if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer does not exists for Peer. Ignoring timeout."]);log.debug([peerId,"RTCDataChannel",transferId,"Clearing data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer&&clearTimeout(self._dataTransfers[transferId].sessions[peerId].timer),self._dataTransfers[transferId].sessions[peerId].timer=null,setPeerTO&&(log.debug([peerId,"RTCDataChannel",transferId,"Setting data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer=setTimeout(function(){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer already ended for Peer. Ignoring expired timeout."]);if(!self._user||!self._user.sid)return void log.debug([peerId,"RTCDataChannel",transferId,"User is not in Room. Ignoring expired timeout."]);if(!self._dataChannels[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Datachannel connection does not exists. Ignoring expired timeout."]);log.error([peerId,"RTCDataChannel",transferId,"Data transfer response has timed out."]);var emitEventFn=function(cb){if("MCU"===peerId){for(var broadcastedPeers=[self._dataTransfers[transferId].peers.main,self._dataTransfers[transferId].peers[transferId]],i=0;i"],rawData);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping data received from Peer as Datachannel connection is not present ->"],rawData);if("string"==typeof rawData)try{var protocolData=JSON.parse(rawData);if(isStreamChunk=!1,log.debug([peerId,"RTCDataChannel",channelProp,'Received protocol "'+protocolData.type+'" message ->'],protocolData),[self._DC_PROTOCOL_TYPE.ACK,self._DC_PROTOCOL_TYPE.ERROR,self._DC_PROTOCOL_TYPE.CANCEL].indexOf(protocolData.type)>-1&&!(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded protocol message as data transfer session is not present ->"],protocolData);switch(protocolData.type){case self._DC_PROTOCOL_TYPE.WRQ:if(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId])return log.warn([peerId,"RTCDataChannel",channelProp,"Rejecting bidirectional data transfer request as it is currently not supported in the SDK ->"],protocolData),void self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,ackN:-1,sender:self._user.sid},channelProp);self._WRQProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ACK:self._ACKProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ERROR:self._ERRORProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.CANCEL:self._CANCELProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.MESSAGE:self._MESSAGEProtocolHandler(peerId,protocolData,channelProp);break;default:log.warn([peerId,"RTCDataChannel",channelProp,'Discarded unknown "'+protocolData.type+'" message ->'],protocolData)}}catch(error){if(rawData.indexOf("{")>-1&&rawData.indexOf("}")>0)throw log.error([peerId,"RTCDataChannel",channelProp,"Failed parsing protocol step data error ->"],{data:rawData,error:error}),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(peerId,channelProp)),error;if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING;if(isStreamChunk||self._dataTransfers[transferId].dataType===self.DATA_TRANSFER_SESSION_TYPE.DATA_URL)log.debug([peerId,"RTCDataChannel",channelProp,"Received string data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.length||rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.STRING,rawData.length||rawData.size||0,channelProp);else{var removeSpaceData=rawData.replace(/\s|\r|\n/g,"");log.debug([peerId,"RTCDataChannel",channelProp,"Received binary string data chunk @"+self._dataTransfers[transferId].sessions[peerId].ackN+" with size ->"],removeSpaceData.length||removeSpaceData.size),self._DATAProtocolHandler(peerId,self._base64ToBlob(removeSpaceData),self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,removeSpaceData.length||removeSpaceData.size||0,channelProp)}}else{if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);if(rawData instanceof Blob)log.debug([peerId,"RTCDataChannel",channelProp,"Received blob data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.BLOB,rawData.size,channelProp);else{var byteArray=rawData,blob=null;if(rawData.constructor&&"Array"===rawData.constructor.name&&(byteArray=new Int8Array(rawData)),"IE"===AdapterJS.webrtcDetectedBrowser){if(window.BlobBuilder){var bb=new BlobBuilder;bb.append(rawData.constructor&&"ArrayBuffer"===rawData.constructor.name?byteArray:new Uint8Array(byteArray).buffer),blob=bb.getBlob()}}else blob=new Blob([byteArray]);log.debug([peerId,"RTCDataChannel",channelProp,"Received arraybuffer data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],blob.size),self._DATAProtocolHandler(peerId,blob,self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,blob.size,channelProp)}}},Skylink.prototype._WRQProtocolHandler=function(peerId,data,channelProp){var self=this,transferId="main"===channelProp?data.transferId||null:channelProp,senderPeerId=data.sender||peerId;if(["fastBinaryStart","fastBinaryStop"].indexOf(data.dataType)>-1)if("fastBinaryStart"===data.dataType){transferId||(transferId="stream_"+peerId+"_"+(new Date).getTime()),self._dataStreams[transferId]={chunkSize:0,chunkType:"string"===data.chunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:data.chunkType,isPrivate:!!data.isPrivate,isStringStream:"string"===data.chunkType,senderPeerId:senderPeerId,isUpload:!1},self._dataChannels[peerId][channelProp].streamId=transferId;self.once("dataChannelState",function(){},function(state,evtPeerId,channelName,channelType,error){if(!self._dataStreams[transferId])return!0;if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId&&channelType===self.DATA_CHANNEL_TYPE.DATA)&&[self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');return self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},updatedError),!0}}),self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STARTED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStarted",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1)}else transferId=self._dataChannels[peerId][channelProp].streamId,self._dataStreams[transferId]&&!self._dataStreams[transferId].isUpload&&(self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STOPPED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStopped",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1),self._dataChannels[peerId][channelProp].streamId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp),delete self._dataStreams[transferId]);else transferId||(transferId="transfer_"+peerId+"_"+(new Date).getTime()),self._dataTransfers[transferId]={name:data.name||transferId,size:data.size||0,chunkSize:data.chunkSize,originalSize:data.originalSize||0,timeout:data.timeout||60,isPrivate:!!data.isPrivate,senderPeerId:data.sender||peerId,dataType:self.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:data.mimeType||null,chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,direction:self.DATA_TRANSFER_TYPE.DOWNLOAD,chunks:[],sessions:{},sessionType:data.dataType||"blob",sessionChunkType:data.chunkType||"string"},"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?(self._dataTransfers[transferId].dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,self._dataTransfers[transferId].chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING):"blob"===self._dataTransfers[transferId].sessionType&&"binary"===self._dataTransfers[transferId].sessionChunkType&&(self._dataTransfers[transferId].chunkType=self._binaryChunkType),self._dataChannels[peerId][channelProp].transferId=transferId,self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0,receivedSize:0},self._trigger("incomingDataRequest",transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!1),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_REQUEST,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)},Skylink.prototype._ACKProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ACK event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};if(data.ackN>-1){if(0===data.ackN)emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_STARTED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,0),null)});else if(self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?data.ackN===self._dataTransfers[transferId].enforceBSInfo.chunks.length:data.ackN===self._dataTransfers[transferId].chunks.length)return self._dataTransfers[transferId].sessions[peerId].ackN=data.ackN,emitEventFn(function(evtPeerId){self._trigger("incomingData",self._getTransferData(transferId),transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,100),null)}),void(self._dataChannels[peerId][channelProp]&&(self._dataChannels[peerId][channelProp].transferId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp)));var uploadFn=function(chunk){self._sendMessageToDataChannel(peerId,chunk,channelProp,!0),data.ackN-1?self._blobToBase64(self._dataTransfers[transferId].enforceBSInfo.chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING?self._blobToBase64(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER?self._blobToArrayBuffer(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):uploadFn(self._dataTransfers[transferId].chunks[data.ackN])}else self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.REJECTED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as Peer has rejected data transfer request"),transferType:self.DATA_TRANSFER_TYPE.UPLOAD})},Skylink.prototype._MESSAGEProtocolHandler=function(peerId,data,channelProp){var senderPeerId=data.sender||peerId;log.log([senderPeerId,"RTCDataChannel",channelProp,"Received P2P message from peer:"],data),this._trigger("incomingMessage",{content:data.data,isPrivate:data.isPrivate,isDataChannel:!0,targetPeerId:this._user.sid,senderPeerId:senderPeerId},senderPeerId,this.getPeerInfo(senderPeerId),!1)},Skylink.prototype._ERRORProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ERROR event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,evtPeerId,self._getTransferInfo(transferId,peerID,!0,!1,!1),{message:new Error(data.content),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._CANCELProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of CANCEL event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(peerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.CANCEL,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error(data.content||"Peer has terminated data transfer."),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._DATAProtocolHandler=function(peerId,chunk,chunkType,chunkSize,channelProp){var self=this,transferId=channelProp,senderPeerId=peerId;if(self._dataChannels[peerId]&&self._dataChannels[peerId][channelProp]){var streamId=self._dataChannels[peerId][channelProp].streamId;if(streamId&&self._dataStreams[streamId]&&("string"==typeof chunk&&"string"===self._dataStreams[streamId].sessionChunkType||chunk instanceof Blob&&"binary"===self._dataStreams[streamId].sessionChunkType))return senderPeerId=self._dataStreams[streamId].senderPeerId||peerId,self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVED,streamId,senderPeerId,{chunk:chunk,chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},null),void self._trigger("incomingDataStream",chunk,transferId,senderPeerId,{chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},!1);if("main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._dataTransfers[transferId].senderPeerId&&(senderPeerId=self._dataTransfers[transferId].senderPeerId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1),self._dataTransfers[transferId].chunkType=chunkType,self._dataTransfers[transferId].sessions[peerId].receivedSize+=chunkSize,self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN]=chunk,self._dataTransfers[transferId].sessions[peerId].receivedSize>=self._dataTransfers[transferId].size)return log.log([peerId,"RTCDataChannel",channelProp,"Data transfer has been completed. Computed size ->"],self._dataTransfers[transferId].sessions[peerId].receivedSize),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN+1},channelProp),self._trigger("incomingData",self._getTransferData(transferId),transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),null),void self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null);self._dataTransfers[transferId].sessions[peerId].ackN+=1,self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN},channelProp),self._handleDataTransferTimeoutForPeer(transferId,peerId,!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOADING,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)}},Skylink.prototype.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._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,userInfo:self._getUserInfo(targetMid),target:targetMid,rid:self._room.id})}}},Skylink.prototype._addIceCandidateToQueue=function(targetMid,canId,candidate){var candidateType=candidate.candidate.split(" ")[7];log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Buffering ICE candidate."]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.BUFFERED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[],this._peerCandidatesQueue[targetMid].push([canId,candidate])},Skylink.prototype._addIceCandidateFromQueue=function(targetMid){this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[];for(var i=0;i"],error),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},error)};if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Adding ICE candidate."]),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESSING,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[targetMid].remoteDescription&&self._peerConnections[targetMid].remoteDescription.sdp&&self._peerConnections[targetMid].remoteDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),void self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed."));try{self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)}catch(error){onErrorCbFn(error)}},Skylink.prototype.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&&("firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion<53?useTURNSSLPort=!0:useTURNSSLProtocol=!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]=[]),-1===iceServersList[username][credential].indexOf(url)&&("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"===AdapterJS.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"===AdapterJS.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport="chrome"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>34||"firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>38||"opera"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>31||["plugin","AppleWebKit"].indexOf(AdapterJS.webrtcDetectedType)>-1||["bowser","edge"].indexOf(AdapterJS.webrtcDetectedBrowser)>-1;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"===AdapterJS.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}))}},refreshSinglePeer=function(peerId,peerCallback){if(!self._peerConnections[peerId])return error="There is currently no existing peer connection made with the peer. Unable to restart connection",log.error([peerId,null,null,error]),void peerCallback(error);log.log([peerId,"PeerConnection",null,"Restarting peer connection"]),self._restartPeerConnection(peerId,doIceRestart,bwOptions,peerCallback)};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?refreshSinglePeer(peerId,refreshSinglePeerCallback(peerId)):(error="Peer connection with peer does not exists. Unable to restart",log.error([peerId,"PeerConnection",null,error]),refreshSinglePeerCallback(peerId)(error))}}},Skylink.prototype.getConnectionStatus=function(targetPeerId,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),listOfPeerStats={},listOfPeerErrors={};if(Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId&&targetPeerId?listOfPeers=[targetPeerId]:"function"==typeof targetPeerId&&(callback=targetPeerId,targetPeerId=void 0),0===listOfPeers.length)return listOfPeerErrors.self=new Error("There is currently no peer connections to retrieve connection status"),log.error([null,"RTCStatsReport",null,"Retrieving request failure ->"],listOfPeerErrors.self),void("function"==typeof callback&&callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null));"edge"===AdapterJS.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){-1===completedTaskCounter.indexOf(peerId)&&completedTaskCounter.push(peerId),completedTaskCounter.length===listOfPeers.length&&"function"==typeof callback&&(Object.keys(listOfPeerErrors).length>0?callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null):callback(null,{listOfPeers:listOfPeers,connectionStats:listOfPeerStats}))},statsFn=function(peerId){var retrieveFn=function(firstRetrieval,nextCb){return function(err,result){if(err)return log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],error),listOfPeerErrors[peerId]=error,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,error),checkCompletedFn(peerId),void(firstRetrieval&&delete self._peerStats[peerId]);firstRetrieval?nextCb():(listOfPeerStats[peerId]=result,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_SUCCESS,peerId,listOfPeerStats[peerId],null),checkCompletedFn(peerId))}};if(!self._peerStats[peerId])return self._peerStats[peerId]={},log.debug([peerId,"RTCStatsReport",null,"Retrieving first report to tabulate results"]),void self._retrieveStats(peerId,retrieveFn(!0,function(){self._retrieveStats(peerId,retrieveFn())}),!0);self._retrieveStats(peerId,retrieveFn())},i=0;i"],listOfPeerErrors[peerId]),self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,listOfPeerErrors[peerId]),checkCompletedFn(peerId))}},Skylink.prototype._retrieveStats=function(peerId,callback,beSilentOnLogs,isAutoBwStats){var self=this,pc=self._peerConnections[peerId],output={raw:{},connection:{},audio:{sending:{},receiving:{}},video:{sending:{},receiving:{}},selectedCandidate:{local:{},remote:{},consentResponses:{},consentRequests:{},responses:{},requests:{}},certificate:{}};if(!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));if(!pc)return callback(new Error("Peer connection is not initialised"));"edge"!==AdapterJS.webrtcDetectedBrowser&&"AppleWebKit"!==AdapterJS.webrtcDetectedType||log.warn("Current connection stats may not be complete as it is in beta"),output.connection.iceConnectionState=pc.iceConnectionState,output.connection.iceGatheringState=pc.iceGatheringState,output.connection.signalingState=pc.signalingState,output.connection.remoteDescription={type:pc.remoteDescription&&pc.remoteDescription.type||"",sdp:pc.remoteDescription&&pc.remoteDescription.sdp||""},output.connection.localDescription={type:pc.localDescription&&pc.localDescription.type||"",sdp:pc.localDescription&&pc.localDescription.sdp||""},output.connection.candidates={sending:self._getSDPICECandidates(peerId,pc.localDescription,beSilentOnLogs),receiving:self._getSDPICECandidates(peerId,pc.remoteDescription,beSilentOnLogs)},output.connection.dataChannels={},output.connection.constraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,output.connection.optional=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,output.connection.sdpConstraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null,output.audio.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),output.video.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),output.audio.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"audio",beSilentOnLogs),output.video.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"video",beSilentOnLogs),output.certificate.local=self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),output.certificate.remote=self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs);var inboundSSRCs=self._getSDPMediaSSRC(peerId,pc.remoteDescription,beSilentOnLogs);output.audio.receiving.ssrc=inboundSSRCs.audio,output.video.receiving.ssrc=inboundSSRCs.video;var outboundSSRCs=self._getSDPMediaSSRC(peerId,pc.localDescription,beSilentOnLogs);output.audio.sending.ssrc=outboundSSRCs.audio,output.video.sending.ssrc=outboundSSRCs.video,Object.keys(self._dataChannels[peerId]||{}).forEach(function(prop){var channel=self._dataChannels[peerId][prop];output.connection.dataChannels[channel.channel.label]={label:channel.channel.label,readyState:channel.channel.readyState,channelType:self.DATA_CHANNEL_TYPE["main"===prop?"MESSAGING":"DATA"],currentTransferId:channel.transferId||null,currentStreamId:channel.streamId||null}});var certificateFn=function(item,prop){if(0===prop.indexOf("RTCCertificate_"))item.fingerprint===output.certificate.local.fingerprint?(output.certificate.local.derBase64=item.base64Certificate,output.certificate.local.fingerprintAlgorithm=item.fingerprintAlgorithm):item.fingerprint===output.certificate.remote.fingerprint&&(output.certificate.remote.derBase64=item.base64Certificate,output.certificate.remote.fingerprintAlgorithm=item.fingerprintAlgorithm);else if(0===prop.indexOf("ssrc_")&&item.transportId){var pairItem=output.raw[item.transportId]||{};output.certificate.srtpCipher=pairItem.srtpCipher,output.certificate.dtlsCipher=pairItem.dtlsCipher;var localCertItem=output.raw[pairItem.localCertificateId||""]||{};output.certificate.local.fingerprint=localCertItem.googFingerprint,output.certificate.local.fingerprintAlgorithm=localCertItem.googFingerprintAlgorithm,output.certificate.local.derBase64=localCertItem.googDerBase64;var remoteCertItem=output.raw[pairItem.remoteCertificateId||""]||{};output.certificate.remote.fingerprint=remoteCertItem.googFingerprint,output.certificate.remote.fingerprintAlgorithm=remoteCertItem.googFingerprintAlgorithm,output.certificate.remote.derBase64=remoteCertItem.googDerBase64}},candidatePairFn=function(item,prop){if(0===prop.indexOf("RTCIceCandidatePair_")){if("succeeded"!==item.state||output.selectedCandidate.nominated||item.prioirty<(output.selectedCandidate.priority||0))return;for(var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],sending=pc.localDescription&&pc.localDescription.sdp&&pc.localDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],receiving=pc.remoteDescription&&pc.remoteDescription&&pc.remoteDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],computePrioirtyFn=function(controller,controlled){return Math.pow(2,32)*Math.min(controller,controlled)+2*Math.max(controller,controlled)+(controller>controlled?1:0)},computeCanTypeFn=function(type){return"relay"===type?"relayed":"host"===type?"local":"srflx"===type?"serverreflexive":type},s=0;s0?"sending":"receiving";item.codecImplementationName="unknown"===item.codecImplementationName?null:item.codecImplementationName,output[item.mediaType][direction].codec.implementation=item.codecImplementationName||null,item.googCodecName="unknown"===item.googCodecName?null:item.googCodecName,output[item.mediaType][direction].codec.name=item.googCodecName||output[item.mediaType][direction].codec.name}},audioStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPAudioStream")){if(output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.audio.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),"function"!=typeof pc.getReceivers)return}else if(0===prop.indexOf("RTCMediaStreamTrack_remote_audio_"))output.audio.receiving.audioOutputLevel=item.audioLevel;else if(0===prop.indexOf("RTCOutboundRTPAudioStream"))output.audio.sending.targetBitrate=item.targetBitrate||0,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"audio"===item.mediaType&&item.isRemote)output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"audio"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"audio"===item.mediaType)if(prop.indexOf("_recv")>0){output.audio.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.audio.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.audio.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.audio.receiving.totalBytes=bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.audio.receiving.totalPackets=packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.audio.receiving.totalPacketsLost=packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost")}else{output.audio.sending.rtt=parseInt(item.googRtt||"0",10),output.audio.sending.audioInputLevel=parseInt(item.audioInputLevel||"0",10),output.audio.sending.echoReturnLoss=parseInt(item.googEchoCancellationReturnLoss||"0",10),output.audio.sending.echoReturnLossEnhancement=parseInt(item.googEchoCancellationReturnLossEnhancement||"0",10);var bytesSent=parseInt(item.bytesSent||"0",10);output.audio.sending.totalBytes=bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.audio.sending.totalPackets=packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent")}else if(0===prop.indexOf("inbound_rtp_audio"))output.audio.receiving.jitter=item.jitter||0,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if(0===prop.indexOf("outbound_rtp_audio")){output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.audio.sending.rtt=rtcpItem.roundTripTime||0}}else{output.audio.sending.targetBitrate=item.targetBitrate,output.audio.sending.rtt=item.roundTripTime,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.audio.sending.audioInputLevel=trackItem.audioLevel,output.audio.sending.echoReturnLoss=trackItem.echoReturnLoss,output.audio.sending.echoReturnLossEnhancement=trackItem.echoReturnLossEnhancement}},videoStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPVideoStream"))output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.framesDecoded=item.framesDecoded,output.video.receiving.qpSum=item.qpSum,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.video.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if(0===prop.indexOf("RTCMediaStreamTrack_remote_video_"))output.video.receiving.frameHeight=item.frameHeight,output.video.receiving.frameWidth=item.frameWidth,output.video.receiving.framesCorrupted=item.framesCorrupted,output.video.receiving.framesPerSecond=item.framesPerSecond,output.video.receiving.framesDropped=item.framesDropped,output.video.receiving.totalFrames=item.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,item,"framesReceived");else if(0===prop.indexOf("RTCOutboundRTPVideoStream"))output.video.sending.qpSum=item.qpSum,output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"video"===item.mediaType&&item.isRemote){output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,
-output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.receiving.framesCorrupted=trackItem.framesCorrupted,output.video.receiving.framesDropped=trackItem.framesDropped,output.video.receiving.framesDecoded=trackItem.framesDecoded,output.video.receiving.totalFrames=trackItem.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,trackItem,"framesReceived")}else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"video"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType)if(prop.indexOf("_recv")>0){output.video.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.video.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.video.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10),output.video.receiving.renderDelayMs=parseInt(item.googRenderDelayMs||"0",10),output.video.receiving.frameWidth=parseInt(item.googFrameWidthReceived||"0",10),output.video.receiving.frameHeight=parseInt(item.googFrameHeightReceived||"0",10),output.video.receiving.framesDecoded=parseInt(item.framesDecoded||"0",10),output.video.receiving.frameRateOutput=parseInt(item.googFrameRateOutput||"0",10),output.video.receiving.frameRateDecoded=parseInt(item.googFrameRateDecoded||"0",10),output.video.receiving.frameRateReceived=parseInt(item.googFrameRateReceived||"0",10),output.video.receiving.qpSum=parseInt(item.qpSum||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.video.receiving.totalBytes=bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.video.receiving.totalPackets=packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.video.receiving.totalPacketsLost=packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost");var nacksSent=parseInt(item.googNacksSent||"0",10);output.video.receiving.totalNacks=nacksSent,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"googNacksSent");var plisSent=parseInt(item.googPlisSent||"0",10);output.video.receiving.totalPlis=plisSent,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"googPlisSent");var firsSent=parseInt(item.googFirsSent||"0",10);output.video.receiving.totalFirs=firsSent,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"googFirsSent")}else{output.video.sending.rtt=parseInt(item.googRtt||"0",10),output.video.sending.frameWidth=parseInt(item.googFrameWidthSent||"0",10),output.video.sending.frameHeight=parseInt(item.googFrameHeightSent||"0",10),output.video.sending.framesEncoded=parseInt(item.framesEncoded||"0",10),output.video.sending.frameRateInput=parseInt(item.googFrameRateInput||"0",10),output.video.sending.frameRateEncoded=parseInt(item.googFrameRateEncoded||"0",10),output.video.sending.frameRateSent=parseInt(item.googFrameRateSent||"0",10),output.video.sending.cpuLimitedResolution="true"===item.googCpuLimitedResolution,output.video.sending.bandwidthLimitedResolution="true"===item.googBandwidthLimitedResolution;var bytesSent=parseInt(item.bytesSent||"0",10);output.video.sending.totalBytes=bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.video.sending.totalPackets=packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent");var nacksReceived=parseInt(item.googNacksReceived||"0",10);output.video.sending.totalNacks=nacksReceived,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"googNacksReceived");var plisReceived=parseInt(item.googPlisReceived||"0",10);output.video.sending.totalPlis=plisReceived,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"googPlisReceived");var firsReceived=parseInt(item.googFirsReceived||"0",10);output.video.sending.totalFirs=firsReceived,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"googFirsReceived")}else if(0===prop.indexOf("inbound_rtp_video"))output.video.receiving.jitter=item.jitter||0,output.video.receiving.framesDecoded=item.framesDecoded||0,output.video.receiving.frameRateMean=item.framerateMean||0,output.video.receiving.frameRateStdDev=item.framerateStdDev||0,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount");else if(0===prop.indexOf("outbound_rtp_video")){output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.frameRateMean=item.framerateMean||0,output.video.sending.frameRateStdDev=item.framerateStdDev||0,output.video.sending.framesDropped=item.droppedFrames||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.video.sending.rtt=rtcpItem.roundTripTime||0}}else{output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.roundTripTime=item.roundTripTime||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.sending.frameHeight=trackItem.frameHeight,output.video.sending.frameWidth=trackItem.frameWidth,output.video.sending.framesPerSecond=trackItem.framesPerSecond,output.video.sending.totalFrames=trackItem.framesSent,output.video.sending.frames=self._parseConnectionStats(prevStats,trackItem,"framesSent")}},videoE2EStatsFn=function(item,prop){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType){var captureStartNtpTimeMs=parseInt(item.googCaptureStartNtpTimeMs||"0",10),remoteStream=pc.getRemoteStreams()[0];if(!(captureStartNtpTimeMs>0&&prop.indexOf("_recv")>0&&remoteStream&&document&&"function"==typeof document.getElementsByTagName))return;try{var elements=document.getElementsByTagName("plugin"===AdapterJS.webrtcDetectedType?"object":"video");"plugin"!==AdapterJS.webrtcDetectedType&&0===elements.length&&(elements=document.getElementsByTagName("audio"));for(var e=0;e0))break;for(var ec=0;ec"],error)}}},successCbFn=function(stats){"function"==typeof stats.forEach?stats.forEach(function(item,prop){output.raw[prop]=item}):output.raw=stats;var edgeTracksKind={remote:{},local:{}};"edge"===AdapterJS.webrtcDetectedBrowser&&(pc.remoteStream&&pc.remoteStream.getTracks().forEach(function(track){edgeTracksKind.remote[track.id]=track.kind}),pc.localStream&&pc.localStream.getTracks().forEach(function(track){edgeTracksKind.local[track.id]=track.kind})),Object.keys(output.raw).forEach(function(prop){if(0!==prop.indexOf("ssrc_")||output.raw[prop].mediaType){if("edge"===AdapterJS.webrtcDetectedBrowser&&!output.raw[prop].mediaType&&["inboundrtp","outboundrtp"].indexOf(output.raw[prop].type)>-1){var trackItem=output.raw[output.raw[prop].mediaTrackId]||{};output.raw[prop].mediaType=edgeTracksKind[output.raw[prop].isRemote?"remote":"local"][trackItem.trackIdentifier]||""}}else output.raw[prop].mediaType=output.raw[prop].audioInputLevel||output.raw[prop].audioOutputLevel?"audio":"video";certificateFn(output.raw[prop],prop),candidatePairFn(output.raw[prop],prop),codecsFn(output.raw[prop],prop),audioStatsFn(output.raw[prop],prop),videoStatsFn(output.raw[prop],prop),videoE2EStatsFn(output.raw[prop],prop),isAutoBwStats&&!self._peerBandwidth[peerId][prop]?self._peerBandwidth[peerId][prop]=output.raw[prop]:isAutoBwStats||self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=output.raw[prop])}),output.audio.sending.bytes=output.audio.sending.bytes||0,output.audio.sending.packets=output.audio.sending.packets||0,output.audio.sending.totalBytes=output.audio.sending.totalBytes||0,output.audio.sending.totalPackets=output.audio.sending.totalPackets||0,output.video.sending.bytes=output.video.sending.bytes||0,output.video.sending.packets=output.video.sending.packets||0,output.video.sending.totalBytes=output.video.sending.totalBytes||0,output.video.sending.totalPackets=output.video.sending.totalPackets||0,output.audio.receiving.bytes=output.audio.receiving.bytes||0,output.audio.receiving.packets=output.audio.receiving.packets||0,output.audio.receiving.totalBytes=output.audio.receiving.totalBytes||0,output.audio.receiving.totalPackets=output.audio.receiving.totalPackets||0,output.video.receiving.bytes=output.video.receiving.bytes||0,output.video.receiving.packets=output.video.receiving.packets||0,output.video.receiving.totalBytes=output.video.receiving.totalBytes||0,output.video.receiving.totalPackets=output.video.receiving.totalPackets||0,callback(null,output)},errorCbFn=function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)};if("function"!=typeof pc.getStats)return errorCbFn(new Error("getStats() API is not available."));"plugin"===AdapterJS.webrtcDetectedType?pc.getStats(null,successCbFn,errorCbFn):pc.getStats(null).then(successCbFn).catch(errorCbFn)},Skylink.prototype._addPeer=function(targetMid,cert,peerBrowser,receiveOnly,isSS){var self=this;return self._peerConnections[targetMid]?void log.error([targetMid,null,null,"Connection to peer has already been made"]):(self._peerConnStatus[targetMid]={connected:!1,init:!1},log.log([targetMid,null,null,"Starting the connection to peer. Options provided:"],{peerBrowser:peerBrowser,receiveOnly:receiveOnly,enableDataChannel:self._enableDataChannel}),log.info("Adding peer",isSS),self._peerConnections[targetMid]=self._createPeerConnection(targetMid,!!isSS,cert),self._peerConnections[targetMid]?(self._peerConnStatus[targetMid].init=!0,void(self._peerConnections[targetMid].hasScreen=!!isSS)):void log.error([targetMid,null,null,"Failed creating the connection to peer."]))},Skylink.prototype._restartPeerConnection=function(peerId,doIceRestart,bwOptions,callback){var self=this;if(!self._peerConnections[peerId])return void log.error([peerId,null,null,"Peer does not have an existing connection. Unable to restart"]);var pc=self._peerConnections[peerId],agent=(self.getPeerInfo(peerId)||{}).agent||{};if(self._isLowerThanVersion(agent.SMProtocolVersion||"","0.1.2")){var notSupportedError=new Error("Failed restarting with other agents connecting from other SDKs as re-negotiation is not supported by other SDKs");return log.warn([peerId,"RTCPeerConnection",null,"Ignoring restart request as agent's SDK does not support it"],notSupportedError),void("function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(notSupportedError)))}if(pc.signalingState===self.PEER_CONNECTION_STATE.STABLE&&self._peerConnections[peerId]){log.log([peerId,null,null,"Sending restart message to signaling server ->"],{iceRestart:doIceRestart,options:bwOptions}),self._peerCustomConfigs[peerId]=self._peerCustomConfigs[peerId]||{},self._peerCustomConfigs[peerId].bandwidth=self._peerCustomConfigs[peerId].bandwidth||{},self._peerCustomConfigs[peerId].googleXBandwidth=self._peerCustomConfigs[peerId].googleXBandwidth||{},bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._peerCustomConfigs[peerId].bandwidth.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._peerCustomConfigs[peerId].bandwidth.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._peerCustomConfigs[peerId].bandwidth.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._peerCustomConfigs[peerId].googleXBandwidth.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._peerCustomConfigs[peerId].googleXBandwidth.max=bwOptions.googleXBandwidth.max));var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===doIceRestart&&self._enableIceRestart&&self._peerInformations[peerId]&&self._peerInformations[peerId].config.enableIceRestart,isRestartResend:!1,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._peerEndOfCandidatesCounter[peerId]=self._peerEndOfCandidatesCounter[peerId]||{},self._peerEndOfCandidatesCounter[peerId].len=0,self._sendChannelMessage(restartMsg),self._trigger("peerRestart",peerId,self.getPeerInfo(peerId),!0,!0===doIceRestart),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart callback"]),callback(null))}else if(pc.signalingState===self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER){var hasLocalDescription=pc.localDescription&&pc.localDescription.sdp;if(hasLocalDescription)self._sendChannelMessage({type:pc.localDescription.type,sdp:pc.localDescription.sdp,mid:self._user.sid,target:peerId,rid:self._room.id,restart:!0});else{var noLocalDescriptionError="Failed re-sending localDescription as there is no localDescription set to connection. There could be a handshaking step error";log.error([peerId,"RTCPeerConnection",null,noLocalDescriptionError],{localDescription:pc.localDescription,remoteDescription:pc.remoteDescription}),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(noLocalDescriptionError)))}}else{var unableToRestartError="Failed restarting as peer connection state is "+pc.signalingState;log.warn([peerId,"RTCPeerConnection",null,unableToRestartError]),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(unableToRestartError)))}},Skylink.prototype._removePeer=function(peerId){if(!this._peerConnections[peerId]&&!this._peerInformations[peerId])return void log.debug([peerId,"RTCPeerConnection",null,"Dropping the hangup from Peer as not connected to Peer at all."]);var peerInfo=clone(this.getPeerInfo(peerId))||{userData:"",settings:{audio:!1,video:!1,data:!1},mediaStatus:{audioMuted:!0,videoMuted:!0},agent:{name:"unknown",version:0,os:"",pluginVersion:null},config:{enableDataChannel:!0,enableIceRestart:!1,enableIceTrickle:!0,priorityWeight:0,publishOnly:!1,receiveOnly:!0},parentId:null,room:clone(this._selectedRoom)};"MCU"!==peerId?this._trigger("peerLeft",peerId,peerInfo,!1):(this._hasMCU=!1,log.log([peerId,null,null,"MCU has stopped listening and left"]),this._trigger("serverPeerLeft",peerId,this.SERVER_PEER_TYPE.MCU)),this._peerConnections[peerId]&&(this._peerConnections[peerId].signalingState!==this.PEER_CONNECTION_STATE.CLOSED&&(this._peerConnections[peerId].close(),"AppleWebKit"===AdapterJS.webrtcDetectedType&&(this._peerConnections[peerId].signalingStateClosed||(this._peerConnections[peerId].signalingStateClosed=!0,this._trigger("peerConnectionState",this.PEER_CONNECTION_STATE.CLOSED,peerId)),this._peerConnections[peerId].iceConnectionStateClosed||(this._peerConnections[peerId].iceConnectionStateClosed=!0,this._trigger("iceConnectionState",this.ICE_CONNECTION_STATE.CLOSED,peerId)))),"MCU"!==peerId&&this._handleEndedStreams(peerId),delete this._peerConnections[peerId]),this._peerInformations[peerId]&&delete this._peerInformations[peerId],this._peerMessagesStamps[peerId]&&delete this._peerMessagesStamps[peerId],this._streamsSession[peerId]&&delete this._streamsSession[peerId],this._peerEndOfCandidatesCounter[peerId]&&delete this._peerEndOfCandidatesCounter[peerId],this._peerCandidatesQueue[peerId]&&delete this._peerCandidatesQueue[peerId],this._sdpSessions[peerId]&&delete this._sdpSessions[peerId],this._peerStats[peerId]&&delete this._peerStats[peerId],this._peerBandwidth[peerId]&&delete this._peerBandwidth[peerId],this._gatheredCandidates[peerId]&&delete this._gatheredCandidates[peerId],this._peerCustomConfigs[peerId]&&delete this._peerCustomConfigs[peerId],this._peerConnStatus[peerId]&&delete this._peerConnStatus[peerId],this._dataChannels[peerId]&&this._closeDataChannel(peerId),log.log([peerId,"RTCPeerConnection",null,"Successfully removed peer"])},Skylink.prototype._createPeerConnection=function(targetMid,isScreenSharing,cert){var pc,self=this;if(self._inRoom&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)){var constraints={iceServers:self._room.connection.peerConfig.iceServers,iceTransportPolicy:self._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(self._useEdgeWebRTC&&window.msRTCPeerConnection?window.msRTCPeerConnection:RTCPeerConnection)(constraints,optional)}catch(error){return log.error([targetMid,null,null,"Failed creating peer connection:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),null}pc.setOffer="",pc.setAnswer="",pc.hasStream=!1,pc.hasScreen=!!isScreenSharing,pc.hasMainChannel=!1,pc.firefoxStreamId="",pc.processingLocalSDP=!1,pc.processingRemoteSDP=!1,pc.gathered=!1,pc.gathering=!1,pc.localStream=null,pc.localStreamId=null,pc.remoteStream=null,pc.remoteStreamId=null,pc.iceConnectionStateClosed=!1,pc.signalingStateClosed=!1,self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}},self._streamsSession[targetMid]=self._streamsSession[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._sdpSessions[targetMid]={local:{},remote:{}},self._peerBandwidth[targetMid]={};var bandwidth=null;return pc.ondatachannel=function(event){var dc=event.channel||event;if(log.debug([targetMid,"RTCDataChannel",dc.label,"Received datachannel ->"],dc),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel){self.DATA_CHANNEL_TYPE.DATA,dc.label;pc.hasMainChannel||(self.DATA_CHANNEL_TYPE.MESSAGING,"main",pc.hasMainChannel=!0),self._createDataChannel(targetMid,dc)}else log.warn([targetMid,"RTCDataChannel",dc.label,"Not adding datachannel as enable datachannel is set to false"])},pc.onaddstream=function(evt){if(self._peerConnections[targetMid]){var stream=evt.stream||evt;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received empty remote stream ->"],stream);pc.remoteStream=stream,pc.remoteStreamId=pc.remoteStreamId||stream.id||stream.label;var peerSettings=clone(self.getPeerInfo(targetMid).settings);self._streamsSession[targetMid][pc.remoteStreamId]=peerSettings,0===stream.getAudioTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].audio=!1),0===stream.getVideoTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].video=!1),pc.hasStream=!0,pc.hasScreen=peerSettings.video&&"object"==typeof peerSettings.video&&peerSettings.video.screenshare,self._onRemoteStreamAdded(targetMid,stream,!!pc.hasScreen)}},pc.onicecandidate=function(event){self._onIceCandidate(targetMid,event.candidate||event)},pc.oniceconnectionstatechange=function(evt){var iceConnectionState=pc.iceConnectionState;if(log.debug([targetMid,"RTCIceConnectionState",null,"Ice connection state changed ->"],iceConnectionState),"edge"===AdapterJS.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),"AppleWebKit"===AdapterJS.webrtcDetectedType&&iceConnectionState===self.ICE_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.iceConnectionStateClosed||self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.CLOSED,targetMid)},10);if(self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._enableIceTrickle&&self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.TRICKLE_FAILED,targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].connected=[self.ICE_CONNECTION_STATE.COMPLETED,self.ICE_CONNECTION_STATE.CONNECTED].indexOf(iceConnectionState)>-1),!self._hasMCU&&[self.ICE_CONNECTION_STATE.CONNECTED,self.ICE_CONNECTION_STATE.COMPLETED].indexOf(iceConnectionState)>-1&&self._bandwidthAdjuster&&!bandwidth&&"edge"!==AdapterJS.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),"AppleWebKit"===AdapterJS.webrtcDetectedType&&pc.signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.signalingStateClosed||self._trigger("peerConnectionState",self.PEER_CONNECTION_STATE.CLOSED,targetMid)},10);self._trigger("peerConnectionState",pc.signalingState,targetMid)},pc.onicegatheringstatechange=function(){log.log([targetMid,"RTCIceGatheringState",null,"Ice gathering state changed ->"],pc.iceGatheringState),self._trigger("candidateGenerationState",pc.iceGatheringState,targetMid)},"firefox"===AdapterJS.webrtcDetectedBrowser&&(pc.removeStream=function(stream){for(var senders=pc.getSenders(),s=0;s"],restartMsg),self._sendChannelMessage(restartMsg)};bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=bwOptions.googleXBandwidth.max));for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers},null):callback(null,{listOfPeers:listOfPeers}))};self.once("peerJoined",peerJoinedFn,function(peerId,peerInfo,isSelf){return isSelf}),self.leaveRoom(!1,function(error,success){if(error){if("function"==typeof callback){for(var i=0;i=self._peerEndOfCandidatesCounter[targetMid].expectedLen&&(!self._peerCandidatesQueue[targetMid]||0===self._peerCandidatesQueue[targetMid].length)&&!self._peerEndOfCandidatesCounter[targetMid].hasSet){log.debug([targetMid,"RTCPeerConnection",null,"Signaling of end-of-candidates remote ICE gathering."]),self._peerEndOfCandidatesCounter[targetMid].hasSet=!0;try{if("edge"===AdapterJS.webrtcDetectedBrowser){for(var mLineCounter=-1,addedMids=[],sdpLines=self._peerConnections[targetMid].remoteDescription.sdp.split("\r\n"),rejected=!1,i=0;i"],error)}}},Skylink.prototype.setUserData=function(userData){var self=this,updatedUserData="";void 0!==userData&&null!==userData&&(updatedUserData=userData),this._userData=updatedUserData,self._inRoom?(log.log("Updated userData -> ",updatedUserData),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.UPDATE_USER,mid:self._user.sid,rid:self._room.id,userData:updatedUserData,stamp:(new Date).getTime()}),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0)):log.warn("User is not in the room. Broadcast of updated information will be dropped")},Skylink.prototype.getUserData=function(peerId){if(peerId&&this._peerInformations[peerId]){var userData=this._peerInformations[peerId].userData;return null!==userData&&void 0===userData||(userData=""),userData}return this._userData},Skylink.prototype.getPeerInfo=function(peerId){var peerInfo=null;return"string"==typeof peerId&&"object"==typeof this._peerInformations[peerId]?(peerInfo=clone(this._peerInformations[peerId]),peerInfo.room=clone(this._selectedRoom),peerInfo.settings.bandwidth=peerInfo.settings.bandwidth||{},peerInfo.settings.googleXBandwidth=peerInfo.settings.googleXBandwidth||{},"boolean"==typeof peerInfo.settings.video||peerInfo.settings.video&&"object"==typeof peerInfo.settings.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"==typeof peerInfo.settings.audio||peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.audioMuted&&(peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.videoMuted&&(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.maxBandwidth&&(peerInfo.settings.bandwidth=clone(peerInfo.settings.maxBandwidth),delete peerInfo.settings.maxBandwidth),peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&peerInfo.settings.video.customSettings&&"object"==typeof peerInfo.settings.video.customSettings&&(peerInfo.settings.video.customSettings.frameRate&&(peerInfo.settings.video.frameRate=clone(peerInfo.settings.video.customSettings.frameRate)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode)),peerInfo.settings.video.customSettings.width&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.width=clone(peerInfo.settings.video.customSettings.width)),peerInfo.settings.video.customSettings.height&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.height=clone(peerInfo.settings.video.customSettings.height)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode))),peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&(peerInfo.settings.audio.stereo=!0===peerInfo.settings.audio.stereo),null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),peerInfo.parentId=peerInfo.parentId||null,"MCU"===peerId?(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1):this._hasMCU&&(peerInfo.config.receiveOnly=!1,peerInfo.config.publishOnly=!0),this._sdpSettings.direction.audio.receive||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.direction.video.receive||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.data=!!(this._dataChannels[peerId]&&this._dataChannels[peerId].main&&this._dataChannels[peerId].main.channel&&this._dataChannels[peerId].main.channel.readyState===this.DATA_CHANNEL_STATE.OPEN),peerInfo.connected=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].connected,peerInfo.init=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].init,this._sdpSessions[peerId]&&this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&"object"==typeof this._sdpSessions[peerId].remote.connection&&(this._sdpSessions[peerId].remote.connection.audio&&this._sdpSessions[peerId].remote.connection.audio.indexOf("send")>-1||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSessions[peerId].remote.connection.video&&this._sdpSessions[peerId].remote.connection.video.indexOf("send")>-1||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSessions[peerId].remote.connection.data&&this._sdpSessions[peerId].remote.connection.data.indexOf("send")>-1||(peerInfo.settings.data=!1))):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,os:window.navigator.platform,pluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:this.SMProtocolVersion,DTProtocolVersion:this.DTProtocolVersion},room:clone(this._selectedRoom),config:{enableDataChannel:this._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;i-1||(customSettings.settings.audio=!1,customSettings.mediaStatus.audioMuted=!0),self._sdpSessions[usePeerId].local.connection.video&&self._sdpSessions[usePeerId].local.connection.video.indexOf("send")>-1||(customSettings.settings.video=!1,customSettings.mediaStatus.videoMuted=!0),self._sdpSessions[usePeerId].local.connection.data&&self._sdpSessions[usePeerId].local.connection.data.indexOf("send")>-1||(customSettings.settings.data=!1)),customSettings},Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo()),userCustomInfoForPeer=peerId?this._getPeerCustomSettings(peerId):null;return userCustomInfoForPeer&&"object"==typeof userCustomInfoForPeer&&(userInfo.settings=userCustomInfoForPeer.settings,userInfo.mediaStatus=userCustomInfoForPeer.mediaStatus),userInfo.settings.video&&"object"==typeof userInfo.settings.video&&(userInfo.settings.video.customSettings={},userInfo.settings.video.frameRate&&"object"==typeof userInfo.settings.video.frameRate&&(userInfo.settings.video.customSettings.frameRate=clone(userInfo.settings.video.frameRate),userInfo.settings.video.frameRate=-1),userInfo.settings.video.facingMode&&"object"==typeof userInfo.settings.video.facingMode&&(userInfo.settings.video.customSettings.facingMode=clone(userInfo.settings.video.facingMode),userInfo.settings.video.facingMode="-1"),userInfo.settings.video.resolution&&"object"==typeof userInfo.settings.video.resolution&&(userInfo.settings.video.resolution.width&&"object"==typeof userInfo.settings.video.resolution.width&&(userInfo.settings.video.customSettings.width=clone(userInfo.settings.video.width),userInfo.settings.video.resolution.width=-1),userInfo.settings.video.resolution.height&&"object"==typeof userInfo.settings.video.resolution.height&&(userInfo.settings.video.customSettings.height=clone(userInfo.settings.video.height),userInfo.settings.video.resolution.height=-1))),userInfo.settings.bandwidth&&(userInfo.settings.maxBandwidth=clone(userInfo.settings.bandwidth),delete userInfo.settings.bandwidth),this._getSDPCommonSupports(peerId).video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._getSDPCommonSupports(peerId).audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart){var self=this,pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of creating of offer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription","offer",'Dropping of creating of offer as signalingState is not "'+self.PEER_CONNECTION_STATE.STABLE+'" ->'],pc.signalingState);var offerConstraints={offerToReceiveAudio:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).video,offerToReceiveVideo:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).audio,iceRestart:!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,voiceActivityDetection:self._voiceActivityDetection};self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._dataChannels[targetMid]&&self._dataChannels[targetMid].main||(self._createDataChannel(targetMid),self._peerConnections[targetMid].hasMainChannel=!0)),log.debug([targetMid,null,null,"Creating offer with config:"],offerConstraints),pc.endOfCandidates=!1,self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=offerConstraints);var onSuccessCbFn=function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)};pc.createOffer(onSuccessCbFn,onErrorCbFn,"plugin"===AdapterJS.webrtcDetectedType?{mandatory:{OfferToReceiveAudio:offerConstraints.offerToReceiveAudio,OfferToReceiveVideo:offerConstraints.offerToReceiveVideo,iceRestart:offerConstraints.iceRestart,voiceActivityDetection:offerConstraints.voiceActivityDetection}}:offerConstraints)},Skylink.prototype._doAnswer=function(targetMid){var self=this;log.log([targetMid,null,null,"Creating answer with config:"],self._room.connection.sdpConstraints);var pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of creating of answer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription","answer",'Dropping of creating of answer as signalingState is not "'+self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER+'" ->'],pc.signalingState);var answerConstraints="edge"===AdapterJS.webrtcDetectedBrowser?{offerToReceiveVideo:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).video,offerToReceiveAudio:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).audio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints);var onSuccessCbFn=function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},onErrorCbFn=function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.createAnswer(onSuccessCbFn,onErrorCbFn,answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,_sessionDescription){var self=this,pc=self._peerConnections[targetMid];if(!_sessionDescription||!_sessionDescription.sdp)return void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],_sessionDescription);if(!pc)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as connection does not exists ->"],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(pc.processingLocalSDP)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as another is being processed ->"],_sessionDescription);pc.processingLocalSDP=!0;var sessionDescription={type:_sessionDescription.type,sdp:_sessionDescription.sdp};sessionDescription.sdp=self._removeSDPFirefoxH264Pref(targetMid,sessionDescription),sessionDescription.sdp=self._setSDPCodecParams(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPUnknownAptRtx(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPCodecs(targetMid,sessionDescription),sessionDescription.sdp=self._handleSDPConnectionSettings(targetMid,sessionDescription,"local"),sessionDescription.sdp=self._removeSDPREMBPackets(targetMid,sessionDescription),log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description updated ->"],sessionDescription.sdp);var onSuccessCbFn=function(){if(log.debug([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description has been set ->"],sessionDescription),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",sessionDescription.type,targetMid),sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER?pc.setAnswer="local":pc.setOffer="local",!self._enableIceTrickle&&!pc.gathered)return void log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description sending is halted to complete ICE gathering."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},onErrorCbFn=function(error){log.error([targetMid,"RTCSessionDescription",sessionDescription.type,"Local description failed setting ->"],error),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.setLocalDescription(new RTCSessionDescription(sessionDescription),onSuccessCbFn,onErrorCbFn)},Skylink.prototype.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:error instanceof Error?error:new Error(JSON.stringify(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);if("AppleWebKit"===AdapterJS.webrtcDetectedType){var checkStream=self._streams.screenshare&&self._streams.screenshare.stream?self._streams.screenshare.stream:self._streams.userMedia&&self._streams.userMedia.stream?self._streams.userMedia.stream:null;checkStream&&0!==checkStream.getTracks().length?0===checkStream.getAudioTracks().length?log.warn("Note that receiving audio streams may fail as safari 11 needs stream with audio and video tracks and not just with video tracks"):0===checkStream.getVideoTracks().length&&log.warn("Note that receiving video streams may fail as safari 11 needs stream with audio and video tracks and not just with audio tracks"):log.warn("Note that receiving audio and video streams may fail as safari 11 needs stream with audio and video tracks")}if("function"==typeof callback){var peerOnJoin=function(peerId,peerInfo,isSelf){self.off("systemAction",peerFailedJoin),self.off("channelClose",peerSocketFailedJoin),log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo})},peerFailedJoin=function(action,message){self.off("peerJoined",peerOnJoin),self.off("channelClose",peerSocketFailedJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room ->"],message),resolveAsErrorFn(new Error(message),self._selectedRoom,self._readyState)},peerSocketFailedJoin=function(){self.off("systemAction",peerFailedJoin),self.off("peerJoined",peerOnJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room due to abrupt disconnection."]),resolveAsErrorFn(new Error("Channel closed abruptly before session was established"),self._selectedRoom,self._readyState)};self.once("peerJoined",peerOnJoin,function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),self.once("systemAction",peerFailedJoin,function(action){return action===self.SYSTEM_ACTION.REJECT}),self.once("channelClose",peerSocketFailedJoin)}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.JOIN_ROOM,uid:self._user.uid,cid:self._key,rid:self._room.id,userCred:self._user.token,timeStamp:self._user.timeStamp,apiOwner:self._appKeyOwner,roomCred:self._room.token,start:self._room.startDateTime,len:self._room.duration,isPrivileged:!0===self._isPrivileged,autoIntroduce:!1!==self._autoIntroduce,key:self._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=!1===mediaOptions.audio&&!1===mediaOptions.video;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?!1===stopMediaOptions&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=!1!==stopMediaOptions.userMedia,stopScreenshare=!1!==stopMediaOptions.screenshare):"function"==typeof stopMediaOptions&&(callback=stopMediaOptions);for(var infoPeerId in self._peerInformations)self._peerInformations.hasOwnProperty(infoPeerId)&&self._peerInformations[infoPeerId]&&(peersThatLeft.push(infoPeerId),self._removePeer(infoPeerId));for(var connPeerId in self._peerConnections)self._peerConnections.hasOwnProperty(connPeerId)&&self._peerConnections[connPeerId]&&-1===peersThatLeft.indexOf(connPeerId)&&(peersThatLeft.push(connPeerId),self._removePeer(connPeerId));if(self._inRoom=!1,self._closeChannel(),isNotInRoom){var notInRoomError="Unable to leave room as user is not in any room";return log.error([null,"Room",previousRoom,notInRoomError]),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}self._stopStreams({userMedia:stopUserMedia,screenshare:stopScreenshare}),self._wait(function(){log.log([null,"Room",previousRoom,"User left the room"]),self._trigger("peerLeft",previousUserPeerId,self.getPeerInfo(),!0),"function"==typeof callback&&callback(null,{peerId:previousUserPeerId,previousRoom:previousRoom})},function(){return!self._channelOpen})},Skylink.prototype.lockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!0),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!0}),this._roomLocked=!0,this._trigger("roomLock",!0,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype.unlockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!1),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!1}),this._roomLocked=!1,this._trigger("roomLock",!1,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype._waitForOpenChannel=function(mediaOptions,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){var onChannelOpen=function(){self.off("socketError",onChannelError),setTimeout(function(){if(mediaOptions=mediaOptions||{},self._userData=mediaOptions.userData||self._userData||"",self._streamsBandwidthSettings={googleX:{},bAS:{}},self._publishOnly=!1,self._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},self._voiceActivityDetection="boolean"!=typeof mediaOptions.voiceActivityDetection||mediaOptions.voiceActivityDetection,self._peerConnectionConfig={bundlePolicy:self.BUNDLE_POLICY.BALANCED,rtcpMuxPolicy:self.RTCP_MUX_POLICY.REQUIRE,iceCandidatePoolSize:0,certificate:self.PEER_CERTIFICATE.AUTO},self._bandwidthAdjuster=null,mediaOptions.bandwidth&&("number"==typeof mediaOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=mediaOptions.bandwidth.audio),"number"==typeof mediaOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=mediaOptions.bandwidth.video),"number"==typeof mediaOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=mediaOptions.bandwidth.data)),mediaOptions.googleXBandwidth&&("number"==typeof mediaOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=mediaOptions.googleXBandwidth.min),"number"==typeof mediaOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=mediaOptions.googleXBandwidth.max)),mediaOptions.sdpSettings&&(mediaOptions.sdpSettings.direction&&(mediaOptions.sdpSettings.direction.audio&&(self._sdpSettings.direction.audio.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.receive||mediaOptions.sdpSettings.direction.audio.receive,self._sdpSettings.direction.audio.send="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.send||mediaOptions.sdpSettings.direction.audio.send),mediaOptions.sdpSettings.direction.video&&(self._sdpSettings.direction.video.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.video.receive||mediaOptions.sdpSettings.direction.video.receive,self._sdpSettings.direction.video.send="boolean"!=typeof mediaOptions.sdpSettings.direction.video.send||mediaOptions.sdpSettings.direction.video.send)),mediaOptions.sdpSettings.connection&&(self._sdpSettings.connection.audio="boolean"!=typeof mediaOptions.sdpSettings.connection.audio||mediaOptions.sdpSettings.connection.audio,self._sdpSettings.connection.video="boolean"!=typeof mediaOptions.sdpSettings.connection.video||mediaOptions.sdpSettings.connection.video,self._sdpSettings.connection.data="boolean"!=typeof mediaOptions.sdpSettings.connection.data||mediaOptions.sdpSettings.connection.data)),mediaOptions.publishOnly&&(self._sdpSettings.direction.audio.send=!0,self._sdpSettings.direction.audio.receive=!1,self._sdpSettings.direction.video.send=!0,self._sdpSettings.direction.video.receive=!1,self._publishOnly=!0,"object"==typeof mediaOptions.publishOnly&&mediaOptions.publishOnly.parentId&&"string"==typeof mediaOptions.publishOnly.parentId&&(self._parentId=mediaOptions.publishOnly.parentId)),mediaOptions.parentId&&(self._parentId=mediaOptions.parentId),mediaOptions.peerConnection&&"object"==typeof mediaOptions.peerConnection){if("string"==typeof mediaOptions.peerConnection.bundlePolicy)for(var bpProp in self.BUNDLE_POLICY)self.BUNDLE_POLICY.hasOwnProperty(bpProp)&&self.BUNDLE_POLICY[bpProp]===mediaOptions.peerConnection.bundlePolicy&&(self._peerConnectionConfig.bundlePolicy=mediaOptions.peerConnection.bundlePolicy);if("string"==typeof mediaOptions.peerConnection.rtcpMuxPolicy)for(var rmpProp in self.RTCP_MUX_POLICY)self.RTCP_MUX_POLICY.hasOwnProperty(rmpProp)&&self.RTCP_MUX_POLICY[rmpProp]===mediaOptions.peerConnection.rtcpMuxPolicy&&(self._peerConnectionConfig.rtcpMuxPolicy=mediaOptions.peerConnection.rtcpMuxPolicy);if("number"==typeof mediaOptions.peerConnection.iceCandidatePoolSize&&mediaOptions.peerConnection.iceCandidatePoolSize>0&&(self._peerConnectionConfig.iceCandidatePoolSize=mediaOptions.peerConnection.iceCandidatePoolSize),"string"==typeof mediaOptions.peerConnection.certificate)for(var pcProp in self.PEER_CERTIFICATE)self.PEER_CERTIFICATE.hasOwnProperty(pcProp)&&self.PEER_CERTIFICATE[pcProp]===mediaOptions.peerConnection.certificate&&(self._peerConnectionConfig.certificate=mediaOptions.peerConnection.certificate)}if(mediaOptions.autoBandwidthAdjustment&&(self._bandwidthAdjuster={interval:10,limitAtPercentage:100,useUploadBwOnly:!1},"object"==typeof mediaOptions.autoBandwidthAdjustment&&("number"==typeof mediaOptions.autoBandwidthAdjustment.interval&&mediaOptions.autoBandwidthAdjustment.interval>=10&&(self._bandwidthAdjuster.interval=mediaOptions.autoBandwidthAdjustment.interval),"number"==typeof mediaOptions.autoBandwidthAdjustment.limitAtPercentage&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage>=0&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage<=100&&(self._bandwidthAdjuster.limitAtPercentage=mediaOptions.autoBandwidthAdjustment.limitAtPercentage),"boolean"==typeof mediaOptions.autoBandwidthAdjustment.useUploadBwOnly&&(self._bandwidthAdjuster.useUploadBwOnly=mediaOptions.autoBandwidthAdjustment.useUploadBwOnly))),!0===mediaOptions.manualGetUserMedia){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){!0===mediaAccessRequiredFailure?self._onUserMediaError(new Error("Waiting for stream timeout"),!1,!1):callback(null,self._streams.userMedia.stream)},function(){return current50Block+=1,600===current50Block?(mediaAccessRequiredFailure=!0,!0):!(!self._streams.userMedia||!self._streams.userMedia.stream)||void 0},50)}if(mediaOptions.audio||mediaOptions.video)return void self.getUserMedia({useExactConstraints:!!mediaOptions.useExactConstraints,audio:mediaOptions.audio,video:mediaOptions.video},function(error,success){error?callback(error,null):callback(null,success)});callback(null,null)},1)},onChannelError=function(errorState,error){self.off("channelOpen",onChannelOpen),callback(error)};self._channelOpen?onChannelOpen():(self.once("channelOpen",onChannelOpen),self.once("socketError",onChannelError,function(errorState){return errorState===self.SOCKET_ERROR.RECONNECTION_ABORTED}),self._openChannel())},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.25",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,useEdgeWebRTC=!1,enableSimultaneousTransfers=!0;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,useEdgeWebRTC="boolean"==typeof options.useEdgeWebRTC?options.useEdgeWebRTC:useEdgeWebRTC,enableSimultaneousTransfers="boolean"==typeof options.enableSimultaneousTransfers?options.enableSimultaneousTransfers:enableSimultaneousTransfers,"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,"sprop-stereo":"boolean"==typeof options.codecParams.audio.opus["sprop-stereo"]?options.codecParams.audio.opus["sprop-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),!0===forceTURN&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===AdapterJS.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,self._useEdgeWebRTC=useEdgeWebRTC,self._enableSimultaneousTransfers=enableSimultaneousTransfers,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,useEdgeWebRTC:self._useEdgeWebRTC,enableSimultaneousTransfers:self._enableSimultaneousTransfers}),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,useEdgeWebRTC:self._useEdgeWebRTC,enableSimultaneousTransfers:self._enableSimultaneousTransfers})):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:error.content instanceof Error?error.content:new Error(JSON.stringify(error.content)),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:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.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;if("function"!=typeof(globals.AdapterJS||window.AdapterJS||{}).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 globals.io||window.io?window.XMLHttpRequest?self._path?void AdapterJS.webRTCReady(function(){if(self._enableIceRestart="firefox"!==AdapterJS.webrtcDetectedBrowser||AdapterJS.webrtcDetectedVersion>=48,self._binaryChunkType="firefox"===AdapterJS.webrtcDetectedBrowser?self.DATA_TRANSFER_DATA_TYPE.BLOB:self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&"plugin"===AdapterJS.webrtcDetectedType?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"plugin"===AdapterJS.webrtcDetectedType&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=-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,useEdgeWebRTC:self._useEdgeWebRTC,enableSimultaneousTransfers:self._enableSimultaneousTransfers};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_KEY="SkylinkJS",_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=_LOG_KEY;if("object"==typeof message){if(outputLog+=message[0]?" ["+message[0]+"] -":" -",outputLog+=message[1]?" <<"+message[1]+">>":"",message[2])if(outputLog+=" ","object"==typeof message[2])for(var i=0;i=logLevel)if(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace){void 0===console.trace&&logLevel[3];void 0!==debugObject?(console[_LOG_LEVELS[logLevel]](outputLog,debugObject),void 0!==console.trace&&console.trace("")):(console[_LOG_LEVELS[logLevel]](outputLog),void 0!==console.trace&&console.trace(""))}else void 0!==debugObject?console[_LOG_LEVELS[logLevel]](outputLog,debugObject):console[_LOG_LEVELS[logLevel]](outputLog)},log={debug:function(message,object){_logFn(4,message,object)},log:function(message,object){_logFn(3,message,object)},info:function(message,object){_logFn(2,message,object)},warn:function(message,object){_logFn(1,message,object)},error:function(message,object){_logFn(0,message,object)}};Skylink.prototype.setLogLevel=function(logLevel){for(var level in this.LOG_LEVEL)if(this.LOG_LEVEL[level]===logLevel)return _logLevel=logLevel,void log.log([null,"Log",level,"Log level exists. Level is set"]);log.error([null,"Log",level,"Log level does not exist. Level is not set"])},Skylink.prototype.setDebugMode=function(isDebugMode){isDebugMode&&"object"==typeof isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0===isDebugMode.trace,_enableDebugStack=!0===isDebugMode.storeLogs):!0===isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)};Skylink.prototype.on=function(eventName,callback){"function"==typeof callback?(this._EVENTS[eventName]=this._EVENTS[eventName]||[],this._EVENTS[eventName].push(callback),log.log([null,"Event",eventName,"Event is subscribed"])):log.error([null,"Event",eventName,"Provided parameter is not a function"])},Skylink.prototype.once=function(eventName,callback,condition,fireAlways){"boolean"==typeof condition&&(fireAlways=condition,condition=null),fireAlways=void 0!==fireAlways&&fireAlways,condition="function"!=typeof condition?function(){return!0}:condition,"function"==typeof callback?(this._onceEvents[eventName]=this._onceEvents[eventName]||[],this._onceEvents[eventName].push([callback,condition,fireAlways]),log.log([null,"Event",eventName,"Event is subscribed on condition"])):log.error([null,"Event",eventName,"Provided callback is not a function"])},Skylink.prototype.off=function(eventName,callback){if(eventName&&"string"==typeof eventName){if(void 0===callback)return this._EVENTS[eventName]=[],this._onceEvents[eventName]=[],void log.log([null,"Event",eventName,"All events are unsubscribed"]);for(var arr=this._EVENTS[eventName]||[],once=this._onceEvents[eventName]||[],i=0;i"],message);self._user.sid&&!self._peerMessagesStamps[self._user.sid]&&(self._peerMessagesStamps[self._user.sid]={userData:0,audioMuted:0,videoMuted:0});var checkStampFn=function(statusMessage){return statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].userData:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].videoMuted:statusMessage.type!==self._SIG_MESSAGE_TYPE.MUTE_AUDIO||!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].audioMuted},setStampFn=function(statusMessage){statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?self._peerMessagesStamps[self._user.sid].userData=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?self._peerMessagesStamps[self._user.sid].videoMuted=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&(self._peerMessagesStamps[self._user.sid].audioMuted=statusMessage.stamp)},setQueueFn=function(){log.debug([null,"Socket",null,"Starting queue timeout"]),self._socketMessageTimeout=setTimeout(function(){if((new Date).getTime()-self._timestamp.socketMessage<=interval)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},interval-((new Date).getTime()-self._timestamp.socketMessage))},triggerEventFn=function(eventMessage){eventMessage.type===self._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE&&self._trigger("incomingMessage",{content:eventMessage.data,isPrivate:!1,targetPeerId:null,listOfPeers:Object.keys(self._peerInformations),isDataChannel:!1,senderPeerId:self._user.sid},self._user.sid,self.getPeerInfo(),!0)},sendGroupMessageFn=function(groupMessageList){if(self._socketMessageTimeout=null,!(self._channelOpen&&self._user&&self._user.sid&&self._socket))return void log.warn([message.target||"Server","Socket",null,"Dropping of group messages as Socket connection is not opened or is at incorrect step ->"],groupMessageList);for(var strGroupMessageList=[],stamps={userData:0,audioMuted:0,videoMuted:0},k=0;kself._peerMessagesStamps[self._user.sid].userData&&groupMessageList[k].stamp>stamps.userData?stamps.userData=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].audioMuted&&groupMessageList[k].stamp>stamps.audioMuted?stamps.audioMuted=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].videoMuted&&groupMessageList[k].stamp>stamps.videoMuted&&(stamps.videoMuted=groupMessageList[k].stamp));for(var i=0;i"],clone(groupMessageList[i])),groupMessageList.splice(i,1),i--):strGroupMessageList.push(JSON.stringify(groupMessageList[i]));if(strGroupMessageList.length>0){var groupMessage={type:self._SIG_MESSAGE_TYPE.GROUP,lists:strGroupMessageList,mid:self._user.sid,rid:self._room.id};log.log([message.target||"Server","Socket",groupMessage.type,"Sending queued grouped message (max: 16 per group) ->"],clone(groupMessage)),self._socket.send(JSON.stringify(groupMessage)),self._timestamp.socketMessage=(new Date).getTime();for(var j=0;j0&&(self._socketMessageQueue.length-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=interval)log.debug([message.target||"Server","Socket",message.type,"Queueing socket message to prevent message drop ->"],clone(message)),self._socketMessageQueue.push(message),self._socketMessageTimeout||setQueueFn();else{if(!checkStampFn(message))return void log.warn([message.target||"Server","Socket",message.type,"Dropping of outdated status message ->"],clone(message));self._socketMessageTimeout&&clearTimeout(self._socketMessageTimeout),log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),setStampFn(message),triggerEventFn(message),self._timestamp.socketMessage=(new Date).getTime()}else log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),message.type===self._SIG_MESSAGE_TYPE.BYE&&self._inRoom&&self._user&&self._user.sid&&message.mid===self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo()))},Skylink.prototype._createSocket=function(type){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:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._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:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._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:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "enter" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid)}self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0};var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),receiveOnly:self.getPeerInfo().config.receiveOnly,os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg),isNewPeer&&self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._restartHandler=function(message){var self=this,targetMid=message.mid,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "restart" received ->'],message),!self._peerInformations[targetMid])return void log.error([targetMid,"RTCPeerConnection",null,"Peer does not have an existing session. Ignoring restart process."]);if("MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId or publishOnly case ->'],message);if(self._hasMCU&&!self._mcuUseRenegoRestart)return log.warn([targetMid,"RTCPeerConnection",null,"Dropping restart request as MCU does not support re-negotiation. Restart workaround is to re-join Room for Peer."]),void self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!1);if(self._peerInformations[targetMid]=userInfo,self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid].len=0,self._peerPriorityWeight>message.weight){if(log.debug([targetMid,"RTCPeerConnection",null,"Re-negotiating new offer/answer."]),self._peerMessagesStamps[targetMid].hasRestart)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "restart" received.']);self._peerMessagesStamps[targetMid].hasRestart=!0,self._doOffer(targetMid,!0===message.doIceRestart,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start re-negotiation."]);var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===message.doIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,isRestartResend:!0,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._sendChannelMessage(restartMsg)}self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!0===message.doIceRestart)},Skylink.prototype._welcomeHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "welcome" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)}if(self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0,hasWelcome:!1},self._hasMCU||self._peerPriorityWeight>message.weight){if(self._peerMessagesStamps[targetMid].hasWelcome)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "welcome" received.']);log.debug([targetMid,"RTCPeerConnection",null,"Starting negotiation"]),self._peerMessagesStamps[targetMid].hasWelcome=!0,self._doOffer(targetMid,!1,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start negotiation."]);var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg)}};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._offerHandler=function(message){var self=this,targetMid=message.mid,pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for offer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}log.log([targetMid,null,message.type,"Received offer from peer. Session description:"],clone(message));var offer={type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],offer),offer.sdp=self._removeSDPFilteredCandidates(targetMid,offer),offer.sdp=self._setSDPCodec(targetMid,offer),offer.sdp=self._setSDPBitrate(targetMid,offer),offer.sdp=self._setSDPCodecParams(targetMid,offer),offer.sdp=self._removeSDPCodecs(targetMid,offer),offer.sdp=self._removeSDPREMBPackets(targetMid,offer),offer.sdp=self._handleSDPConnectionSettings(targetMid,offer,"remote"),offer.sdp=self._removeSDPUnknownAptRtx(targetMid,offer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "stable" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.resend});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,offer);var onSuccessCbFn=function(){log.debug([targetMid,"RTCSessionDescription",message.type,"Remote description set"]),pc.setOffer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.OFFER,targetMid),self._addIceCandidateFromQueue(targetMid),self._doAnswer(targetMid)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,offer:offer})};pc.setRemoteDescription(new RTCSessionDescription(offer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._candidateHandler=function(message){var targetMid=message.mid;if(!message.candidate&&!message.id)return void log.warn([targetMid,"RTCIceCandidate",null,"Received invalid ICE candidate message ->"],message);var canId="can-"+(new Date).getTime(),candidateType=message.candidate.split(" ")[7]||"",candidate=new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate,sdpMid:message.id});if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Received ICE candidate ->"],candidate),this._peerEndOfCandidatesCounter[targetMid]=this._peerEndOfCandidatesCounter[targetMid]||{},this._peerEndOfCandidatesCounter[targetMid].len=this._peerEndOfCandidatesCounter[targetMid].len||0,this._peerEndOfCandidatesCounter[targetMid].hasSet=!1,this._peerEndOfCandidatesCounter[targetMid].len++,this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.RECEIVED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!this._peerConnections[targetMid]||this._peerConnections[targetMid].signalingState===this.PEER_CONNECTION_STATE.CLOSED)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed.")),void this._signalingEndOfCandidates(targetMid);if(this._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};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],answer),answer.sdp=self._removeSDPFilteredCandidates(targetMid,answer),answer.sdp=self._setSDPCodec(targetMid,answer),answer.sdp=self._setSDPBitrate(targetMid,answer),answer.sdp=self._setSDPCodecParams(targetMid,answer),answer.sdp=self._removeSDPCodecs(targetMid,answer),answer.sdp=self._removeSDPREMBPackets(targetMid,answer),answer.sdp=self._handleSDPConnectionSettings(targetMid,answer,"remote"),answer.sdp=self._removeSDPUnknownAptRtx(targetMid,answer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "have-local-offer" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.restart});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,answer);var onSuccessCbFn=function(){log.debug([targetMid,null,message.type,"Remote description set"]),pc.setAnswer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ANSWER,targetMid),self._addIceCandidateFromQueue(targetMid),self._peerMessagesStamps[targetMid]&&(self._peerMessagesStamps[targetMid].hasRestart=!1),self._dataChannels[targetMid]&&(-1===pc.remoteDescription.sdp.indexOf("m=application")||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,answer:answer})};pc.setRemoteDescription(new RTCSessionDescription(answer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=(agentVer||"").split("."),partsB=(requiredVer||"").split("."),i=0;i0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for sendStream() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream);else{var notInRoomAgainError="Unable to send stream as user is not in the Room.";log.error(notInRoomAgainError,stream),"function"==typeof callback&&callback(new Error(notInRoomAgainError),null)}};if(!("object"==typeof options&&null!==options||AdapterJS&&AdapterJS.WebRTCPlugin&&AdapterJS.WebRTCPlugin.plugin&&["function","object"].indexOf(typeof options)>-1)){var invalidOptionsError="Provided stream settings is invalid";return log.error(invalidOptionsError,options),void("function"==typeof callback&&callback(new Error(invalidOptionsError),null))}if(!self._inRoom){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"===AdapterJS.webrtcDetectedBrowser){var edgeNotSupportError="Edge browser currently does not support renegotiation.";return log.error(edgeNotSupportError,options),void("function"==typeof callback&&callback(new Error(edgeNotSupportError),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0&&(useMediaSource=enableAudioArr)}else enableAudio&&"object"==typeof enableAudio?enableAudioSettings={usedtx:"boolean"==typeof enableAudio.usedtx?enableAudio.usedtx:null,useinbandfec:"boolean"==typeof enableAudio.useinbandfec?enableAudio.useinbandfec:null,stereo:!0===enableAudio.stereo,echoCancellation:!1!==enableAudio.echoCancellation,deviceId:enableAudio.deviceId}:!0===enableAudio?enableAudioSettings=!0===enableAudio&&{usedtx:null,useinbandfec:null,stereo:!1,echoCancellation:!0,deviceId:null}:"function"==typeof enableAudio&&(callback=enableAudio,enableAudio=!1);if(mediaSource&&"string"==typeof mediaSource)checkIfSourceExistsFn(mediaSource)&&(useMediaSource=[mediaSource]);else if(Array.isArray(mediaSource)){for(var mediaSourceArr=[],i=0;i0&&(useMediaSource=mediaSourceArr)}else"function"==typeof mediaSource&&(callback=mediaSource);useMediaSource.indexOf("audio")>-1&&-1===useMediaSource.indexOf("tab")&&(useMediaSource.splice(useMediaSource.indexOf("audio"),1),0===useMediaSource.length&&(useMediaSource=[self.MEDIA_SOURCE.SCREEN])),self._throttle(function(runFn){if(runFn){var settings={settings:{audio:enableAudioSettings,video:{screenshare:!0,exactConstraints:!1}},getUserMediaSettings:{audio:!1,video:{mediaSource:useMediaSource}}},mediaAccessSuccessFn=function(stream){self.off("mediaAccessError",mediaAccessErrorFn),self._inRoom?(self._trigger("incomingStream",self._user.sid,stream,!0,self.getPeerInfo(),!0,stream.id||stream.label),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0),Object.keys(self._peerConnections).length>0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for shareScreen() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream)):"function"==typeof callback&&callback(null,stream)},mediaAccessErrorFn=function(error){self.off("mediaAccessSuccess",mediaAccessSuccessFn),"function"==typeof callback&&callback(error,null)};self.once("mediaAccessSuccess",mediaAccessSuccessFn,function(stream,isScreensharing){return isScreensharing}),self.once("mediaAccessError",mediaAccessErrorFn,function(error,isScreensharing){return isScreensharing});var getUserMediaAudioSettings=!!enableAudioSettings&&{echoCancellation:enableAudioSettings.echoCancellation};try{var hasDefaultAudioTrack=!1;enableAudioSettings&&("firefox"===AdapterJS.webrtcDetectedBrowser?(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio=getUserMediaAudioSettings):useMediaSource.indexOf("audio")>-1&&useMediaSource.indexOf("tab")>-1&&(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio={}));var onSuccessCbFn=function(stream){if(hasDefaultAudioTrack||!enableAudioSettings)return void self._onStreamAccessSuccess(stream,settings,!0,!1);settings.getUserMediaSettings.audio=getUserMediaAudioSettings;var onAudioSuccessCbFn=function(audioStream){try{audioStream.addTrack(stream.getVideoTracks()[0]),self.once("mediaAccessSuccess",function(){self._streams.screenshare.streamClone=stream},function(stream,isScreensharing){return isScreensharing}),self._onStreamAccessSuccess(audioStream,settings,!0,!1)}catch(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)}},onAudioErrorCbFn=function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)};navigator.getUserMedia({audio:getUserMediaAudioSettings},onAudioSuccessCbFn,onAudioErrorCbFn)},onErrorCbFn=function(error){self._onStreamAccessError(error,settings,!0,!1)};navigator.getUserMedia(settings.getUserMediaSettings,onSuccessCbFn,onErrorCbFn)}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"!==AdapterJS.webrtcDetectedBrowser&&("boolean"==typeof options.audio.echoCancellation&&(settings.settings.audio.echoCancellation=options.audio.echoCancellation,settings.getUserMediaSettings.audio.echoCancellation=options.audio.echoCancellation),Array.isArray(options.audio.optional)&&(settings.settings.audio.optional=clone(options.audio.optional),settings.getUserMediaSettings.audio.optional=clone(options.audio.optional)),options.audio.deviceId&&"string"==typeof options.audio.deviceId&&"firefox"!==AdapterJS.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,settings.getUserMediaSettings.audio.deviceId=options.useExactConstraints?{exact:options.audio.deviceId}:{ideal:options.audio.deviceId}))),"edge"===AdapterJS.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio=!0)),options.video&&(settings.settings.video={resolution:clone(this.VIDEO_RESOLUTION.VGA),screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video={},"object"==typeof options.video?("boolean"==typeof options.video.mute&&(settings.mutedSettings.shouldVideoMuted=options.video.mute),Array.isArray(options.video.optional)&&(settings.settings.video.optional=clone(options.video.optional),settings.getUserMediaSettings.video.optional=clone(options.video.optional)),options.video.deviceId&&"string"==typeof options.video.deviceId&&"firefox"!==AdapterJS.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,settings.getUserMediaSettings.video.deviceId=options.useExactConstraints?{exact:options.video.deviceId}:{ideal:options.video.deviceId}),options.video.resolution&&"object"==typeof options.video.resolution&&((options.video.resolution.width&&"object"==typeof options.video.resolution.width||"number"==typeof options.video.resolution.width)&&(settings.settings.video.resolution.width=options.video.resolution.width),(options.video.resolution.height&&"object"==typeof options.video.resolution.height||"number"==typeof options.video.resolution.height)&&(settings.settings.video.resolution.height=options.video.resolution.height)),settings.getUserMediaSettings.video.width="object"==typeof settings.settings.video.resolution.width?settings.settings.video.resolution.width:options.useExactConstraints?{exact:settings.settings.video.resolution.width}:{max:settings.settings.video.resolution.width},settings.getUserMediaSettings.video.height="object"==typeof settings.settings.video.resolution.height?settings.settings.video.resolution.height:options.useExactConstraints?{exact:settings.settings.video.resolution.height}:{max:settings.settings.video.resolution.height},(options.video.frameRate&&"object"==typeof options.video.frameRate||"number"==typeof options.video.frameRate&&"plugin"!==AdapterJS.webrtcDetectedType)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}),options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&"plugin"===AdapterJS.webrtcDetectedType&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):settings.getUserMediaSettings.video={width:options.useExactConstraints?{exact:settings.settings.video.resolution.width}:{max:settings.settings.video.resolution.width},height:options.useExactConstraints?{exact:settings.settings.video.resolution.height}:{max:settings.settings.video.resolution.height}},"edge"===AdapterJS.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,streamHasEnded=!1;if(log.log([null,"MediaStream",streamId,"Has access to stream ->"],stream),!isScreenSharing&&self._streams.userMedia?self._stopStreams({userMedia:!0,screenshare:!1}):isScreenSharing&&self._streams.screenshare&&self._stopStreams({userMedia:!1,screenshare:!0}),self._streamsStoppedCbs[streamId]=function(){log.log([null,"MediaStream",streamId,"Stream has ended"]),streamHasEnded=!0,self._trigger("mediaAccessStopped",!!isScreenSharing,!!isAudioFallback,streamId),self._inRoom&&(log.debug([null,"MediaStream",streamId,"Sending Stream ended status to Peers"]),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.STREAM,mid:self._user.sid,rid:self._room.id,cid:self._key,streamId:streamId,settings:settings.settings,status:"ended"}),self._trigger("streamEnded",self._user.sid,self.getPeerInfo(),!0,!!isScreenSharing,streamId),isScreenSharing&&self._streams.screenshare&&self._streams.screenshare.stream&&(self._streams.screenshare.stream.id||self._streams.screenshare.stream.label)===streamId?self._streams.screenshare=null:!isScreenSharing&&self._streams.userMedia&&self._streams.userMedia.stream&&(self._streams.userMedia.stream.id||self._streams.userMedia.stream.label)===streamId&&(self._streams.userMedia=null))},["chrome","opera"].indexOf(AdapterJS.webrtcDetectedBrowser)>-1?(stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},isScreenSharing&&stream.getVideoTracks().length>0&&(stream.getVideoTracks()[0].onended=function(){setTimeout(function(){!streamHasEnded&&self._inRoom&&self.stopScreen()},350)})):"firefox"===AdapterJS.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._audioFallback){log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0);var onAudioSuccessCbFn=function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},onAudioErrorCbFn=function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)};return void navigator.getUserMedia({audio:!0},onAudioSuccessCbFn,onAudioErrorCbFn)}log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this,streamId=self._peerConnections[targetMid]&&self._peerConnections[targetMid].remoteStreamId||stream.id||stream.label;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",streamId,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",streamId,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",streamId,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,streamId),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId];if(pc){var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)&&self._getSDPCommonSupports(peerId,pc.remoteDescription).video,offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPCommonSupports(peerId,pc.remoteDescription).audio;if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){if(!updatedStream||(!pc.localStreamId||updatedStream.id!==pc.localStreamId)){if("edge"!==AdapterJS.webrtcDetectedBrowser||self._useEdgeWebRTC&&window.msRTCPeerConnection?pc.getLocalStreams().forEach(function(stream){pc.removeStream(stream)}):pc.getSenders().forEach(function(sender){pc.removeTrack(sender)}),!offerToReceiveAudio&&!offerToReceiveVideo)return;updatedStream&&("edge"!==AdapterJS.webrtcDetectedBrowser||self._useEdgeWebRTC&&window.msRTCPeerConnection?pc.addStream(updatedStream):updatedStream.getTracks().forEach(function(track){"audio"===track.kind&&!offerToReceiveAudio||"video"===track.kind&&!offerToReceiveVideo||pc.addTrack(track,updatedStream)}),pc.localStreamId=updatedStream.id||updatedStream.label,pc.localStream=updatedStream)}};self._streams.screenshare&&self._streams.screenshare.stream?(log.debug([peerId,"MediaStream",null,"Sending screen"],self._streams.screenshare.stream),updateStreamFn(self._streams.screenshare.stream)):self._streams.userMedia&&self._streams.userMedia.stream?(log.debug([peerId,"MediaStream",null,"Sending stream"],self._streams.userMedia.stream),updateStreamFn(self._streams.userMedia.stream)):(log.warn([peerId,"MediaStream",null,"No media to send. Will be only receiving"]),updateStreamFn(null))}else log.warn([peerId,"MediaStream",null,"Not adding any stream as signalingState is closed"])}else log.warn([peerId,"MediaStream",self._mediaStream,"Not adding stream as peerconnection object does not exists"])}catch(error){(error.message||"").indexOf("already added")>-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){if(self._streamsSession[peerId][streamId]){var peerInfo=clone(self.getPeerInfo(peerId));peerInfo.settings.audio=clone(self._streamsSession[peerId][streamId].audio),peerInfo.settings.video=clone(self._streamsSession[peerId][streamId].video);var hasScreenshare=peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&!!peerInfo.settings.video.screenshare;self._streamsSession[peerId][streamId]=!1,self._trigger("streamEnded",peerId,peerInfo,!1,hasScreenshare,streamId)}};if(checkStreamId)renderEndedFn(checkStreamId);else if(self._peerConnections[peerId])for(var streamId in self._streamsSession[peerId])self._streamsSession[peerId].hasOwnProperty(streamId)&&self._streamsSession[peerId][streamId]&&renderEndedFn(streamId)},Skylink.prototype._setSDPCodecParams=function(targetMid,sessionDescription){var self=this,parseFn=function(type,codecName,samplingRate,settings){var mLine=sessionDescription.sdp.match(new RegExp("m="+type+" .*\r\n","gi"));if(Array.isArray(mLine)&&mLine.length>0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-1===cLineIndex?void log.error([targetMid,"RTCSessionDesription",sessionDescription.type,'Failed setting "'+type+'" bandwidth as c-line is missing.']):(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Limiting maximum sending "'+type+'" bandwidth ->'],bw),void sdpLines.splice(cLineIndex+1,0,"firefox"===window.webrtcDetectedBrowser?"b=TIAS:"+(1e3*bw*(window.webrtcDetectedVersion>52&&window.webrtcDetectedVersion<55?1e3:1)).toFixed(0):"b=AS:"+bw)):void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not limiting "'+type+'" bandwidth'])},bASAudioBw=this._streamsBandwidthSettings.bAS.audio,bASVideoBw=this._streamsBandwidthSettings.bAS.video,bASDataBw=this._streamsBandwidthSettings.bAS.data,googleXMinBw=this._streamsBandwidthSettings.googleX.min,googleXMaxBw=this._streamsBandwidthSettings.googleX.max;if(this._peerCustomConfigs[targetMid]&&(this._peerCustomConfigs[targetMid].bandwidth&&"object"==typeof this._peerCustomConfigs[targetMid].bandwidth&&("number"==typeof this._peerCustomConfigs[targetMid].bandwidth.audio&&(bASAudioBw=this._peerCustomConfigs[targetMid].bandwidth.audio),"number"==typeof this._peerCustomConfigs[targetMid].bandwidth.video&&(bASVideoBw=this._peerCustomConfigs[targetMid].bandwidth.video),"number"==typeof this._peerCustomConfigs[targetMid].bandwidth.data&&(bASDataBw=this._peerCustomConfigs[targetMid].bandwidth.data)),this._peerCustomConfigs[targetMid].googleXBandwidth&&"object"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth&&("number"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth.min&&(googleXMinBw=this._peerCustomConfigs[targetMid].googleXBandwidth.min),"number"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth.max&&(googleXMaxBw=this._peerCustomConfigs[targetMid].googleXBandwidth.max))),parseFn("audio",bASAudioBw),parseFn("video",bASVideoBw),parseFn("data",bASDataBw),"number"==typeof googleXMinBw||"number"==typeof googleXMaxBw){for(var codec=null,codecRtpMapLineIndex=-1,codecFmtpLineIndex=-1,j=0;j-1){var xGoogleParams="";"number"==typeof googleXMinBw&&(xGoogleParams+="x-google-min-bitrate="+googleXMinBw+";"),"number"==typeof googleXMaxBw&&(xGoogleParams+="x-google-max-bitrate="+googleXMaxBw+";"),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Limiting x-google-bitrate ->"],xGoogleParams),codecFmtpLineIndex>-1?sdpLines[codecFmtpLineIndex]+=(sdpLines[codecFmtpLineIndex].split(" ")[1]?";":"")+xGoogleParams:sdpLines.splice(codecRtpMapLineIndex+1,0,"a=fmtp:"+codec+" "+xGoogleParams)}}return sdpLines.join("\r\n")},Skylink.prototype._setSDPCodec=function(targetMid,sessionDescription,overrideSettings){var self=this,parseFn=function(type,codecSettings){var codec="object"==typeof codecSettings?codecSettings.codec:codecSettings,samplingRate="object"==typeof codecSettings?codecSettings.samplingRate:null,channels="object"==typeof codecSettings?codecSettings.channels:null;if(codec===self["audio"===type?"AUDIO_CODEC":"VIDEO_CODEC"].AUTO)return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not preferring any codec for "'+type+'" streaming. Using browser selection.']);var mLine=sessionDescription.sdp.match(new RegExp("m="+type+" .*\r\n","gi"));if(!(Array.isArray(mLine)&&mLine.length>0))return void log.error([targetMid,"RTCSessionDesription",sessionDescription.type,'Not preferring any codec for "'+type+'" streaming as m= line is not found.']);var setLineFn=function(codecsList,isSROk,isChnlsOk){if(Array.isArray(codecsList)&&codecsList.length>0){isSROk||(samplingRate=null),isChnlsOk||(channels=null),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Preferring "'+codec+'" (samplingRate: '+(samplingRate||"n/a")+", channels: "+(channels||"n/a")+') for "'+type+'" streaming.']);var line=mLine[0],lineParts=line.replace("\r\n","").split(" ");line=lineParts[0]+" "+lineParts[1]+" "+lineParts[2]+" ",lineParts.splice(0,3);for(var i=0;i0?(lineParts.splice(j,1),j--):sessionDescription.sdp.match(new RegExp("a=rtpmap:"+lineParts[j]+" "+codec+"/.*\r\n","gi"))&&(line+=lineParts[j]+" ",lineParts.splice(j,1),j--);return line+=lineParts.join(" ")+"\r\n",sessionDescription.sdp=sessionDescription.sdp.replace(mLine[0],line),!0}};if(samplingRate){if("audio"===type&&channels&&setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/"+samplingRate+(1===channels?"[/1]*":"/"+channels)+"\r\n","gi")),!0,!0))return;if(setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/"+samplingRate+"[/]*.*\r\n","gi")),!0))return}"audio"===type&&channels&&setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/.*/"+channels+"\r\n","gi")),!1,!0)||setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/.*\r\n","gi")))};return parseFn("audio",overrideSettings?overrideSettings.audio:self._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._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var mediaLines=(sessionDescription.sdp.split("\r\n"),sessionDescription.sdp.split("m=")),formatRtx=function(str){return(str.match(/a=rtpmap:.*\ rtx\/.*\r\n/gi)||[]).forEach(function(line){var payload=(line.split("a=rtpmap:")[1]||"").split(" ")[0]||"",fmtpLine=(str.match(new RegExp("a=fmtp:"+payload+" .*\r\n","gi"))||[])[0];if(!fmtpLine)return void(str=str.replace(new RegExp(line,"g"),""));var codecPayload=(fmtpLine.split(" apt=")[1]||"").replace(/\r\n/gi,"");str.match(new RegExp("a=rtpmap:"+codecPayload+" .*\r\n","gi"))||(str=str.replace(new RegExp(line,"g"),""),str=str.replace(new RegExp(fmtpLine,"g"),""))}),str},formatFmtpRtcpFb=function(str){return(str.match(/a=(fmtp|rtcp-fb):.*\ rtx\/.*\r\n/gi)||[]).forEach(function(line){var payload=(line.split("a="+(line.indexOf("rtcp")>0?"rtcp-fb":"fmtp"))[1]||"").split(" ")[0]||"";str.match(new RegExp("a=rtpmap:"+payload+" .*\r\n","gi"))||(str=str.replace(new RegExp(line,"g"),""))}),str},m=0;m0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._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){var codecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index&&0===mediaItem.indexOf(type+" ")){var codecs=(mediaItem.split("\r\n")[0]||"").split(" ");codecs.splice(0,3);for(var i=0;i-1)){codecInfo.name=parts[0],codecInfo.clockRate=parseInt(parts[1],10)||0,codecInfo.channels=parseInt(parts[2]||"1",10)||1,codecInfo.payloadType=parseInt(codecs[i],10),codecInfo.params="";(mediaItem.match(new RegExp("a=fmtp:"+codecs[i]+".*\r\n","gi"))||[]).forEach(function(paramItem){codecInfo.params+=paramItem.replace(new RegExp("a=fmtp:"+codecs[i],"gi"),"").replace(/\ /g,"").replace(/\r\n/g,"")});break}}}}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,'Parsing session description "'+type+'" codecs ->'],codecInfo),codecInfo):codecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._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);if(self._currentCodecSupport={audio:{},video:{}},"AppleWebKit"===AdapterJS.webrtcDetectedType)return self._currentCodecSupport.audio={opus:["48000/2"]},self._currentCodecSupport.video={h264:["48000"]},callback(null);try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints="plugin"!==AdapterJS.webrtcDetectedType?{offerToReceiveAudio:!0,offerToReceiveVideo:!0}:{mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}};try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){self._currentCodecSupport=self._getSDPCodecsSupport(null,offer),callback(null)},function(error){callback(error)},offerConstraints)}}catch(error){callback(error)}},Skylink.prototype._handleSDPConnectionSettings=function(targetMid,sessionDescription,direction){var self=this;if(!self._sdpSessions[targetMid])return sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;"remote"!==direction||self.getPeerInfo(targetMid).config.enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",mediaType=(self._peerInformations[targetMid],""),bundleLineIndex=-1,bundleLineMids=[],mLineIndex=-1,settings=clone(self._sdpSettings);if("MCU"===targetMid&&(settings.connection.audio=!0,settings.connection.video=!0,settings.connection.data=!0),self._hasMCU){var peerStreamSettings=clone(self.getPeerInfo(targetMid)).settings||{};settings.direction.audio.receive="MCU"!==targetMid&&!!peerStreamSettings.audio,settings.direction.audio.send="MCU"===targetMid,settings.direction.video.receive="MCU"!==targetMid&&!!peerStreamSettings.video,settings.direction.video.send="MCU"===targetMid}if("remote"===direction){var offerCodecs=self._getSDPCommonSupports(targetMid,sessionDescription);offerCodecs.audio||(settings.connection.audio=!1),offerCodecs.video||(settings.connection.video=!1)}self._sdpSessions[targetMid][direction].mLines=[],self._sdpSessions[targetMid][direction].bundleLine="",self._sdpSessions[targetMid][direction].connection={audio:null,video:null,data:null};for(var i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");else if(mediaType&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){if(-1===["audio","video"].indexOf(mediaType)){self._sdpSessions[targetMid][direction].connection.data=sdpLines[i];continue}if("local"===direction)settings.direction[mediaType].send&&!settings.direction[mediaType].receive?sdpLines[i]=sdpLines[i].indexOf("send")>-1?"a=sendonly":"a=inactive":!settings.direction[mediaType].send&&settings.direction[mediaType].receive?sdpLines[i]=sdpLines[i].indexOf("recv")>-1?"a=recvonly":"a=inactive":settings.direction[mediaType].send||settings.direction[mediaType].receive||(sdpLines[i]="a=inactive"),self._hasMCU||"firefox"===window.webrtcDetectedBrowser||"firefox"!==peerAgent||sessionDescription.type!==self.HANDSHAKE_PROGRESS.OFFER||"a=recvonly"!==sdpLines[i]||(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Overriding any original settings to receive only to send and receive to resolve chrome BUNDLE errors."]),sdpLines[i]="a=sendrecv",settings.direction[mediaType].send=!0,settings.direction[mediaType].receive=!0);else if(sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER){var localOfferRes=self._sdpSessions[targetMid].local.connection[mediaType];"a=sendonly"===localOfferRes?sdpLines[i]=-1===["a=inactive","a=recvonly"].indexOf(sdpLines[i])?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=-1===["a=inactive","a=sendonly"].indexOf(sdpLines[i])?"a=recvonly"===sdpLines[i]?"a=inactive":"a=sendonly":sdpLines[i]:"a=inactive"===localOfferRes&&(sdpLines[i]="a=inactive")}self._sdpSessions[targetMid][direction].connection[mediaType]=sdpLines[i]}}else sdpLines.splice(i,1),i--;(sdpLines[i]||"").replace(/\n|\r|\s|\ /gi,"")||(sdpLines.splice(i,1),i--)}return bundleLineIndex>-1&&(self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE?sdpLines[bundleLineIndex]="a=group:BUNDLE "+bundleLineMids.join(" "):self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.NONE&&sdpLines.splice(bundleLineIndex,1)),"edge"!==window.webrtcDetectedBrowser&&(sdpLines[sdpLines.length-1].replace(/\n|\r|\s/gi,"")?sdpLines.push(""):sdpLines[sdpLines.length-1]=""),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Handling connection lines and direction ->"],settings),sdpLines.join("\r\n")},Skylink.prototype._getSDPFingerprint=function(targetMid,sessionDescription,beSilentOnLogs){var fingerprint={fingerprint:null,fingerprintAlgorithm:null,derBase64:null};if(!sessionDescription||!sessionDescription.sdp)return fingerprint;for(var sdpLines=sessionDescription.sdp.split("\r\n"),i=0;i"],fingerprint),fingerprint},Skylink.prototype._renderSDPOutput=function(targetMid,sessionDescription){var self=this,localStream=null,localStreamId=null;if(sessionDescription&&sessionDescription.sdp){if(!self._peerConnections[targetMid])return sessionDescription.sdp;self._peerConnections[targetMid].localStream&&(localStream=self._peerConnections[targetMid].localStream,localStreamId=self._peerConnections[targetMid].localStreamId||self._peerConnections[targetMid].localStream.id);var sdpLines=(self._enableIceTrickle?sessionDescription.sdp:sessionDescription.sdp.replace(/a=end-of-candidates\r\n/g,"")).split("\r\n");self._peerInformations[targetMid];if(localStream)for(var mediaType="",i=0;i0?ssrcParts=sdpLines[i].split(" msid:"):sdpLines[i].indexOf(" mslabel:")>0&&(ssrcParts=sdpLines[i].split(" mslabel:")),ssrcParts){var ssrcMsidParts=(ssrcParts[1]||"").split(" ");ssrcMsidParts[0]=localStreamId,ssrcParts[1]=ssrcMsidParts.join(" "),sdpLines[i].indexOf(" msid:")>0?sdpLines[i]=ssrcParts.join(" msid:"):sdpLines[i].indexOf(" mslabel:")>0&&(sdpLines[i]=ssrcParts.join(" mslabel:"))}}if(!self._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var e=0;e"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),log.info([targetMid,"RTCSessionDescription",sessionDescription.type,"Formatted output ->"],sdpLines.join("\r\n")),sdpLines.join("\r\n")}},Skylink.prototype._parseSDPMediaStreamIDs=function(targetMid,sessionDescription){if(this._peerConnections[targetMid]){if(!sessionDescription||!sessionDescription.sdp)return void(this._peerConnections[targetMid].remoteStreamId=null);for(var sdpLines=sessionDescription.sdp.split("\r\n"),currentStreamId=null,i=0;i0){currentStreamId=(sdpLines[i].split(" msid:")[1]||"").split(" ")[0];break}}currentStreamId?currentStreamId!==this._peerConnections[targetMid].remoteStreamId?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"New remote stream is sent ->"],currentStreamId),this._peerConnections[targetMid].remoteStreamId=currentStreamId):log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Same remote stream is sent ->"],currentStreamId):(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"No remote stream is sent."]),this._peerConnections[targetMid].remoteStreamId=null)}},Skylink.prototype._getSDPICECandidates=function(targetMid,sessionDescription,beSilentOnLogs){var candidates={host:[],srflx:[],relay:[]};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index){var sdpMid=((mediaItem.match(/a=mid:.*\r\n/gi)||[])[0]||"").replace(/a=mid:/gi,"").replace(/\r\n/,""),sdpMLineIndex=index-1;(mediaItem.match(/a=candidate:.*\r\n/gi)||[]).forEach(function(item){var canType=(item.split(" ")[7]||"host").replace(/\r\n/g,"");candidates[canType]=candidates[canType]||[],candidates[canType].push(new RTCIceCandidate({sdpMid:sdpMid,sdpMLineIndex:sdpMLineIndex,candidate:(item.split("a=")[1]||"").replace(/\r\n/g,"")}))})}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,"Parsing session description ICE candidates ->"],candidates),candidates):candidates},Skylink.prototype._getSDPMediaSSRC=function(targetMid,sessionDescription,beSilentOnLogs){var ssrcs={audio:0,video:0};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index){var mediaType=mediaItem.split(" ")[0]||"",ssrcLine=(mediaItem.match(/a=ssrc:.*\r\n/)||[])[0];"number"==typeof ssrcs[mediaType]&&ssrcLine&&(ssrcs[mediaType]=parseInt((ssrcLine.split("a=ssrc:")[1]||"").split(" ")[0],10)||0)}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,"Parsing session description media SSRCs ->"],ssrcs),ssrcs):ssrcs},Skylink.prototype._getSDPCodecsSupport=function(targetMid,sessionDescription){var codecs={audio:{},video:{}};if(!sessionDescription||!sessionDescription.sdp)return codecs;for(var sdpLines=sessionDescription.sdp.split("\r\n"),mediaType="",i=0;i-1)continue;codecs[mediaType][codec]=codecs[mediaType][codec]||[],-1===codecs[mediaType][codec].indexOf(info)&&codecs[mediaType][codec].push(info)}}else if(mediaType=(sdpLines[i].split("m=")[1]||"").split(" ")[0],-1===["audio","video"].indexOf(mediaType))break;return log.info([targetMid||null,"RTCSessionDescription",sessionDescription.type,"Parsed codecs support ->"],codecs),codecs},Skylink.prototype._getSDPCommonSupports=function(targetMid,sessionDescription){var self=this,offer={audio:!1,video:!1};if(!targetMid||!sessionDescription||!sessionDescription.sdp){if(offer.video=!(!self._currentCodecSupport.video.h264&&!self._currentCodecSupport.video.vp8),offer.audio=!!self._currentCodecSupport.audio.opus,targetMid){var peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"";AdapterJS.webrtcDetectedBrowser===peerAgent&&(offer.video=Object.keys(self._currentCodecSupport.video).length>0,offer.audio=Object.keys(self._currentCodecSupport.audio).length>0)}return offer}var remoteCodecs=self._getSDPCodecsSupport(targetMid,sessionDescription),localCodecs=self._currentCodecSupport;for(var ac in localCodecs.audio)if(localCodecs.audio.hasOwnProperty(ac)&&localCodecs.audio[ac]&&remoteCodecs.audio[ac]){offer.audio=!0;break}for(var vc in localCodecs.video)if(localCodecs.video.hasOwnProperty(vc)&&localCodecs.video[vc]&&remoteCodecs.video[vc]){offer.video=!0;break}return offer},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this);
\ No newline at end of file
+updatedConstraints.video.mandatory.chromeMediaSourceId=response.sourceId,Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("tab")>-1&&updatedConstraints.video.mediaSource.indexOf("audio")>-1&&updatedConstraints.audio&&(updatedConstraints.audio="object"==typeof updatedConstraints.audio?updatedConstraints.audio:{},updatedConstraints.audio.mandatory=updatedConstraints.audio.mandatory||{},updatedConstraints.audio.mandatory.chromeMediaSource="desktop",updatedConstraints.audio.mandatory.chromeMediaSourceId=response.sourceId),delete updatedConstraints.video.mediaSource,baseGetUserMedia(updatedConstraints,successCb,failureCb)):(response.extensionLink&&AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_CHROME,AdapterJS.TEXT.EXTENSION.BUTTON_CHROME,function(e){window.open(response.extensionLink,"_blank"),e.target&&e.target.parentElement&&e.target.nextElementSibling&&e.target.nextElementSibling.click&&e.target.nextElementSibling.click(),AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION?AdapterJS.TEXT.EXTENSION.REQUIRE_REFRESH:AdapterJS.TEXT.REFRESH.REQUIRE_REFRESH,AdapterJS.TEXT.REFRESH.BUTTON,function(){window.open("javascript:location.reload()","_top")})}),failureCb(response.error))};if(AdapterJS.extensionInfo.chrome.iframeLink&&"opera"!==AdapterJS.webrtcDetectedBrowser)iframe.getSourceId(updatedConstraints.video.mediaSource,fetchStream);else{var extensionId=AdapterJS.extensionInfo["opera"===AdapterJS.webrtcDetectedBrowser?"opera":"chrome"].extensionId,extensionLink=AdapterJS.extensionInfo["opera"===AdapterJS.webrtcDetectedBrowser?"opera":"chrome"].extensionLink,icon=document.createElement("img");icon.src="chrome-extension://"+extensionId+"/icon.png",icon.onload=function(){chrome.runtime.sendMessage(extensionId,{type:"get-version"},function(versionRes){if(!versionRes||"object"!=typeof versionRes||"send-version"!==versionRes.type)return void fetchStream({success:!1,error:new Error("Extension is disabled")});chrome.runtime.sendMessage(extensionId,{type:"get-source",sources:updatedConstraints.video.mediaSource},function(sourceRes){fetchStream(sourceRes&&"object"==typeof sourceRes?"send-source-error"===sourceRes.type?{success:!1,error:new Error("Permission denied for screen retrieval")}:{success:!0,sourceId:sourceRes.sourceId}:{success:!1,error:new Error("Retrieval failed")})})})},icon.onerror=function(){fetchStream({success:!1,error:new Error("Extension not installed"),extensionLink:extensionLink})}}}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=window.getUserMedia=navigator.getUserMedia,navigator.mediaDevices.getUserMedia=function(constraints){return new Promise(function(resolve,reject){try{window.getUserMedia(constraints,resolve,reject)}catch(error){reject(error)}})},"chrome"===AdapterJS.webrtcDetectedBrowser){var states={loaded:!1,error:!1};if(iframe)try{(document.body||document.documentElement).removeChild(iframe)}catch(e){}if(!AdapterJS.extensionInfo.chrome.iframeLink)return;iframe.onload=function(){states.loaded=!0},iframe.onerror=function(){states.error=!0},iframe.src=AdapterJS.extensionInfo.chrome.iframeLink,iframe.style.display="none";var getSourceIdFromIFrame=function(sources,cb){window.addEventListener("message",function iframeListener(evt){window.removeEventListener("message",iframeListener),cb(evt.data?"not-installed"===evt.data.chromeExtensionStatus?{success:!1,error:new Error("Extension is not installed"),extensionLink:evt.data.data||AdapterJS.extensionInfo.chrome.extensionLink}:"installed-disabled"===evt.data.chromeExtensionStatus?{success:!1,error:new Error("Extension is disabled")}:"PermissionDeniedError"===evt.data.chromeMediaSourceId?{success:!1,error:new Error("Permission denied for screen retrieval")}:evt.data.chromeMediaSourceId&&"string"==typeof evt.data.chromeMediaSourceId?{success:!0,sourceId:evt.data.chromeMediaSourceId}:{success:!1,error:new Error("Failed retrieving selected screen")}:{success:!1,error:new Error("Failed retrieving response")})}),iframe.contentWindow.postMessage({captureSourceId:!0,sources:sources,legacy:!0,extensionId:AdapterJS.extensionInfo.chrome.extensionId,extensionLink:AdapterJS.extensionInfo.chrome.extensionLink},"*")};iframe.getSourceId=function(sources,cb){if(states.error)return void cb({success:!1,error:new Error("iframe is not loaded")});if(states.loaded)getSourceIdFromIFrame(sources,cb);else var endBlocks=0,intervalChecker=setInterval(function(){states.loaded?(clearInterval(intervalChecker),getSourceIdFromIFrame(sources,cb)):50===endBlocks?(clearInterval(intervalChecker),cb({success:!1,error:new Error("iframe failed to load")})):endBlocks++},100)},(document.body||document.documentElement).appendChild(iframe)}}else"edge"===AdapterJS.webrtcDetectedBrowser?console.warn("Edge does not support screensharing feature in getUserMedia"):"AppleWebKit"===AdapterJS.webrtcDetectedType?console.warn("Safari does not support screensharing feature in getUserMedia"):"plugin"===AdapterJS.webrtcDetectedType&&(baseGetUserMedia=window.navigator.getUserMedia,navigator.getUserMedia=function(constraints,successCb,failureCb){if(checkIfConstraintsIsValid(constraints,successCb,failureCb),constraints.video&&"object"==typeof constraints.video&&constraints.video.hasOwnProperty("mediaSource")){var updatedConstraints=clone(constraints);AdapterJS.WebRTCPlugin.callWhenPluginReady(function(){if(!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature||!AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable)return void failureCb(new Error("Your version of the WebRTC plugin does not support screensharing"));if(AdapterJS.WebRTCPlugin.plugin.screensharingKeys)if(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("screen")>-1&&updatedConstraints.video.mediaSource.indexOf("window")>-1||updatedConstraints.video.mediaSource===AdapterJS.WebRTCPlugin.plugin.screensharingKey||updatedConstraints.video.mediaSource===AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screenOrWindow)updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screenOrWindow;else if(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("screen")>-1||"screen"===updatedConstraints.video.mediaSource)updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.screen;else{if(!(Array.isArray(updatedConstraints.video.mediaSource)&&updatedConstraints.video.mediaSource.indexOf("window")>-1||"window"===updatedConstraints.video.mediaSource))return void failureCb(new Error('GetUserMedia: Only "screen", "window", ["screen", "window"] are supported as mediaSource constraints'));updatedConstraints.video.mediaSource=AdapterJS.WebRTCPlugin.plugin.screensharingKeys.window}updatedConstraints.video.optional=updatedConstraints.video.optional||[],updatedConstraints.video.optional.push({sourceId:updatedConstraints.video.mediaSource}),baseGetUserMedia(updatedConstraints,successCb,failureCb)})}else baseGetUserMedia(constraints,successCb,failureCb)},AdapterJS.getUserMedia=getUserMedia=window.getUserMedia=navigator.getUserMedia,navigator.mediaDevices&&"undefined"!=typeof Promise&&(navigator.mediaDevices.getUserMedia=requestUserMedia))}},"function"!=typeof window.require&&AdapterJS._defineMediaSourcePolyfill(),function(globals){"use strict";function Skylink(){this._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=!1,this._retryCounters={},this._peerConnections={},this._peerStats={},this._peerBandwidth={},this._peerCustomConfigs={},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=7e3,this._apiTimeout=4e3,this._socketUseXDR=!1,this._enableIceRestart=!1,this._hasMCU=!1,this._forceSSL=!0,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=this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={},this._useEdgeWebRTC=!1,this._joinRoomManager={timestamp:0,socketsFn:[]}}!function(){Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,r=!{toString:null}.propertyIsEnumerable("toString"),e=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],o=e.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var c=[];for(var l in n)t.call(n,l)&&c.push(l);if(r)for(var p=0;o>p;p++)t.call(n,e[p])&&c.push(e[p]);return c}}())}(),function(){function t(t){return 10>t?"0"+t:t}Date.prototype.toISOString=function(){return this.getUTCFullYear()+"-"+t(this.getUTCMonth()+1)+"-"+t(this.getUTCDate())+"T"+t(this.getUTCHours())+":"+t(this.getUTCMinutes())+":"+t(this.getUTCSeconds())+"."+(this.getUTCMilliseconds()/1e3).toFixed(3).slice(2,5)+"Z"}}(),function(){"function"!=typeof Date.now&&(Date.now=function(){return(new Date).getTime()})}(),function(e,t){function n(e){var n=t[e];t[e]=function(e){return o(n(e))}}function a(t,n,a){return(a=this).attachEvent("on"+t,function(t){var t=t||e.event;t.preventDefault=t.preventDefault||function(){t.returnValue=!1},t.stopPropagation=t.stopPropagation||function(){t.cancelBubble=!0},n.call(a,t)})}function o(e,t){if(t=e.length)for(;t--;)e[t].addEventListener=a;else e.addEventListener=a;return e}e.addEventListener||(o([t,e]),"Element"in e?e.Element.prototype.addEventListener=a:(t.attachEvent("onreadystatechange",function(){o(t.all)}),n("getElementsByTagName"),n("getElementById"),n("createElement"),o(t.all)))}(window,document),function(){if("performance"in window==0&&(window.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in window.performance==0){var a=Date.now();performance.timing&&performance.timing.navigationStart&&(a=performance.timing.navigationStart),window.performance.now=function(){return Date.now()-a}}}(),window.BlobBuilder=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,Array.prototype.forEach||(Array.prototype.forEach=function(callback){var T,k;if(null==this)throw new TypeError("this is null or not defined");var O=Object(this),len=O.length>>>0;if("function"!=typeof callback)throw new TypeError(callback+" is not a function");for(arguments.length>1&&(T=arguments[1]),k=0;k"],error),void self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CREATE_ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))}self._dataChannels[peerId]?self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel.label===channelName&&(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING):(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING,self._dataChannels[peerId]={},log.debug([peerId,"RTCDataChannel",channelProp,"initializing main DataChannel"])),dataChannel.onerror=function(evt){var channelError=evt.error||evt;log.error([peerId,"RTCDataChannel",channelProp,"Datachannel has an exception ->"],channelError),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,channelError,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onbufferedamountlow=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel buffering data transfer low"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.BUFFERED_AMOUNT_LOW,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onmessage=function(event){self._processDataChannelData(event.data,peerId,channelName,channelType)};var onOpenHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has opened"]),dataChannel.bufferedAmountLowThreshold=bufferThreshold||0,self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.OPEN,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))};dataChannel.readyState===self.DATA_CHANNEL_STATE.OPEN?setTimeout(onOpenHandlerFn,1):(self._trigger("dataChannelState",dataChannel.readyState,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),dataChannel.onopen=onOpenHandlerFn);var onCloseHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has closed"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSED,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),self._peerConnections[peerId]&&self._peerConnections[peerId].remoteDescription&&self._peerConnections[peerId].remoteDescription.sdp&&(-1===self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")||self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application 0")>0)||channelType===self.DATA_CHANNEL_TYPE.MESSAGING&&setTimeout(function(){self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[peerId].localDescription&&self._peerConnections[peerId].localDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&(log.debug([peerId,"RTCDataChannel",channelProp,"Reviving Datachannel connection"]),self._createDataChannel(peerId,channelName,bufferThreshold,!0))},100)};if("firefox"===AdapterJS.webrtcDetectedBrowser){var hasTriggeredClose=!1,timeBlockAfterClosing=0;dataChannel.onclose=function(){hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())};var onFFClosed=setInterval(function(){dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSED||hasTriggeredClose||5===timeBlockAfterClosing?(clearInterval(onFFClosed),hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())):dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSING&&timeBlockAfterClosing++},1e3)}else dataChannel.onclose=onCloseHandlerFn;channelType===self.DATA_CHANNEL_TYPE.MESSAGING?self._dataChannels[peerId].main={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}:self._dataChannels[peerId][channelName]={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}},Skylink.prototype._getDataChannelBuffer=function(peerId,channelProp){if("object"==typeof peerId)return{bufferedAmountLow:"number"==typeof peerId.bufferedAmountLow?peerId.bufferedAmountLow:parseInt(peerId.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?peerId.bufferedAmountLowThreshold:parseInt(peerId.bufferedAmountLowThreshold,10)||0};if(!(this._dataChannels[peerId]&&this._dataChannels[peerId][channelProp]&&this._dataChannels[peerId][channelProp].channel))return{bufferedAmountLow:0,bufferedAmountLowThreshold:0};var channel=this._dataChannels[peerId][channelProp].channel;return{bufferedAmountLow:"number"==typeof channel.bufferedAmountLow?channel.bufferedAmountLow:parseInt(channel.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof channel.bufferedAmountLowThreshold?channel.bufferedAmountLowThreshold:parseInt(channel.bufferedAmountLowThreshold,10)||0}},Skylink.prototype._sendMessageToDataChannel=function(peerId,data,channelProp,doNotConvert){var self=this;if(channelProp&&channelProp!==peerId||(channelProp="main"),!("object"==typeof data&&data||data&&"string"==typeof data))return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping invalid data ->"],data);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Peer connection does not exists or is closed ->"],data);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Datachannel connection does not exists ->"],data);var channelName=self._dataChannels[peerId][channelProp].channelName,channelType=self._dataChannels[peerId][channelProp].channelType,readyState=self._dataChannels[peerId][channelProp].channel.readyState,messageType="object"==typeof data&&data.type===self._DC_PROTOCOL_TYPE.MESSAGE?self.DATA_CHANNEL_MESSAGE_ERROR.MESSAGE:self.DATA_CHANNEL_MESSAGE_ERROR.TRANSFER;if(readyState!==self.DATA_CHANNEL_STATE.OPEN){var notOpenError='Failed sending message as Datachannel connection state is not opened. Current readyState is "'+readyState+'"';throw log.error([peerId,"RTCDataChannel",channelProp,notOpenError+" ->"],data),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,new Error(notOpenError),channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),new Error(notOpenError)}try{doNotConvert||"object"!=typeof data?(log.debug([peerId,"RTCDataChannel",channelProp,"Sending data with size ->"],data.size||data.length||data.byteLength),self._dataChannels[peerId][channelProp].channel.send(data)):(log.debug([peerId,"RTCDataChannel",channelProp,'Sending "'+data.type+'" protocol message ->'],data),self._dataChannels[peerId][channelProp].channel.send(JSON.stringify(data)))}catch(error){throw log.error([peerId,"RTCDataChannel",channelProp,"Failed sending "+(doNotConvert||"object"!=typeof data?"data":'"'+data.type+'" protocol message')+" ->"],error),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,error,channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),error}},Skylink.prototype._closeDataChannel=function(peerId,channelProp){var self=this;if(!self._dataChannels[peerId])return void log.warn([peerId,"RTCDataChannel",channelProp||null,"Aborting closing Datachannels as Peer connection does not have Datachannel sessions"]);var closeFn=function(rChannelProp){var channelName=self._dataChannels[peerId][rChannelProp].channelName,channelType=self._dataChannels[peerId][rChannelProp].channelType;self._dataChannels[peerId][rChannelProp].readyState!==self.DATA_CHANNEL_STATE.CLOSED&&(log.debug([peerId,"RTCDataChannel",channelProp,"Closing Datachannel"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSING,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(peerId,rChannelProp)),self._dataChannels[peerId][rChannelProp].channel.close(),delete self._dataChannels[peerId][rChannelProp])};if(channelProp){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.");if(!self._enableSimultaneousTransfers)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature requires simultaneous data transfers to be enabled");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},listenToPeerFn=function(peerId,channelProp){var hasStarted=!1;sessions[peerId]=channelProp,self.once("dataStreamState",function(){},function(state,evtTransferId,evtPeerId,evtSessionInfo){if(evtTransferId===transferId&&evtPeerId===peerId){evtSessionInfo.chunk;return delete clone(evtSessionInfo).chunk,state===self.DATA_STREAM_STATE.SENDING_STARTED?void(hasStarted=!0):hasStarted&&[self.DATA_STREAM_STATE.ERROR,self.DATA_STREAM_STATE.SENDING_STOPPED].indexOf(state)>-1?(channelProp===transferId&&self._closeDataChannel(peerId,transferId),self._dataStreams[transferId]&&self._dataStreams[transferId].sessions[peerId]&&(delete self._dataStreams[transferId].sessions[peerId],0===Object.keys(self._dataStreams[transferId].sessions).length&&delete self._dataStreams[transferId]),!0):void 0}})},i=0;i-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE)};if(peersNonInterop.length>0)if(self._hasMCU)waitForChannelOpenFn("MCU",peersNonInterop);else for(var pni=0;pni0)if(self._hasMCU)startDataSessionFn("MCU","main",peersInterop);else for(var pi=0;piself._CHUNK_DATAURL_SIZE:updatedDataChunk.length>self._BINARY_FILE_SIZE)return void log.error("Failed streaming data chunk as data chunk exceeds maximum chunk limit.");var sessionInfo={chunk:updatedDataChunk,chunkSize:updatedDataChunk.size||updatedDataChunk.length||updatedDataChunk.byteLength,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){var onSendDataFn=function(buffer){self._sendMessageToDataChannel(peerId,buffer,channelProp,!0);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype.stopStreamingData=function(transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error("Failed streaming data chunk as stream session ID is not provided.");if(!(self._inRoom&&self._user&&self._user.sid))return void log.error("Failed streaming data chunk as User is not in the Room.");if(!self._dataStreams[transferId])return void log.error("Failed stopping data streaming session as it does not exists.");if(!self._dataStreams[transferId].isUpload)return void log.error("Failed stopping data streaming session as it is not sending.");if(self._hasMCU)return void log.error("Failed stopping data streaming session as MCU does not support this feature yet.");var sessionInfo={chunk:null,chunkSize:0,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:transferId,size:0,originalSize:0,dataType:"fastBinaryStop",mimeType:null,chunkType:self._dataStreams[transferId].sessionChunkType,chunkSize:0,timeout:0,isPrivate:self._dataStreams[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype._startDataTransfer=function(data,timeout,targetPeerId,sendChunksAsBinary,callback,sessionType){var self=this,transferId=(self._user?self._user.sid:"")+"_"+(new Date).getTime(),transferErrors={},transferCompleted=[],chunks=[],listOfPeers=Object.keys(self._peerConnections),sessionChunkType="string",transferInfo={name:null,size:null,chunkSize:null,chunkType:null,dataType:null,mimeType:null,direction:self.DATA_TRANSFER_TYPE.UPLOAD,timeout:60,isPrivate:!1,percentage:0};"number"==typeof timeout?transferInfo.timeout=timeout:Array.isArray(timeout)?listOfPeers=timeout:timeout&&"string"==typeof timeout?listOfPeers=[timeout]:timeout&&"boolean"==typeof timeout?sessionChunkType="binary":"function"==typeof timeout&&(callback=timeout),Array.isArray(targetPeerId)?listOfPeers=targetPeerId:targetPeerId&&"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:targetPeerId&&"boolean"==typeof targetPeerId?sessionChunkType="binary":"function"==typeof targetPeerId&&(callback=targetPeerId),sendChunksAsBinary&&"boolean"==typeof sendChunksAsBinary?sessionChunkType="binary":"function"==typeof sendChunksAsBinary&&(callback=sendChunksAsBinary),listOfPeers.indexOf("MCU")>-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeDataTransferFn=function(error){if(log.error(error),"function"==typeof callback){var transferErrors={};if(0===listOfPeers.length)transferErrors.self=new Error(error);else for(var i=0;i0){var bsChunkSize="firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_CHUNK_FILE_SIZE:self._CHUNK_FILE_SIZE,bsChunks=self._chunkBlobData(new Blob(chunks),bsChunkSize);self._dataTransfers[transferId].enforceBSInfo={chunkSize:4*Math.ceil(bsChunkSize/3),chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,size:4*Math.ceil(transferInfo.originalSize/3),chunks:bsChunks}}}for(var completeFn=function(peerId,error){transferCompleted.indexOf(peerId)>-1||(log.debug([peerId,"RTCDataChannel",transferId,"Data transfer result. Is errors present? ->"],error),transferCompleted.push(peerId),error&&(transferErrors[peerId]=new Error(error)),listOfPeers.length===transferCompleted.length&&(log.log([null,"RTCDataChannel",transferId,"Data transfer request completed"]),"function"==typeof callback&&(Object.keys(transferErrors).length>0?callback({transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),transferErrors:transferErrors,listOfPeers:listOfPeers},null):callback(null,{transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),listOfPeers:listOfPeers}))))},i=0;i0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,"main",Object.keys(self._dataTransfers[transferId].peers.main)),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,transferId,Object.keys(self._dataTransfers[transferId].peers[transferId])))},Skylink.prototype._startDataTransferToPeer=function(transferId,peerId,callback,channelProp,targetPeers){var self=this,peerConnectionStateCbFn=null,dataChannelStateCbFn=null,emitEventFn=function(cb){for(var peers=targetPeers||[peerId],i=0;i-1&&(log.warn([peerId,"RTCDataChannel",transferId,"Binary data chunks transfer is not yet supported with Peer connecting from Android, iOS and C++ SDK. Fallbacking to binary string data chunks transfer."]),size=self._dataTransfers[transferId].enforceBSInfo.size,chunkSize=self._dataTransfers[transferId].enforceBSInfo.chunkSize,chunkType="string"),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:self._dataTransfers[transferId].name,size:size,originalSize:self._dataTransfers[transferId].originalSize,dataType:self._dataTransfers[transferId].sessionType,mimeType:self._dataTransfers[transferId].mimeType,chunkType:chunkType,chunkSize:chunkSize,timeout:self._dataTransfers[transferId].timeout,isPrivate:self._dataTransfers[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp),emitEventFn(function(evtPeerId){self._trigger("incomingDataRequest",transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_UPLOAD_REQUEST,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)})};if("MCU"!==peerId){var dataTransferStateCbFn=function(state,evtTransferId,evtPeerId,transferInfo,error){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&&-1===self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)))return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel currently has an active "+self._dataStreams[streamId].sessionChunkType+" data streaming session.");var protocolVer=(self._peerInformations[peerId].agent||{}).DTProtocolVersion||"0.1.0",requireInterop=self._isLowerThanVersion(protocolVer,"0.1.2")||!self._enableSimultaneousTransfers;return self._isLowerThanVersion(protocolVer,"0.1.2")&&"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer do not support DATA_URL type of data transfers"):"MCU"!==peerId&&self._hasMCU?(channelProp=requireInterop?"main":transferId,peerConnectionStateCbFn=function(){returnErrorBeforeTransferFn("Data transfer terminated as Peer connection is not stable.")},self.once("peerConnectionState",peerConnectionStateCbFn,function(state,evtPeerId){return self._dataTransfers[transferId]?state!==self.PEER_CONNECTION_STATE.STABLE&&evtPeerId===peerId:void self.off("peerConnectionState",peerConnectionStateCbFn)}),requireInterop):(requireInterop||"main"===channelProp)&&self._dataChannels[peerId].main.transferId?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel has a data transfer in-progress."):(self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0},dataChannelStateCbFn=function(state,evtPeerId,error){self._dataTransfers[transferId].sessions[peerId].ackN>=self._dataTransfers[transferId].chunks.length-1||returnErrorBeforeTransferFn(error?error.message||error.toString():"Data transfer terminated as Peer Datachannel connection closed abruptly.")},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){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"===AdapterJS.webrtcDetectedBrowser?16384:65546:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE))))},Skylink.prototype._getTransferInfo=function(transferId,peerId,returnDataProp,hidePercentage,returnDataAtStart){
+if(!this._dataTransfers[transferId])return{};var transferInfo={name:this._dataTransfers[transferId].name,size:this._dataTransfers[transferId].size,dataType:this._dataTransfers[transferId].dataType||this.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:this._dataTransfers[transferId].mimeType||null,chunkSize:this._dataTransfers[transferId].chunkSize,chunkType:this._dataTransfers[transferId].chunkType,timeout:this._dataTransfers[transferId].timeout,isPrivate:this._dataTransfers[transferId].isPrivate,direction:this._dataTransfers[transferId].direction};if(this._dataTransfers[transferId].originalSize?transferInfo.size=this._dataTransfers[transferId].originalSize:this._dataTransfers[transferId].chunkType===this.DATA_TRANSFER_DATA_TYPE.BINARY_STRING&&(transferInfo.size=Math.ceil(3*transferInfo.size/4)),!hidePercentage){if(transferInfo.percentage=0,!this._dataTransfers[transferId].sessions[peerId])return returnDataProp&&(transferInfo.data=null),transferInfo;if(this._dataTransfers[transferId].direction===this.DATA_TRANSFER_TYPE.DOWNLOAD)this._dataTransfers[transferId].sessions[peerId].receivedSize===this._dataTransfers[transferId].sessions[peerId].size?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].receivedSize/this._dataTransfers[transferId].size*100).toFixed(2),10);else{var chunksLength=this._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?this._dataTransfers[transferId].enforceBSInfo.chunks.length:this._dataTransfers[transferId].chunks.length;this._dataTransfers[transferId].sessions[peerId].ackN===chunksLength?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].ackN/chunksLength*100).toFixed(2),10)}returnDataProp&&("number"!=typeof returnDataAtStart?100===transferInfo.percentage?transferInfo.data=this._getTransferData(transferId):transferInfo.data=null:(transferInfo.percentage=returnDataAtStart,0===returnDataAtStart&&(transferInfo.data=this._getTransferData(transferId))))}return transferInfo},Skylink.prototype._getTransferData=function(transferId){if(!this._dataTransfers[transferId])return null;if(this._dataTransfers[transferId].dataType===this.DATA_TRANSFER_SESSION_TYPE.BLOB){var mimeType={name:this._dataTransfers[transferId].name};return this._dataTransfers[transferId].mimeType&&(mimeType.type=this._dataTransfers[transferId].mimeType),new Blob(this._dataTransfers[transferId].chunks,mimeType)}return this._dataTransfers[transferId].chunks.join("")},Skylink.prototype._handleDataTransferTimeoutForPeer=function(transferId,peerId,setPeerTO){var self=this;if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer does not exists for Peer. Ignoring timeout."]);log.debug([peerId,"RTCDataChannel",transferId,"Clearing data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer&&clearTimeout(self._dataTransfers[transferId].sessions[peerId].timer),self._dataTransfers[transferId].sessions[peerId].timer=null,setPeerTO&&(log.debug([peerId,"RTCDataChannel",transferId,"Setting data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer=setTimeout(function(){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer already ended for Peer. Ignoring expired timeout."]);if(!self._user||!self._user.sid)return void log.debug([peerId,"RTCDataChannel",transferId,"User is not in Room. Ignoring expired timeout."]);if(!self._dataChannels[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Datachannel connection does not exists. Ignoring expired timeout."]);log.error([peerId,"RTCDataChannel",transferId,"Data transfer response has timed out."]);var emitEventFn=function(cb){if("MCU"===peerId){for(var broadcastedPeers=[self._dataTransfers[transferId].peers.main,self._dataTransfers[transferId].peers[transferId]],i=0;i"],rawData);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping data received from Peer as Datachannel connection is not present ->"],rawData);if("string"==typeof rawData)try{var protocolData=JSON.parse(rawData);if(isStreamChunk=!1,log.debug([peerId,"RTCDataChannel",channelProp,'Received protocol "'+protocolData.type+'" message ->'],protocolData),[self._DC_PROTOCOL_TYPE.ACK,self._DC_PROTOCOL_TYPE.ERROR,self._DC_PROTOCOL_TYPE.CANCEL].indexOf(protocolData.type)>-1&&!(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded protocol message as data transfer session is not present ->"],protocolData);switch(protocolData.type){case self._DC_PROTOCOL_TYPE.WRQ:if(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId])return log.warn([peerId,"RTCDataChannel",channelProp,"Rejecting bidirectional data transfer request as it is currently not supported in the SDK ->"],protocolData),void self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,ackN:-1,sender:self._user.sid},channelProp);self._WRQProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ACK:self._ACKProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ERROR:self._ERRORProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.CANCEL:self._CANCELProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.MESSAGE:self._MESSAGEProtocolHandler(peerId,protocolData,channelProp);break;default:log.warn([peerId,"RTCDataChannel",channelProp,'Discarded unknown "'+protocolData.type+'" message ->'],protocolData)}}catch(error){if(rawData.indexOf("{")>-1&&rawData.indexOf("}")>0)throw log.error([peerId,"RTCDataChannel",channelProp,"Failed parsing protocol step data error ->"],{data:rawData,error:error}),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(peerId,channelProp)),error;if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING;if(isStreamChunk||self._dataTransfers[transferId].dataType===self.DATA_TRANSFER_SESSION_TYPE.DATA_URL)log.debug([peerId,"RTCDataChannel",channelProp,"Received string data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.length||rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.STRING,rawData.length||rawData.size||0,channelProp);else{var removeSpaceData=rawData.replace(/\s|\r|\n/g,"");log.debug([peerId,"RTCDataChannel",channelProp,"Received binary string data chunk @"+self._dataTransfers[transferId].sessions[peerId].ackN+" with size ->"],removeSpaceData.length||removeSpaceData.size),self._DATAProtocolHandler(peerId,self._base64ToBlob(removeSpaceData),self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,removeSpaceData.length||removeSpaceData.size||0,channelProp)}}else{if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);if(rawData instanceof Blob)log.debug([peerId,"RTCDataChannel",channelProp,"Received blob data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.BLOB,rawData.size,channelProp);else{var byteArray=rawData,blob=null;if(rawData.constructor&&"Array"===rawData.constructor.name&&(byteArray=new Int8Array(rawData)),"IE"===AdapterJS.webrtcDetectedBrowser){if(window.BlobBuilder){var bb=new BlobBuilder;bb.append(rawData.constructor&&"ArrayBuffer"===rawData.constructor.name?byteArray:new Uint8Array(byteArray).buffer),blob=bb.getBlob()}}else blob=new Blob([byteArray]);log.debug([peerId,"RTCDataChannel",channelProp,"Received arraybuffer data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],blob.size),self._DATAProtocolHandler(peerId,blob,self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,blob.size,channelProp)}}},Skylink.prototype._WRQProtocolHandler=function(peerId,data,channelProp){var self=this,transferId="main"===channelProp?data.transferId||null:channelProp,senderPeerId=data.sender||peerId;if(["fastBinaryStart","fastBinaryStop"].indexOf(data.dataType)>-1)if("fastBinaryStart"===data.dataType){transferId||(transferId="stream_"+peerId+"_"+(new Date).getTime()),self._dataStreams[transferId]={chunkSize:0,chunkType:"string"===data.chunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:data.chunkType,isPrivate:!!data.isPrivate,isStringStream:"string"===data.chunkType,senderPeerId:senderPeerId,isUpload:!1},self._dataChannels[peerId][channelProp].streamId=transferId;self.once("dataChannelState",function(){},function(state,evtPeerId,channelName,channelType,error){if(!self._dataStreams[transferId])return!0;if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId&&channelType===self.DATA_CHANNEL_TYPE.DATA)&&[self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');return self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},updatedError),!0}}),self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STARTED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStarted",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1)}else transferId=self._dataChannels[peerId][channelProp].streamId,self._dataStreams[transferId]&&!self._dataStreams[transferId].isUpload&&(self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STOPPED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStopped",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1),self._dataChannels[peerId][channelProp].streamId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp),delete self._dataStreams[transferId]);else transferId||(transferId="transfer_"+peerId+"_"+(new Date).getTime()),self._dataTransfers[transferId]={name:data.name||transferId,size:data.size||0,chunkSize:data.chunkSize,originalSize:data.originalSize||0,timeout:data.timeout||60,isPrivate:!!data.isPrivate,senderPeerId:data.sender||peerId,dataType:self.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:data.mimeType||null,chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,direction:self.DATA_TRANSFER_TYPE.DOWNLOAD,chunks:[],sessions:{},sessionType:data.dataType||"blob",sessionChunkType:data.chunkType||"string"},"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?(self._dataTransfers[transferId].dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,self._dataTransfers[transferId].chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING):"blob"===self._dataTransfers[transferId].sessionType&&"binary"===self._dataTransfers[transferId].sessionChunkType&&(self._dataTransfers[transferId].chunkType=self._binaryChunkType),self._dataChannels[peerId][channelProp].transferId=transferId,self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0,receivedSize:0},self._trigger("incomingDataRequest",transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!1),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_REQUEST,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)},Skylink.prototype._ACKProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ACK event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};if(data.ackN>-1){if(0===data.ackN)emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_STARTED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,0),null)});else if(self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?data.ackN===self._dataTransfers[transferId].enforceBSInfo.chunks.length:data.ackN===self._dataTransfers[transferId].chunks.length)return self._dataTransfers[transferId].sessions[peerId].ackN=data.ackN,emitEventFn(function(evtPeerId){self._trigger("incomingData",self._getTransferData(transferId),transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,100),null)}),void(self._dataChannels[peerId][channelProp]&&(self._dataChannels[peerId][channelProp].transferId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp)));var uploadFn=function(chunk){self._sendMessageToDataChannel(peerId,chunk,channelProp,!0),data.ackN-1?self._blobToBase64(self._dataTransfers[transferId].enforceBSInfo.chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING?self._blobToBase64(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER?self._blobToArrayBuffer(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):uploadFn(self._dataTransfers[transferId].chunks[data.ackN])}else self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.REJECTED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as Peer has rejected data transfer request"),transferType:self.DATA_TRANSFER_TYPE.UPLOAD})},Skylink.prototype._MESSAGEProtocolHandler=function(peerId,data,channelProp){var senderPeerId=data.sender||peerId;log.log([senderPeerId,"RTCDataChannel",channelProp,"Received P2P message from peer:"],data),this._trigger("incomingMessage",{content:data.data,isPrivate:data.isPrivate,isDataChannel:!0,targetPeerId:this._user.sid,senderPeerId:senderPeerId},senderPeerId,this.getPeerInfo(senderPeerId),!1)},Skylink.prototype._ERRORProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ERROR event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,evtPeerId,self._getTransferInfo(transferId,peerID,!0,!1,!1),{message:new Error(data.content),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._CANCELProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of CANCEL event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(peerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.CANCEL,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error(data.content||"Peer has terminated data transfer."),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._DATAProtocolHandler=function(peerId,chunk,chunkType,chunkSize,channelProp){var self=this,transferId=channelProp,senderPeerId=peerId;if(self._dataChannels[peerId]&&self._dataChannels[peerId][channelProp]){var streamId=self._dataChannels[peerId][channelProp].streamId;if(streamId&&self._dataStreams[streamId]&&("string"==typeof chunk&&"string"===self._dataStreams[streamId].sessionChunkType||chunk instanceof Blob&&"binary"===self._dataStreams[streamId].sessionChunkType))return senderPeerId=self._dataStreams[streamId].senderPeerId||peerId,self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVED,streamId,senderPeerId,{chunk:chunk,chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},null),void self._trigger("incomingDataStream",chunk,transferId,senderPeerId,{chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},!1);if("main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._dataTransfers[transferId].senderPeerId&&(senderPeerId=self._dataTransfers[transferId].senderPeerId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1),self._dataTransfers[transferId].chunkType=chunkType,self._dataTransfers[transferId].sessions[peerId].receivedSize+=chunkSize,self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN]=chunk,self._dataTransfers[transferId].sessions[peerId].receivedSize>=self._dataTransfers[transferId].size)return log.log([peerId,"RTCDataChannel",channelProp,"Data transfer has been completed. Computed size ->"],self._dataTransfers[transferId].sessions[peerId].receivedSize),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN+1},channelProp),self._trigger("incomingData",self._getTransferData(transferId),transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),null),void self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null);self._dataTransfers[transferId].sessions[peerId].ackN+=1,self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN},channelProp),self._handleDataTransferTimeoutForPeer(transferId,peerId,!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOADING,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)}},Skylink.prototype.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._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,userInfo:self._getUserInfo(targetMid),target:targetMid,rid:self._room.id})}}},Skylink.prototype._addIceCandidateToQueue=function(targetMid,canId,candidate){var candidateType=candidate.candidate.split(" ")[7];log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Buffering ICE candidate."]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.BUFFERED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[],this._peerCandidatesQueue[targetMid].push([canId,candidate])},Skylink.prototype._addIceCandidateFromQueue=function(targetMid){this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[];for(var i=0;i"],error),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},error)};if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Adding ICE candidate."]),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESSING,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[targetMid].remoteDescription&&self._peerConnections[targetMid].remoteDescription.sdp&&self._peerConnections[targetMid].remoteDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),void self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed."));try{self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)}catch(error){onErrorCbFn(error)}},Skylink.prototype.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(passedIceServers){var self=this,iceServerName=null,iceServerProtocol="stun",iceServerPorts={udp:[3478,19302,19303,19304],tcp:[80,443],both:[19305,19306,19307,19308]},iceServers=[{urls:[]},{urls:[]}];return passedIceServers.forEach(function(server){
+if(0===server.url.indexOf("stun:"))server.url.indexOf("temasys")>0?iceServerName=(server.url.split(":")[1]||"").split("?")[0]||null:iceServers[0].urls.push(server.url);else if(0===server.url.indexOf("turn:")&&server.url.indexOf("@")>0&&server.credential&&!iceServers[1].username&&!iceServers[1].credential){var parts=server.url.split(":"),urlParts=(parts[1]||"").split("@");iceServerName=(urlParts[1]||"").split("?")[0],iceServers[1].username=urlParts[0],iceServers[1].credential=server.credential,iceServerProtocol="turn"}}),self._iceServer?iceServers=[{urls:self._iceServer.urls,username:iceServers[1].username,credential:iceServers[1].credential}]:(iceServerName=iceServerName||"turn.temasys.io","edge"===AdapterJS.webrtcDetectedBrowser?(iceServerPorts.udp=[3478],iceServerPorts.tcp=[],iceServerPorts.both=[],iceServerProtocol="turn"):self._forceTURNSSL?"firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion<53?(iceServerPorts.udp=[],iceServerPorts.tcp=[443],iceServerPorts.both=[],iceServerProtocol="turn"):(iceServerPorts.udp=[],iceServerProtocol="turns"):"firefox"===AdapterJS.webrtcDetectedBrowser&&(iceServerPorts.udp=[3478],iceServerPorts.tcp=[443,80]),self._TURNTransport!==self.TURN_TRANSPORT.UDP||self._forceTURNSSL?self._TURNTransport===self.TURN_TRANSPORT.TCP?(iceServerPorts.tcp=iceServerPorts.tcp.concat(iceServerPorts.both),iceServerPorts.udp=[],iceServerPorts.both=[]):self._TURNTransport===self.TURN_TRANSPORT.NONE&&(iceServerPorts.tcp=[],iceServerPorts.udp=[]):(iceServerPorts.udp=iceServerPorts.udp.concat(iceServerPorts.both),iceServerPorts.tcp=[],iceServerPorts.both=[]),"stun"===iceServerProtocol&&(iceServerPorts.tcp=[]),iceServerPorts.tcp.forEach(function(tcpPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+tcpPort+"?transport=tcp")}),iceServerPorts.udp.forEach(function(udpPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+udpPort+"?transport=udp")}),iceServerPorts.both.forEach(function(bothPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+bothPort)})),self._usePublicSTUN||iceServers.splice(0,1),log.log("Output iceServers configuration:",iceServers),{iceServers:iceServers}},Skylink.prototype.PEER_CONNECTION_STATE={STABLE:"stable",HAVE_LOCAL_OFFER:"have-local-offer",HAVE_REMOTE_OFFER:"have-remote-offer",CLOSED:"closed"},Skylink.prototype.GET_CONNECTION_STATUS_STATE={RETRIEVING:0,RETRIEVE_SUCCESS:1,RETRIEVE_ERROR:-1},Skylink.prototype.SERVER_PEER_TYPE={MCU:"mcu"},Skylink.prototype.BUNDLE_POLICY={MAX_COMPAT:"max-compat",BALANCED:"balanced",MAX_BUNDLE:"max-bundle",NONE:"none"},Skylink.prototype.RTCP_MUX_POLICY={REQUIRE:"require",NEGOTIATE:"negotiate"},Skylink.prototype.PEER_CERTIFICATE={RSA:"RSA",ECDSA:"ECDSA",AUTO:"AUTO"},Skylink.prototype.refreshConnection=function(targetPeerId,iceRestart,options,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),doIceRestart=!1,bwOptions={};Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:"boolean"==typeof targetPeerId?doIceRestart=targetPeerId:targetPeerId&&"object"==typeof targetPeerId?bwOptions=targetPeerId:"function"==typeof targetPeerId&&(callback=targetPeerId),"boolean"==typeof iceRestart?doIceRestart=iceRestart:iceRestart&&"object"==typeof iceRestart?bwOptions=iceRestart:"function"==typeof iceRestart&&(callback=iceRestart),options&&"object"==typeof options?bwOptions=options:"function"==typeof options&&(callback=options);var emitErrorForPeersFn=function(error){if(log.error(error),"function"==typeof callback){var listOfPeerErrors={};if(0===listOfPeers.length)listOfPeerErrors.self=new Error(error);else for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}},refreshSinglePeer=function(peerId,peerCallback){if(!self._peerConnections[peerId])return error="There is currently no existing peer connection made with the peer. Unable to restart connection",log.error([peerId,null,null,error]),void peerCallback(error);log.log([peerId,"PeerConnection",null,"Restarting peer connection"]),self._restartPeerConnection(peerId,doIceRestart,bwOptions,peerCallback)};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?refreshSinglePeer(peerId,refreshSinglePeerCallback(peerId)):(error="Peer connection with peer does not exists. Unable to restart",log.error([peerId,"PeerConnection",null,error]),refreshSinglePeerCallback(peerId)(error))}}},Skylink.prototype.getConnectionStatus=function(targetPeerId,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),listOfPeerStats={},listOfPeerErrors={};if(Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId&&targetPeerId?listOfPeers=[targetPeerId]:"function"==typeof targetPeerId&&(callback=targetPeerId,targetPeerId=void 0),0===listOfPeers.length)return listOfPeerErrors.self=new Error("There is currently no peer connections to retrieve connection status"),log.error([null,"RTCStatsReport",null,"Retrieving request failure ->"],listOfPeerErrors.self),void("function"==typeof callback&&callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null));"edge"===AdapterJS.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){-1===completedTaskCounter.indexOf(peerId)&&completedTaskCounter.push(peerId),completedTaskCounter.length===listOfPeers.length&&"function"==typeof callback&&(Object.keys(listOfPeerErrors).length>0?callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null):callback(null,{listOfPeers:listOfPeers,connectionStats:listOfPeerStats}))},statsFn=function(peerId){var retrieveFn=function(firstRetrieval,nextCb){return function(err,result){if(err)return log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],error),listOfPeerErrors[peerId]=error,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,error),checkCompletedFn(peerId),void(firstRetrieval&&delete self._peerStats[peerId]);firstRetrieval?nextCb():(listOfPeerStats[peerId]=result,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_SUCCESS,peerId,listOfPeerStats[peerId],null),checkCompletedFn(peerId))}};if(!self._peerStats[peerId])return self._peerStats[peerId]={},log.debug([peerId,"RTCStatsReport",null,"Retrieving first report to tabulate results"]),void self._retrieveStats(peerId,retrieveFn(!0,function(){self._retrieveStats(peerId,retrieveFn())}),!0);self._retrieveStats(peerId,retrieveFn())},i=0;i"],listOfPeerErrors[peerId]),self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,listOfPeerErrors[peerId]),checkCompletedFn(peerId))}},Skylink.prototype._retrieveStats=function(peerId,callback,beSilentOnLogs,isAutoBwStats){var self=this,pc=self._peerConnections[peerId],output={raw:{},connection:{},audio:{sending:{},receiving:{}},video:{sending:{},receiving:{}},selectedCandidate:{local:{},remote:{},consentResponses:{},consentRequests:{},responses:{},requests:{}},certificate:{}};if(!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));if(!pc)return callback(new Error("Peer connection is not initialised"));"edge"!==AdapterJS.webrtcDetectedBrowser&&"AppleWebKit"!==AdapterJS.webrtcDetectedType||log.warn("Current connection stats may not be complete as it is in beta"),output.connection.iceConnectionState=pc.iceConnectionState,output.connection.iceGatheringState=pc.iceGatheringState,output.connection.signalingState=pc.signalingState,output.connection.remoteDescription={type:pc.remoteDescription&&pc.remoteDescription.type||"",sdp:pc.remoteDescription&&pc.remoteDescription.sdp||""},output.connection.localDescription={type:pc.localDescription&&pc.localDescription.type||"",sdp:pc.localDescription&&pc.localDescription.sdp||""},output.connection.candidates={sending:self._getSDPICECandidates(peerId,pc.localDescription,beSilentOnLogs),receiving:self._getSDPICECandidates(peerId,pc.remoteDescription,beSilentOnLogs)},output.connection.dataChannels={},output.connection.constraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,output.connection.optional=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,output.connection.sdpConstraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null,output.audio.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),output.video.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),output.audio.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"audio",beSilentOnLogs),output.video.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"video",beSilentOnLogs),output.certificate.local=self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),output.certificate.remote=self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs);var inboundSSRCs=self._getSDPMediaSSRC(peerId,pc.remoteDescription,beSilentOnLogs);output.audio.receiving.ssrc=inboundSSRCs.audio,output.video.receiving.ssrc=inboundSSRCs.video;var outboundSSRCs=self._getSDPMediaSSRC(peerId,pc.localDescription,beSilentOnLogs);output.audio.sending.ssrc=outboundSSRCs.audio,output.video.sending.ssrc=outboundSSRCs.video,Object.keys(self._dataChannels[peerId]||{}).forEach(function(prop){var channel=self._dataChannels[peerId][prop];output.connection.dataChannels[channel.channel.label]={label:channel.channel.label,readyState:channel.channel.readyState,channelType:self.DATA_CHANNEL_TYPE["main"===prop?"MESSAGING":"DATA"],currentTransferId:channel.transferId||null,currentStreamId:channel.streamId||null}});var certificateFn=function(item,prop){if(0===prop.indexOf("RTCCertificate_"))item.fingerprint===output.certificate.local.fingerprint?(output.certificate.local.derBase64=item.base64Certificate,output.certificate.local.fingerprintAlgorithm=item.fingerprintAlgorithm):item.fingerprint===output.certificate.remote.fingerprint&&(output.certificate.remote.derBase64=item.base64Certificate,output.certificate.remote.fingerprintAlgorithm=item.fingerprintAlgorithm);else if(0===prop.indexOf("ssrc_")&&item.transportId){var pairItem=output.raw[item.transportId]||{};output.certificate.srtpCipher=pairItem.srtpCipher,output.certificate.dtlsCipher=pairItem.dtlsCipher;var localCertItem=output.raw[pairItem.localCertificateId||""]||{};output.certificate.local.fingerprint=localCertItem.googFingerprint,output.certificate.local.fingerprintAlgorithm=localCertItem.googFingerprintAlgorithm,output.certificate.local.derBase64=localCertItem.googDerBase64;var remoteCertItem=output.raw[pairItem.remoteCertificateId||""]||{};output.certificate.remote.fingerprint=remoteCertItem.googFingerprint,output.certificate.remote.fingerprintAlgorithm=remoteCertItem.googFingerprintAlgorithm,output.certificate.remote.derBase64=remoteCertItem.googDerBase64}},candidatePairFn=function(item,prop){if(0===prop.indexOf("RTCIceCandidatePair_")){if("succeeded"!==item.state||output.selectedCandidate.nominated||item.prioirty<(output.selectedCandidate.priority||0))return;for(var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],sending=pc.localDescription&&pc.localDescription.sdp&&pc.localDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],receiving=pc.remoteDescription&&pc.remoteDescription&&pc.remoteDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],computePrioirtyFn=function(controller,controlled){return Math.pow(2,32)*Math.min(controller,controlled)+2*Math.max(controller,controlled)+(controller>controlled?1:0)},computeCanTypeFn=function(type){return"relay"===type?"relayed":"host"===type?"local":"srflx"===type?"serverreflexive":type},s=0;s0?"sending":"receiving";item.codecImplementationName="unknown"===item.codecImplementationName?null:item.codecImplementationName,output[item.mediaType][direction].codec.implementation=item.codecImplementationName||null,item.googCodecName="unknown"===item.googCodecName?null:item.googCodecName,output[item.mediaType][direction].codec.name=item.googCodecName||output[item.mediaType][direction].codec.name}},audioStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPAudioStream")){if(output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.audio.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),"function"!=typeof pc.getReceivers)return}else if(0===prop.indexOf("RTCMediaStreamTrack_remote_audio_"))output.audio.receiving.audioOutputLevel=item.audioLevel;else if(0===prop.indexOf("RTCOutboundRTPAudioStream"))output.audio.sending.targetBitrate=item.targetBitrate||0,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"audio"===item.mediaType&&item.isRemote)output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"audio"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"audio"===item.mediaType)if(prop.indexOf("_recv")>0){output.audio.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.audio.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.audio.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.audio.receiving.totalBytes=bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.audio.receiving.totalPackets=packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.audio.receiving.totalPacketsLost=packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost")}else{output.audio.sending.rtt=parseInt(item.googRtt||"0",10),output.audio.sending.audioInputLevel=parseInt(item.audioInputLevel||"0",10),output.audio.sending.echoReturnLoss=parseInt(item.googEchoCancellationReturnLoss||"0",10),output.audio.sending.echoReturnLossEnhancement=parseInt(item.googEchoCancellationReturnLossEnhancement||"0",10);var bytesSent=parseInt(item.bytesSent||"0",10);output.audio.sending.totalBytes=bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.audio.sending.totalPackets=packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent")}else if(0===prop.indexOf("inbound_rtp_audio"))output.audio.receiving.jitter=item.jitter||0,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if(0===prop.indexOf("outbound_rtp_audio")){output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.audio.sending.rtt=rtcpItem.roundTripTime||0}}else{output.audio.sending.targetBitrate=item.targetBitrate,output.audio.sending.rtt=item.roundTripTime,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.audio.sending.audioInputLevel=trackItem.audioLevel,output.audio.sending.echoReturnLoss=trackItem.echoReturnLoss,output.audio.sending.echoReturnLossEnhancement=trackItem.echoReturnLossEnhancement}},videoStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPVideoStream"))output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.framesDecoded=item.framesDecoded,output.video.receiving.qpSum=item.qpSum,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.video.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if(0===prop.indexOf("RTCMediaStreamTrack_remote_video_"))output.video.receiving.frameHeight=item.frameHeight,output.video.receiving.frameWidth=item.frameWidth,output.video.receiving.framesCorrupted=item.framesCorrupted,output.video.receiving.framesPerSecond=item.framesPerSecond,output.video.receiving.framesDropped=item.framesDropped,output.video.receiving.totalFrames=item.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,item,"framesReceived");else if(0===prop.indexOf("RTCOutboundRTPVideoStream"))output.video.sending.qpSum=item.qpSum,output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"video"===item.mediaType&&item.isRemote){output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.receiving.framesCorrupted=trackItem.framesCorrupted,output.video.receiving.framesDropped=trackItem.framesDropped,output.video.receiving.framesDecoded=trackItem.framesDecoded,output.video.receiving.totalFrames=trackItem.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,trackItem,"framesReceived")}else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"video"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType)if(prop.indexOf("_recv")>0){output.video.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.video.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.video.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10),output.video.receiving.renderDelayMs=parseInt(item.googRenderDelayMs||"0",10),output.video.receiving.frameWidth=parseInt(item.googFrameWidthReceived||"0",10),output.video.receiving.frameHeight=parseInt(item.googFrameHeightReceived||"0",10),output.video.receiving.framesDecoded=parseInt(item.framesDecoded||"0",10),output.video.receiving.frameRateOutput=parseInt(item.googFrameRateOutput||"0",10),output.video.receiving.frameRateDecoded=parseInt(item.googFrameRateDecoded||"0",10),
+output.video.receiving.frameRateReceived=parseInt(item.googFrameRateReceived||"0",10),output.video.receiving.qpSum=parseInt(item.qpSum||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.video.receiving.totalBytes=bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.video.receiving.totalPackets=packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.video.receiving.totalPacketsLost=packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost");var nacksSent=parseInt(item.googNacksSent||"0",10);output.video.receiving.totalNacks=nacksSent,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"googNacksSent");var plisSent=parseInt(item.googPlisSent||"0",10);output.video.receiving.totalPlis=plisSent,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"googPlisSent");var firsSent=parseInt(item.googFirsSent||"0",10);output.video.receiving.totalFirs=firsSent,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"googFirsSent")}else{output.video.sending.rtt=parseInt(item.googRtt||"0",10),output.video.sending.frameWidth=parseInt(item.googFrameWidthSent||"0",10),output.video.sending.frameHeight=parseInt(item.googFrameHeightSent||"0",10),output.video.sending.framesEncoded=parseInt(item.framesEncoded||"0",10),output.video.sending.frameRateInput=parseInt(item.googFrameRateInput||"0",10),output.video.sending.frameRateEncoded=parseInt(item.googFrameRateEncoded||"0",10),output.video.sending.frameRateSent=parseInt(item.googFrameRateSent||"0",10),output.video.sending.cpuLimitedResolution="true"===item.googCpuLimitedResolution,output.video.sending.bandwidthLimitedResolution="true"===item.googBandwidthLimitedResolution;var bytesSent=parseInt(item.bytesSent||"0",10);output.video.sending.totalBytes=bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.video.sending.totalPackets=packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent");var nacksReceived=parseInt(item.googNacksReceived||"0",10);output.video.sending.totalNacks=nacksReceived,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"googNacksReceived");var plisReceived=parseInt(item.googPlisReceived||"0",10);output.video.sending.totalPlis=plisReceived,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"googPlisReceived");var firsReceived=parseInt(item.googFirsReceived||"0",10);output.video.sending.totalFirs=firsReceived,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"googFirsReceived")}else if(0===prop.indexOf("inbound_rtp_video"))output.video.receiving.jitter=item.jitter||0,output.video.receiving.framesDecoded=item.framesDecoded||0,output.video.receiving.frameRateMean=item.framerateMean||0,output.video.receiving.frameRateStdDev=item.framerateStdDev||0,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount");else if(0===prop.indexOf("outbound_rtp_video")){output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.frameRateMean=item.framerateMean||0,output.video.sending.frameRateStdDev=item.framerateStdDev||0,output.video.sending.framesDropped=item.droppedFrames||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.video.sending.rtt=rtcpItem.roundTripTime||0}}else{output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.roundTripTime=item.roundTripTime||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.sending.frameHeight=trackItem.frameHeight,output.video.sending.frameWidth=trackItem.frameWidth,output.video.sending.framesPerSecond=trackItem.framesPerSecond,output.video.sending.totalFrames=trackItem.framesSent,output.video.sending.frames=self._parseConnectionStats(prevStats,trackItem,"framesSent")}},videoE2EStatsFn=function(item,prop){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType){var captureStartNtpTimeMs=parseInt(item.googCaptureStartNtpTimeMs||"0",10),remoteStream=pc.getRemoteStreams()[0];if(!(captureStartNtpTimeMs>0&&prop.indexOf("_recv")>0&&remoteStream&&document&&"function"==typeof document.getElementsByTagName))return;try{var elements=document.getElementsByTagName("plugin"===AdapterJS.webrtcDetectedType?"object":"video");"plugin"!==AdapterJS.webrtcDetectedType&&0===elements.length&&(elements=document.getElementsByTagName("audio"));for(var e=0;e0))break;for(var ec=0;ec"],error)}}},successCbFn=function(stats){"function"==typeof stats.forEach?stats.forEach(function(item,prop){output.raw[prop]=item}):output.raw=stats;var edgeTracksKind={remote:{},local:{}};"edge"===AdapterJS.webrtcDetectedBrowser&&(pc.remoteStream&&pc.remoteStream.getTracks().forEach(function(track){edgeTracksKind.remote[track.id]=track.kind}),pc.localStream&&pc.localStream.getTracks().forEach(function(track){edgeTracksKind.local[track.id]=track.kind})),Object.keys(output.raw).forEach(function(prop){if(0!==prop.indexOf("ssrc_")||output.raw[prop].mediaType){if("edge"===AdapterJS.webrtcDetectedBrowser&&!output.raw[prop].mediaType&&["inboundrtp","outboundrtp"].indexOf(output.raw[prop].type)>-1){var trackItem=output.raw[output.raw[prop].mediaTrackId]||{};output.raw[prop].mediaType=edgeTracksKind[output.raw[prop].isRemote?"remote":"local"][trackItem.trackIdentifier]||""}}else output.raw[prop].mediaType=output.raw[prop].audioInputLevel||output.raw[prop].audioOutputLevel?"audio":"video";certificateFn(output.raw[prop],prop),candidatePairFn(output.raw[prop],prop),codecsFn(output.raw[prop],prop),audioStatsFn(output.raw[prop],prop),videoStatsFn(output.raw[prop],prop),videoE2EStatsFn(output.raw[prop],prop),isAutoBwStats&&!self._peerBandwidth[peerId][prop]?self._peerBandwidth[peerId][prop]=output.raw[prop]:isAutoBwStats||self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=output.raw[prop])}),output.audio.sending.bytes=output.audio.sending.bytes||0,output.audio.sending.packets=output.audio.sending.packets||0,output.audio.sending.totalBytes=output.audio.sending.totalBytes||0,output.audio.sending.totalPackets=output.audio.sending.totalPackets||0,output.video.sending.bytes=output.video.sending.bytes||0,output.video.sending.packets=output.video.sending.packets||0,output.video.sending.totalBytes=output.video.sending.totalBytes||0,output.video.sending.totalPackets=output.video.sending.totalPackets||0,output.audio.receiving.bytes=output.audio.receiving.bytes||0,output.audio.receiving.packets=output.audio.receiving.packets||0,output.audio.receiving.totalBytes=output.audio.receiving.totalBytes||0,output.audio.receiving.totalPackets=output.audio.receiving.totalPackets||0,output.video.receiving.bytes=output.video.receiving.bytes||0,output.video.receiving.packets=output.video.receiving.packets||0,output.video.receiving.totalBytes=output.video.receiving.totalBytes||0,output.video.receiving.totalPackets=output.video.receiving.totalPackets||0,callback(null,output)},errorCbFn=function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)};if("function"!=typeof pc.getStats)return errorCbFn(new Error("getStats() API is not available."));"plugin"===AdapterJS.webrtcDetectedType?pc.getStats(null,successCbFn,errorCbFn):pc.getStats(null).then(successCbFn).catch(errorCbFn)},Skylink.prototype._addPeer=function(targetMid,cert,peerBrowser,receiveOnly,isSS){var self=this;return self._peerConnections[targetMid]?void log.error([targetMid,null,null,"Connection to peer has already been made"]):(self._peerConnStatus[targetMid]={connected:!1,init:!1},log.log([targetMid,null,null,"Starting the connection to peer. Options provided:"],{peerBrowser:peerBrowser,receiveOnly:receiveOnly,enableDataChannel:self._enableDataChannel}),log.info("Adding peer",isSS),self._peerConnections[targetMid]=self._createPeerConnection(targetMid,!!isSS,cert),self._peerConnections[targetMid]?(self._peerConnStatus[targetMid].init=!0,void(self._peerConnections[targetMid].hasScreen=!!isSS)):void log.error([targetMid,null,null,"Failed creating the connection to peer."]))},Skylink.prototype._restartPeerConnection=function(peerId,doIceRestart,bwOptions,callback){var self=this;if(!self._peerConnections[peerId])return void log.error([peerId,null,null,"Peer does not have an existing connection. Unable to restart"]);var pc=self._peerConnections[peerId],agent=(self.getPeerInfo(peerId)||{}).agent||{};if(self._isLowerThanVersion(agent.SMProtocolVersion||"","0.1.2")){var notSupportedError=new Error("Failed restarting with other agents connecting from other SDKs as re-negotiation is not supported by other SDKs");return log.warn([peerId,"RTCPeerConnection",null,"Ignoring restart request as agent's SDK does not support it"],notSupportedError),void("function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(notSupportedError)))}if(pc.signalingState===self.PEER_CONNECTION_STATE.STABLE&&self._peerConnections[peerId]){log.log([peerId,null,null,"Sending restart message to signaling server ->"],{iceRestart:doIceRestart,options:bwOptions}),self._peerCustomConfigs[peerId]=self._peerCustomConfigs[peerId]||{},self._peerCustomConfigs[peerId].bandwidth=self._peerCustomConfigs[peerId].bandwidth||{},self._peerCustomConfigs[peerId].googleXBandwidth=self._peerCustomConfigs[peerId].googleXBandwidth||{},bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._peerCustomConfigs[peerId].bandwidth.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._peerCustomConfigs[peerId].bandwidth.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._peerCustomConfigs[peerId].bandwidth.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._peerCustomConfigs[peerId].googleXBandwidth.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._peerCustomConfigs[peerId].googleXBandwidth.max=bwOptions.googleXBandwidth.max));var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===doIceRestart&&self._enableIceRestart&&self._peerInformations[peerId]&&self._peerInformations[peerId].config.enableIceRestart,isRestartResend:!1,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._peerEndOfCandidatesCounter[peerId]=self._peerEndOfCandidatesCounter[peerId]||{},self._peerEndOfCandidatesCounter[peerId].len=0,self._sendChannelMessage(restartMsg),self._trigger("peerRestart",peerId,self.getPeerInfo(peerId),!0,!0===doIceRestart),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart callback"]),callback(null))}else if(pc.signalingState===self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER){var hasLocalDescription=pc.localDescription&&pc.localDescription.sdp;if(hasLocalDescription)self._sendChannelMessage({type:pc.localDescription.type,sdp:pc.localDescription.sdp,mid:self._user.sid,target:peerId,rid:self._room.id,restart:!0});else{var noLocalDescriptionError="Failed re-sending localDescription as there is no localDescription set to connection. There could be a handshaking step error";log.error([peerId,"RTCPeerConnection",null,noLocalDescriptionError],{localDescription:pc.localDescription,remoteDescription:pc.remoteDescription}),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(noLocalDescriptionError)))}}else{var unableToRestartError="Failed restarting as peer connection state is "+pc.signalingState;log.warn([peerId,"RTCPeerConnection",null,unableToRestartError]),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(unableToRestartError)))}},Skylink.prototype._removePeer=function(peerId){if(!this._peerConnections[peerId]&&!this._peerInformations[peerId])return void log.debug([peerId,"RTCPeerConnection",null,"Dropping the hangup from Peer as not connected to Peer at all."]);var peerInfo=clone(this.getPeerInfo(peerId))||{userData:"",settings:{audio:!1,video:!1,data:!1},mediaStatus:{audioMuted:!0,videoMuted:!0},agent:{name:"unknown",version:0,os:"",pluginVersion:null},config:{enableDataChannel:!0,enableIceRestart:!1,enableIceTrickle:!0,priorityWeight:0,publishOnly:!1,receiveOnly:!0},parentId:null,room:clone(this._selectedRoom)};"MCU"!==peerId?this._trigger("peerLeft",peerId,peerInfo,!1):(this._hasMCU=!1,log.log([peerId,null,null,"MCU has stopped listening and left"]),this._trigger("serverPeerLeft",peerId,this.SERVER_PEER_TYPE.MCU)),this._peerConnections[peerId]&&(this._peerConnections[peerId].signalingState!==this.PEER_CONNECTION_STATE.CLOSED&&(this._peerConnections[peerId].close(),"AppleWebKit"===AdapterJS.webrtcDetectedType&&(this._peerConnections[peerId].signalingStateClosed||(this._peerConnections[peerId].signalingStateClosed=!0,this._trigger("peerConnectionState",this.PEER_CONNECTION_STATE.CLOSED,peerId)),this._peerConnections[peerId].iceConnectionStateClosed||(this._peerConnections[peerId].iceConnectionStateClosed=!0,this._trigger("iceConnectionState",this.ICE_CONNECTION_STATE.CLOSED,peerId)))),"MCU"!==peerId&&this._handleEndedStreams(peerId),delete this._peerConnections[peerId]),this._peerInformations[peerId]&&delete this._peerInformations[peerId],this._peerMessagesStamps[peerId]&&delete this._peerMessagesStamps[peerId],this._streamsSession[peerId]&&delete this._streamsSession[peerId],this._peerEndOfCandidatesCounter[peerId]&&delete this._peerEndOfCandidatesCounter[peerId],this._peerCandidatesQueue[peerId]&&delete this._peerCandidatesQueue[peerId],this._sdpSessions[peerId]&&delete this._sdpSessions[peerId],this._peerStats[peerId]&&delete this._peerStats[peerId],this._peerBandwidth[peerId]&&delete this._peerBandwidth[peerId],this._gatheredCandidates[peerId]&&delete this._gatheredCandidates[peerId],this._peerCustomConfigs[peerId]&&delete this._peerCustomConfigs[peerId],this._peerConnStatus[peerId]&&delete this._peerConnStatus[peerId],this._dataChannels[peerId]&&this._closeDataChannel(peerId),log.log([peerId,"RTCPeerConnection",null,"Successfully removed peer"])},Skylink.prototype._createPeerConnection=function(targetMid,isScreenSharing,cert){var pc,self=this;if(self._inRoom&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)){var constraints={iceServers:self._room.connection.peerConfig.iceServers,iceTransportPolicy:self._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(self._useEdgeWebRTC&&window.msRTCPeerConnection?window.msRTCPeerConnection:RTCPeerConnection)(constraints,optional)}catch(error){return log.error([targetMid,null,null,"Failed creating peer connection:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),null}pc.setOffer="",pc.setAnswer="",pc.hasStream=!1,pc.hasScreen=!!isScreenSharing,pc.hasMainChannel=!1,pc.firefoxStreamId="",pc.processingLocalSDP=!1,pc.processingRemoteSDP=!1,pc.gathered=!1,pc.gathering=!1,pc.localStream=null,pc.localStreamId=null,pc.remoteStream=null,pc.remoteStreamId=null,pc.iceConnectionStateClosed=!1,pc.signalingStateClosed=!1,self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}},self._streamsSession[targetMid]=self._streamsSession[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._sdpSessions[targetMid]={local:{},remote:{}},self._peerBandwidth[targetMid]={};var bandwidth=null;return pc.ondatachannel=function(event){var dc=event.channel||event;if(log.debug([targetMid,"RTCDataChannel",dc.label,"Received datachannel ->"],dc),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel){self.DATA_CHANNEL_TYPE.DATA,dc.label;pc.hasMainChannel||(self.DATA_CHANNEL_TYPE.MESSAGING,"main",pc.hasMainChannel=!0),self._createDataChannel(targetMid,dc)}else log.warn([targetMid,"RTCDataChannel",dc.label,"Not adding datachannel as enable datachannel is set to false"])},pc.onaddstream=function(evt){if(self._peerConnections[targetMid]){var stream=evt.stream||evt;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received empty remote stream ->"],stream);pc.remoteStream=stream,pc.remoteStreamId=pc.remoteStreamId||stream.id||stream.label;var peerSettings=clone(self.getPeerInfo(targetMid).settings);self._streamsSession[targetMid][pc.remoteStreamId]=peerSettings,0===stream.getAudioTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].audio=!1),0===stream.getVideoTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].video=!1),pc.hasStream=!0,pc.hasScreen=peerSettings.video&&"object"==typeof peerSettings.video&&peerSettings.video.screenshare,self._onRemoteStreamAdded(targetMid,stream,!!pc.hasScreen)}},pc.onicecandidate=function(event){self._onIceCandidate(targetMid,event.candidate||event)},pc.oniceconnectionstatechange=function(evt){var iceConnectionState=pc.iceConnectionState;if(log.debug([targetMid,"RTCIceConnectionState",null,"Ice connection state changed ->"],iceConnectionState),"edge"===AdapterJS.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),"AppleWebKit"===AdapterJS.webrtcDetectedType&&iceConnectionState===self.ICE_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.iceConnectionStateClosed||self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.CLOSED,targetMid)},10);if(self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._enableIceTrickle&&self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.TRICKLE_FAILED,targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].connected=[self.ICE_CONNECTION_STATE.COMPLETED,self.ICE_CONNECTION_STATE.CONNECTED].indexOf(iceConnectionState)>-1),!self._hasMCU&&[self.ICE_CONNECTION_STATE.CONNECTED,self.ICE_CONNECTION_STATE.COMPLETED].indexOf(iceConnectionState)>-1&&self._bandwidthAdjuster&&!bandwidth&&"edge"!==AdapterJS.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),"AppleWebKit"===AdapterJS.webrtcDetectedType&&pc.signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.signalingStateClosed||self._trigger("peerConnectionState",self.PEER_CONNECTION_STATE.CLOSED,targetMid)},10);self._trigger("peerConnectionState",pc.signalingState,targetMid)},pc.onicegatheringstatechange=function(){log.log([targetMid,"RTCIceGatheringState",null,"Ice gathering state changed ->"],pc.iceGatheringState),self._trigger("candidateGenerationState",pc.iceGatheringState,targetMid)},"firefox"===AdapterJS.webrtcDetectedBrowser&&(pc.removeStream=function(stream){for(var senders=pc.getSenders(),s=0;s"],restartMsg),self._sendChannelMessage(restartMsg)};bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=bwOptions.googleXBandwidth.max));for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers},null):callback(null,{listOfPeers:listOfPeers}))};self.once("peerJoined",peerJoinedFn,function(peerId,peerInfo,isSelf){return isSelf}),self.leaveRoom(!1,function(error,success){if(error){if("function"==typeof callback){for(var i=0;i=self._peerEndOfCandidatesCounter[targetMid].expectedLen&&(!self._peerCandidatesQueue[targetMid]||0===self._peerCandidatesQueue[targetMid].length)&&!self._peerEndOfCandidatesCounter[targetMid].hasSet){log.debug([targetMid,"RTCPeerConnection",null,"Signaling of end-of-candidates remote ICE gathering."]),self._peerEndOfCandidatesCounter[targetMid].hasSet=!0;try{if("edge"===AdapterJS.webrtcDetectedBrowser){for(var mLineCounter=-1,addedMids=[],sdpLines=self._peerConnections[targetMid].remoteDescription.sdp.split("\r\n"),rejected=!1,i=0;i"],error)}}},Skylink.prototype.setUserData=function(userData){var self=this,updatedUserData="";void 0!==userData&&null!==userData&&(updatedUserData=userData),this._userData=updatedUserData,self._inRoom?(log.log("Updated userData -> ",updatedUserData),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.UPDATE_USER,mid:self._user.sid,rid:self._room.id,userData:updatedUserData,stamp:(new Date).getTime()}),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0)):log.warn("User is not in the room. Broadcast of updated information will be dropped")},Skylink.prototype.getUserData=function(peerId){if(peerId&&this._peerInformations[peerId]){var userData=this._peerInformations[peerId].userData;return null!==userData&&void 0===userData||(userData=""),userData}return this._userData},Skylink.prototype.getPeerInfo=function(peerId){var peerInfo=null;return"string"==typeof peerId&&"object"==typeof this._peerInformations[peerId]?(peerInfo=clone(this._peerInformations[peerId]),peerInfo.room=clone(this._selectedRoom),peerInfo.settings.bandwidth=peerInfo.settings.bandwidth||{},peerInfo.settings.googleXBandwidth=peerInfo.settings.googleXBandwidth||{},"boolean"==typeof peerInfo.settings.video||peerInfo.settings.video&&"object"==typeof peerInfo.settings.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"==typeof peerInfo.settings.audio||peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.audioMuted&&(peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.videoMuted&&(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.maxBandwidth&&(peerInfo.settings.bandwidth=clone(peerInfo.settings.maxBandwidth),delete peerInfo.settings.maxBandwidth),peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&peerInfo.settings.video.customSettings&&"object"==typeof peerInfo.settings.video.customSettings&&(peerInfo.settings.video.customSettings.frameRate&&(peerInfo.settings.video.frameRate=clone(peerInfo.settings.video.customSettings.frameRate)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode)),peerInfo.settings.video.customSettings.width&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.width=clone(peerInfo.settings.video.customSettings.width)),peerInfo.settings.video.customSettings.height&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.height=clone(peerInfo.settings.video.customSettings.height)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode))),peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&(peerInfo.settings.audio.stereo=!0===peerInfo.settings.audio.stereo),null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),peerInfo.parentId=peerInfo.parentId||null,"MCU"===peerId?(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1):this._hasMCU&&(peerInfo.config.receiveOnly=!1,peerInfo.config.publishOnly=!0),this._sdpSettings.direction.audio.receive||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.direction.video.receive||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.data=!!(this._dataChannels[peerId]&&this._dataChannels[peerId].main&&this._dataChannels[peerId].main.channel&&this._dataChannels[peerId].main.channel.readyState===this.DATA_CHANNEL_STATE.OPEN),peerInfo.connected=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].connected,peerInfo.init=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].init,this._sdpSessions[peerId]&&this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&"object"==typeof this._sdpSessions[peerId].remote.connection&&(this._sdpSessions[peerId].remote.connection.audio&&this._sdpSessions[peerId].remote.connection.audio.indexOf("send")>-1||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSessions[peerId].remote.connection.video&&this._sdpSessions[peerId].remote.connection.video.indexOf("send")>-1||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSessions[peerId].remote.connection.data&&this._sdpSessions[peerId].remote.connection.data.indexOf("send")>-1||(peerInfo.settings.data=!1))):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,os:window.navigator.platform,pluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:this.SMProtocolVersion,DTProtocolVersion:this.DTProtocolVersion},room:clone(this._selectedRoom),config:{enableDataChannel:this._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;i-1||(customSettings.settings.audio=!1,customSettings.mediaStatus.audioMuted=!0),self._sdpSessions[usePeerId].local.connection.video&&self._sdpSessions[usePeerId].local.connection.video.indexOf("send")>-1||(customSettings.settings.video=!1,customSettings.mediaStatus.videoMuted=!0),self._sdpSessions[usePeerId].local.connection.data&&self._sdpSessions[usePeerId].local.connection.data.indexOf("send")>-1||(customSettings.settings.data=!1)),customSettings},Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo()),userCustomInfoForPeer=peerId?this._getPeerCustomSettings(peerId):null;return userCustomInfoForPeer&&"object"==typeof userCustomInfoForPeer&&(userInfo.settings=userCustomInfoForPeer.settings,userInfo.mediaStatus=userCustomInfoForPeer.mediaStatus),userInfo.settings.video&&"object"==typeof userInfo.settings.video&&(userInfo.settings.video.customSettings={},userInfo.settings.video.frameRate&&"object"==typeof userInfo.settings.video.frameRate&&(userInfo.settings.video.customSettings.frameRate=clone(userInfo.settings.video.frameRate),userInfo.settings.video.frameRate=-1),userInfo.settings.video.facingMode&&"object"==typeof userInfo.settings.video.facingMode&&(userInfo.settings.video.customSettings.facingMode=clone(userInfo.settings.video.facingMode),userInfo.settings.video.facingMode="-1"),userInfo.settings.video.resolution&&"object"==typeof userInfo.settings.video.resolution&&(userInfo.settings.video.resolution.width&&"object"==typeof userInfo.settings.video.resolution.width&&(userInfo.settings.video.customSettings.width=clone(userInfo.settings.video.width),userInfo.settings.video.resolution.width=-1),userInfo.settings.video.resolution.height&&"object"==typeof userInfo.settings.video.resolution.height&&(userInfo.settings.video.customSettings.height=clone(userInfo.settings.video.height),userInfo.settings.video.resolution.height=-1))),userInfo.settings.bandwidth&&(userInfo.settings.maxBandwidth=clone(userInfo.settings.bandwidth),delete userInfo.settings.bandwidth),this._getSDPCommonSupports(peerId).video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._getSDPCommonSupports(peerId).audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart){var self=this,pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of creating of offer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription","offer",'Dropping of creating of offer as signalingState is not "'+self.PEER_CONNECTION_STATE.STABLE+'" ->'],pc.signalingState);var offerConstraints={offerToReceiveAudio:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).video,offerToReceiveVideo:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).audio,iceRestart:!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,voiceActivityDetection:self._voiceActivityDetection};self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._dataChannels[targetMid]&&self._dataChannels[targetMid].main||(self._createDataChannel(targetMid),self._peerConnections[targetMid].hasMainChannel=!0)),log.debug([targetMid,null,null,"Creating offer with config:"],offerConstraints),pc.endOfCandidates=!1,self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=offerConstraints);var onSuccessCbFn=function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)};pc.createOffer(onSuccessCbFn,onErrorCbFn,"plugin"===AdapterJS.webrtcDetectedType?{mandatory:{OfferToReceiveAudio:offerConstraints.offerToReceiveAudio,OfferToReceiveVideo:offerConstraints.offerToReceiveVideo,iceRestart:offerConstraints.iceRestart,voiceActivityDetection:offerConstraints.voiceActivityDetection}}:offerConstraints)},Skylink.prototype._doAnswer=function(targetMid){var self=this;log.log([targetMid,null,null,"Creating answer with config:"],self._room.connection.sdpConstraints);var pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of creating of answer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription","answer",'Dropping of creating of answer as signalingState is not "'+self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER+'" ->'],pc.signalingState);var answerConstraints="edge"===AdapterJS.webrtcDetectedBrowser?{offerToReceiveVideo:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).video,offerToReceiveAudio:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).audio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints);var onSuccessCbFn=function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},onErrorCbFn=function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.createAnswer(onSuccessCbFn,onErrorCbFn,answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,_sessionDescription){var self=this,pc=self._peerConnections[targetMid];if(!_sessionDescription||!_sessionDescription.sdp)return void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],_sessionDescription);if(!pc)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as connection does not exists ->"],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(pc.processingLocalSDP)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as another is being processed ->"],_sessionDescription);pc.processingLocalSDP=!0;var sessionDescription={type:_sessionDescription.type,sdp:_sessionDescription.sdp};sessionDescription.sdp=self._removeSDPFirefoxH264Pref(targetMid,sessionDescription),sessionDescription.sdp=self._setSDPCodecParams(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPUnknownAptRtx(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPCodecs(targetMid,sessionDescription),sessionDescription.sdp=self._handleSDPConnectionSettings(targetMid,sessionDescription,"local"),sessionDescription.sdp=self._removeSDPREMBPackets(targetMid,sessionDescription),log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description updated ->"],sessionDescription.sdp);var onSuccessCbFn=function(){if(log.debug([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description has been set ->"],sessionDescription),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",sessionDescription.type,targetMid),sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER?pc.setAnswer="local":pc.setOffer="local",!self._enableIceTrickle&&!pc.gathered)return void log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description sending is halted to complete ICE gathering."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},onErrorCbFn=function(error){log.error([targetMid,"RTCSessionDescription",sessionDescription.type,"Local description failed setting ->"],error),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.setLocalDescription(new RTCSessionDescription(sessionDescription),onSuccessCbFn,onErrorCbFn)},Skylink.prototype.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={},timestamp=(new Date).getTime()+Math.floor(1e4*Math.random());self._joinRoomManager.timestamp=timestamp,room&&"string"==typeof room?selectedRoom=room:room&&"object"==typeof room?mediaOptions=room:"function"==typeof room&&(callback=room),options&&"object"==typeof options?mediaOptions=options:"function"==typeof options&&(callback=options);var resolveAsErrorFn=function(error,tryRoom,readyState){log.error(error),"function"==typeof callback&&callback({room:tryRoom,errorCode:readyState||null,error:error instanceof Error?error:new Error(JSON.stringify(error))})},joinRoomFn=function(){if(self._joinRoomManager.timestamp!==timestamp)return void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom);self._initSelectedRoom(selectedRoom,function(initError,initSuccess){return initError?void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState):self._joinRoomManager.timestamp!==timestamp?void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom):void self._waitForOpenChannel(mediaOptions||{},timestamp,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);if(self._joinRoomManager.timestamp!==timestamp)return void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom);if("AppleWebKit"===AdapterJS.webrtcDetectedType){var checkStream=self._streams.screenshare&&self._streams.screenshare.stream?self._streams.screenshare.stream:self._streams.userMedia&&self._streams.userMedia.stream?self._streams.userMedia.stream:null;checkStream&&0!==checkStream.getTracks().length?0===checkStream.getAudioTracks().length?log.warn("Note that receiving audio streams may fail as safari 11 needs stream with audio and video tracks and not just with video tracks"):0===checkStream.getVideoTracks().length&&log.warn("Note that receiving video streams may fail as safari 11 needs stream with audio and video tracks and not just with audio tracks"):log.warn("Note that receiving audio and video streams may fail as safari 11 needs stream with audio and video tracks")}if("function"==typeof callback){var peerOnJoin=function(peerId,peerInfo,isSelf){self.off("systemAction",peerFailedJoin),self.off("channelClose",peerSocketFailedJoin),log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo})},peerFailedJoin=function(action,message){self.off("peerJoined",peerOnJoin),self.off("channelClose",peerSocketFailedJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room ->"],message),resolveAsErrorFn(new Error(message),self._selectedRoom,self._readyState)},peerSocketFailedJoin=function(){self.off("systemAction",peerFailedJoin),self.off("peerJoined",peerOnJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room due to abrupt disconnection."]),resolveAsErrorFn(new Error("Channel closed abruptly before session was established"),self._selectedRoom,self._readyState)};self.once("peerJoined",peerOnJoin,function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),self.once("systemAction",peerFailedJoin,function(action){return action===self.SYSTEM_ACTION.REJECT}),self.once("channelClose",peerSocketFailedJoin)}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.JOIN_ROOM,uid:self._user.uid,cid:self._key,rid:self._room.id,userCred:self._user.token,timeStamp:self._user.timeStamp,apiOwner:self._appKeyOwner,roomCred:self._room.token,start:self._room.startDateTime,len:self._room.duration,isPrivileged:!0===self._isPrivileged,autoIntroduce:!1!==self._autoIntroduce,key:self._appKey})})})};if(null===room||["number","boolean"].indexOf(typeof room)>-1)return void resolveAsErrorFn("Invalid room name is provided",room);if(null===options||["number","boolean"].indexOf(typeof options)>-1)return void resolveAsErrorFn("Invalid mediaOptions is provided",selectedRoom);self._joinRoomManager.socketsFn.forEach(function(fnItem){fnItem(timestamp)}),self._joinRoomManager.socketsFn=[];var stopStream=!1===mediaOptions.audio&&!1===mediaOptions.video;self._inRoom?self.leaveRoom({userMedia:stopStream},function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()}):(stopStream&&self.stopStream(),joinRoomFn())},Skylink.prototype.leaveRoom=function(stopMediaOptions,callback){var self=this,stopUserMedia=!0,stopScreenshare=!0,previousRoom=self._selectedRoom,previousUserPeerId=self._user?self._user.sid:null,peersThatLeft=[],isNotInRoom=!self._inRoom;"boolean"==typeof stopMediaOptions?!1===stopMediaOptions&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=!1!==stopMediaOptions.userMedia,stopScreenshare=!1!==stopMediaOptions.screenshare):"function"==typeof stopMediaOptions&&(callback=stopMediaOptions);for(var infoPeerId in self._peerInformations)self._peerInformations.hasOwnProperty(infoPeerId)&&self._peerInformations[infoPeerId]&&(peersThatLeft.push(infoPeerId),self._removePeer(infoPeerId));for(var connPeerId in self._peerConnections)self._peerConnections.hasOwnProperty(connPeerId)&&self._peerConnections[connPeerId]&&-1===peersThatLeft.indexOf(connPeerId)&&(peersThatLeft.push(connPeerId),self._removePeer(connPeerId));if(self._inRoom=!1,self._closeChannel(),isNotInRoom){var notInRoomError="Unable to leave room as user is not in any room";return log.error([null,"Room",previousRoom,notInRoomError]),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}self._stopStreams({userMedia:stopUserMedia,screenshare:stopScreenshare}),self._wait(function(){log.log([null,"Room",previousRoom,"User left the room"]),
+self._trigger("peerLeft",previousUserPeerId,self.getPeerInfo(),!0),"function"==typeof callback&&callback(null,{peerId:previousUserPeerId,previousRoom:previousRoom})},function(){return!self._channelOpen})},Skylink.prototype.lockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!0),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!0}),this._roomLocked=!0,this._trigger("roomLock",!0,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype.unlockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!1),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!1}),this._roomLocked=!1,this._trigger("roomLock",!1,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype._waitForOpenChannel=function(mediaOptions,joinRoomTimestamp,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){var onChannelOpen=function(){self.off("socketError",onChannelError),setTimeout(function(){if(mediaOptions=mediaOptions||{},self._userData=mediaOptions.userData||self._userData||"",self._streamsBandwidthSettings={googleX:{},bAS:{}},self._publishOnly=!1,self._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},self._voiceActivityDetection="boolean"!=typeof mediaOptions.voiceActivityDetection||mediaOptions.voiceActivityDetection,self._peerConnectionConfig={bundlePolicy:self.BUNDLE_POLICY.BALANCED,rtcpMuxPolicy:self.RTCP_MUX_POLICY.REQUIRE,iceCandidatePoolSize:0,certificate:self.PEER_CERTIFICATE.AUTO},self._bandwidthAdjuster=null,mediaOptions.bandwidth&&("number"==typeof mediaOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=mediaOptions.bandwidth.audio),"number"==typeof mediaOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=mediaOptions.bandwidth.video),"number"==typeof mediaOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=mediaOptions.bandwidth.data)),mediaOptions.googleXBandwidth&&("number"==typeof mediaOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=mediaOptions.googleXBandwidth.min),"number"==typeof mediaOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=mediaOptions.googleXBandwidth.max)),mediaOptions.sdpSettings&&(mediaOptions.sdpSettings.direction&&(mediaOptions.sdpSettings.direction.audio&&(self._sdpSettings.direction.audio.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.receive||mediaOptions.sdpSettings.direction.audio.receive,self._sdpSettings.direction.audio.send="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.send||mediaOptions.sdpSettings.direction.audio.send),mediaOptions.sdpSettings.direction.video&&(self._sdpSettings.direction.video.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.video.receive||mediaOptions.sdpSettings.direction.video.receive,self._sdpSettings.direction.video.send="boolean"!=typeof mediaOptions.sdpSettings.direction.video.send||mediaOptions.sdpSettings.direction.video.send)),mediaOptions.sdpSettings.connection&&(self._sdpSettings.connection.audio="boolean"!=typeof mediaOptions.sdpSettings.connection.audio||mediaOptions.sdpSettings.connection.audio,self._sdpSettings.connection.video="boolean"!=typeof mediaOptions.sdpSettings.connection.video||mediaOptions.sdpSettings.connection.video,self._sdpSettings.connection.data="boolean"!=typeof mediaOptions.sdpSettings.connection.data||mediaOptions.sdpSettings.connection.data)),mediaOptions.publishOnly&&(self._sdpSettings.direction.audio.send=!0,self._sdpSettings.direction.audio.receive=!1,self._sdpSettings.direction.video.send=!0,self._sdpSettings.direction.video.receive=!1,self._publishOnly=!0,"object"==typeof mediaOptions.publishOnly&&mediaOptions.publishOnly.parentId&&"string"==typeof mediaOptions.publishOnly.parentId&&(self._parentId=mediaOptions.publishOnly.parentId)),mediaOptions.parentId&&(self._parentId=mediaOptions.parentId),mediaOptions.peerConnection&&"object"==typeof mediaOptions.peerConnection){if("string"==typeof mediaOptions.peerConnection.bundlePolicy)for(var bpProp in self.BUNDLE_POLICY)self.BUNDLE_POLICY.hasOwnProperty(bpProp)&&self.BUNDLE_POLICY[bpProp]===mediaOptions.peerConnection.bundlePolicy&&(self._peerConnectionConfig.bundlePolicy=mediaOptions.peerConnection.bundlePolicy);if("string"==typeof mediaOptions.peerConnection.rtcpMuxPolicy)for(var rmpProp in self.RTCP_MUX_POLICY)self.RTCP_MUX_POLICY.hasOwnProperty(rmpProp)&&self.RTCP_MUX_POLICY[rmpProp]===mediaOptions.peerConnection.rtcpMuxPolicy&&(self._peerConnectionConfig.rtcpMuxPolicy=mediaOptions.peerConnection.rtcpMuxPolicy);if("number"==typeof mediaOptions.peerConnection.iceCandidatePoolSize&&mediaOptions.peerConnection.iceCandidatePoolSize>0&&(self._peerConnectionConfig.iceCandidatePoolSize=mediaOptions.peerConnection.iceCandidatePoolSize),"string"==typeof mediaOptions.peerConnection.certificate)for(var pcProp in self.PEER_CERTIFICATE)self.PEER_CERTIFICATE.hasOwnProperty(pcProp)&&self.PEER_CERTIFICATE[pcProp]===mediaOptions.peerConnection.certificate&&(self._peerConnectionConfig.certificate=mediaOptions.peerConnection.certificate)}if(mediaOptions.autoBandwidthAdjustment&&(self._bandwidthAdjuster={interval:10,limitAtPercentage:100,useUploadBwOnly:!1},"object"==typeof mediaOptions.autoBandwidthAdjustment&&("number"==typeof mediaOptions.autoBandwidthAdjustment.interval&&mediaOptions.autoBandwidthAdjustment.interval>=10&&(self._bandwidthAdjuster.interval=mediaOptions.autoBandwidthAdjustment.interval),"number"==typeof mediaOptions.autoBandwidthAdjustment.limitAtPercentage&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage>=0&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage<=100&&(self._bandwidthAdjuster.limitAtPercentage=mediaOptions.autoBandwidthAdjustment.limitAtPercentage),"boolean"==typeof mediaOptions.autoBandwidthAdjustment.useUploadBwOnly&&(self._bandwidthAdjuster.useUploadBwOnly=mediaOptions.autoBandwidthAdjustment.useUploadBwOnly))),!0===mediaOptions.manualGetUserMedia){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){!0===mediaAccessRequiredFailure?self._onUserMediaError(new Error("Waiting for stream timeout"),!1,!1):callback(null,self._streams.userMedia.stream)},function(){return current50Block+=1,600===current50Block?(mediaAccessRequiredFailure=!0,!0):!(!self._streams.userMedia||!self._streams.userMedia.stream)||void 0},50)}if(mediaOptions.audio||mediaOptions.video)return void self.getUserMedia({useExactConstraints:!!mediaOptions.useExactConstraints,audio:mediaOptions.audio,video:mediaOptions.video},function(error,success){error?callback(error,null):callback(null,success)});callback(null,null)},1)},onChannelError=function(errorState,error){self.off("channelOpen",onChannelOpen),callback(error)};self._channelOpen?onChannelOpen():(self.once("channelOpen",onChannelOpen),self.once("socketError",onChannelError,function(errorState){return errorState===self.SOCKET_ERROR.RECONNECTION_ABORTED}),self._openChannel(joinRoomTimestamp))},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.26",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,XML_HTTP_NO_REPONSE_ERROR:-2,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=!0,socketTimeout=7e3,apiTimeout=4e3,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!1,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,useEdgeWebRTC=!1,enableSimultaneousTransfers=!0;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&&socketTimeout<5e3&&socketTimeout>0?options.socketTimeout:socketTimeout,apiTimeout="number"==typeof options.apiTimeout&&options.apiTimeout>0?options.apiTimeout:apiTimeout,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,useEdgeWebRTC="boolean"==typeof options.useEdgeWebRTC?options.useEdgeWebRTC:useEdgeWebRTC,enableSimultaneousTransfers="boolean"==typeof options.enableSimultaneousTransfers?options.enableSimultaneousTransfers:enableSimultaneousTransfers,"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,"sprop-stereo":"boolean"==typeof options.codecParams.audio.opus["sprop-stereo"]?options.codecParams.audio.opus["sprop-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),!0===forceTURN&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===AdapterJS.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._apiTimeout=apiTimeout,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,self._useEdgeWebRTC=useEdgeWebRTC,self._enableSimultaneousTransfers=enableSimultaneousTransfers,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,apiTimeout:self._apiTimeout,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,useEdgeWebRTC:self._useEdgeWebRTC,enableSimultaneousTransfers:self._enableSimultaneousTransfers}),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,apiTimeout:self._apiTimeout,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,useEdgeWebRTC:self._useEdgeWebRTC,enableSimultaneousTransfers:self._enableSimultaneousTransfers})):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:error.content instanceof Error?error.content:new Error(JSON.stringify(error.content)),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,retries=0;self._socketUseXDR="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest,url=self._forceSSL?"https:"+url:url,function requestFn(){var xhr=new XMLHttpRequest,completed=!1;self._socketUseXDR&&(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest for CORS authentication."]),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}),xhr.onload=function(){if(!completed){completed=!0;var response=JSON.parse(xhr.responseText||xhr.response||"{}"),status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters ->"],response),callback(status,response)}},xhr.onerror=function(error){completed||(completed=!0,log.error([null,"XMLHttpRequest",method,"Failed retrieving information with 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,params:params})};try{xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()}catch(error){return completed=!0,self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"Failed starting XHR process.",errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom)}setTimeout(function(){completed||(completed=!0,xhr.onload=null,xhr.onerror=null,xhr.onprogress=null,retries<2?(retries++,requestFn()):(self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"Response timed out from API server",errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_NO_REPONSE_ERROR},self._selectedRoom)))},self._apiTimeout)}()},Skylink.prototype._parseInfo=function(info){if(log.log("Parsing parameter from server",info),!info.pc_constraints&&!info.offer_constraints)return void this._trigger("readyStateChange",this.READY_STATE_CHANGE.ERROR,{status:200,content:info.info,errorCode:info.error},self._selectedRoom);log.debug("Peer connection constraints:",info.pc_constraints),log.debug("Offer constraints:",info.offer_constraints),this._key=info.cid,this._appKeyOwner=info.apiOwner,this._signalingServer=info.ipSigserver,this._isPrivileged=info.isPrivileged,this._autoIntroduce=info.autoIntroduce,this._user={uid:info.username,token:info.userCred,timeStamp:info.timeStamp,streams:[],info:{}},this._room={id:info.room_key,token:info.roomCred,startDateTime:info.start,duration:info.len,connection:{peerConstraints:JSON.parse(info.pc_constraints),peerConfig:null,offerConstraints:JSON.parse(info.offer_constraints),sdpConstraints:{mandatory:{OfferToReceiveAudio:!0,OfferToReceiveVideo:!0}},mediaConstraints:JSON.parse(info.media_constraints)}},this._socketPorts={"http:":Array.isArray(info.httpPortList)&&info.httpPortList.length>0?info.httpPortList:[80,3e3],"https:":Array.isArray(info.httpsPortList)&&info.httpsPortList.length>0?info.httpsPortList:[443,3443]},this._readyState=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;if("function"!=typeof(globals.AdapterJS||window.AdapterJS||{}).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 globals.io||window.io?window.XMLHttpRequest?self._path?void AdapterJS.webRTCReady(function(){if(self._enableIceRestart="firefox"!==AdapterJS.webrtcDetectedBrowser||AdapterJS.webrtcDetectedVersion>=48,self._binaryChunkType="firefox"===AdapterJS.webrtcDetectedBrowser?self.DATA_TRANSFER_DATA_TYPE.BLOB:self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&"plugin"===AdapterJS.webrtcDetectedType?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"plugin"===AdapterJS.webrtcDetectedType&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=-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,apiTimeout:self._apiTimeout,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,useEdgeWebRTC:self._useEdgeWebRTC,enableSimultaneousTransfers:self._enableSimultaneousTransfers};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_KEY="SkylinkJS",_LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!1,_printTimestamp=!1,_storedLogs=[],_getStoredLogsFn=function(logLevel){if(void 0===logLevel)return _storedLogs;for(var returnLogs=[],i=0;i<_storedLogs.length;i++)_storedLogs[i][1]===_LOG_LEVELS[logLevel]&&returnLogs.push(_storedLogs[i]);return returnLogs},_clearAllStoredLogsFn=function(){_storedLogs=[]},_printAllStoredLogsFn=function(){for(var i=0;i<_storedLogs.length;i++){var timestamp=_storedLogs[i][0],log="undefined"!==console[_storedLogs[i][1]]?_storedLogs[i][1]:"log",message=_storedLogs[i][2],debugObject=_storedLogs[i][3];void 0!==debugObject?console[log](message,debugObject,timestamp):console[log](message,timestamp)}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="",datetime=new Date;if("object"==typeof message){if(outputLog+=message[0]?" ["+message[0]+"] -":" -",outputLog+=message[1]?" <<"+message[1]+">>":"",message[2])if(outputLog+=" ","object"==typeof message[2])for(var i=0;i=logLevel)if(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace){void 0===console.trace&&logLevel[3];void 0!==debugObject?(console[_LOG_LEVELS[logLevel]](outputLog,debugObject),void 0!==console.trace&&console.trace("")):(console[_LOG_LEVELS[logLevel]](outputLog),void 0!==console.trace&&console.trace(""))}else void 0!==debugObject?console[_LOG_LEVELS[logLevel]](outputLog,debugObject):console[_LOG_LEVELS[logLevel]](outputLog)},log={debug:function(message,object){_logFn(4,message,object)},log:function(message,object){_logFn(3,message,object)},info:function(message,object){_logFn(2,message,object)},warn:function(message,object){_logFn(1,message,object)},error:function(message,object){_logFn(0,message,object)}};Skylink.prototype.setLogLevel=function(logLevel){for(var level in this.LOG_LEVEL)if(this.LOG_LEVEL[level]===logLevel)return _logLevel=logLevel,void log.log([null,"Log",level,"Log level exists. Level is set"]);log.error([null,"Log",level,"Log level does not exist. Level is not set"])},Skylink.prototype.setDebugMode=function(isDebugMode){isDebugMode&&"object"==typeof isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0===isDebugMode.trace,_enableDebugStack=!0===isDebugMode.storeLogs,_printTimestamp=!0===isDebugMode.printTimestamp):!0===isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0,_printTimestamp=!1):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1,_printTimestamp=!1)};Skylink.prototype.on=function(eventName,callback){"function"==typeof callback?(this._EVENTS[eventName]=this._EVENTS[eventName]||[],this._EVENTS[eventName].push(callback),log.log([null,"Event",eventName,"Event is subscribed"])):log.error([null,"Event",eventName,"Provided parameter is not a function"])},Skylink.prototype.once=function(eventName,callback,condition,fireAlways){"boolean"==typeof condition&&(fireAlways=condition,condition=null),fireAlways=void 0!==fireAlways&&fireAlways,condition="function"!=typeof condition?function(){return!0}:condition,"function"==typeof callback?(this._onceEvents[eventName]=this._onceEvents[eventName]||[],this._onceEvents[eventName].push([callback,condition,fireAlways]),log.log([null,"Event",eventName,"Event is subscribed on condition"])):log.error([null,"Event",eventName,"Provided callback is not a function"])},Skylink.prototype.off=function(eventName,callback){if(eventName&&"string"==typeof eventName){if(void 0===callback)return this._EVENTS[eventName]=[],this._onceEvents[eventName]=[],void log.log([null,"Event",eventName,"All events are unsubscribed"]);for(var arr=this._EVENTS[eventName]||[],once=this._onceEvents[eventName]||[],i=0;i"],message);self._user.sid&&!self._peerMessagesStamps[self._user.sid]&&(self._peerMessagesStamps[self._user.sid]={userData:0,audioMuted:0,videoMuted:0});var checkStampFn=function(statusMessage){return statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].userData:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].videoMuted:statusMessage.type!==self._SIG_MESSAGE_TYPE.MUTE_AUDIO||!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].audioMuted},setStampFn=function(statusMessage){statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?self._peerMessagesStamps[self._user.sid].userData=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?self._peerMessagesStamps[self._user.sid].videoMuted=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&(self._peerMessagesStamps[self._user.sid].audioMuted=statusMessage.stamp)},setQueueFn=function(){log.debug([null,"Socket",null,"Starting queue timeout"]),self._socketMessageTimeout=setTimeout(function(){if((new Date).getTime()-self._timestamp.socketMessage<=interval)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},interval-((new Date).getTime()-self._timestamp.socketMessage))},triggerEventFn=function(eventMessage){eventMessage.type===self._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE&&self._trigger("incomingMessage",{content:eventMessage.data,isPrivate:!1,targetPeerId:null,listOfPeers:Object.keys(self._peerInformations),isDataChannel:!1,senderPeerId:self._user.sid},self._user.sid,self.getPeerInfo(),!0)},sendGroupMessageFn=function(groupMessageList){if(self._socketMessageTimeout=null,!(self._channelOpen&&self._user&&self._user.sid&&self._socket))return void log.warn([message.target||"Server","Socket",null,"Dropping of group messages as Socket connection is not opened or is at incorrect step ->"],groupMessageList);for(var strGroupMessageList=[],stamps={userData:0,audioMuted:0,videoMuted:0},k=0;kself._peerMessagesStamps[self._user.sid].userData&&groupMessageList[k].stamp>stamps.userData?stamps.userData=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].audioMuted&&groupMessageList[k].stamp>stamps.audioMuted?stamps.audioMuted=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].videoMuted&&groupMessageList[k].stamp>stamps.videoMuted&&(stamps.videoMuted=groupMessageList[k].stamp));for(var i=0;i"],clone(groupMessageList[i])),groupMessageList.splice(i,1),i--):strGroupMessageList.push(JSON.stringify(groupMessageList[i]));if(strGroupMessageList.length>0){var groupMessage={type:self._SIG_MESSAGE_TYPE.GROUP,lists:strGroupMessageList,mid:self._user.sid,rid:self._room.id};log.log([message.target||"Server","Socket",groupMessage.type,"Sending queued grouped message (max: 16 per group) ->"],clone(groupMessage)),self._socket.send(JSON.stringify(groupMessage)),self._timestamp.socketMessage=(new Date).getTime();for(var j=0;j0&&(self._socketMessageQueue.length-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=interval)log.debug([message.target||"Server","Socket",message.type,"Queueing socket message to prevent message drop ->"],clone(message)),self._socketMessageQueue.push(message),self._socketMessageTimeout||setQueueFn();else{if(!checkStampFn(message))return void log.warn([message.target||"Server","Socket",message.type,"Dropping of outdated status message ->"],clone(message));self._socketMessageTimeout&&clearTimeout(self._socketMessageTimeout),log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),setStampFn(message),triggerEventFn(message),self._timestamp.socketMessage=(new Date).getTime()}else log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),message.type===self._SIG_MESSAGE_TYPE.BYE&&self._inRoom&&self._user&&self._user.sid&&message.mid===self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo()))},Skylink.prototype._createSocket=function(type,joinRoomTimestamp){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._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+"?rand="+Date.now(),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));var socket=null;try{socket=io.connect(url,options)}catch(error){return log.error("Failed creating socket connection object ->",error),fallbackType===self.SOCKET_FALLBACK.NON_FALLBACK?self._trigger("socketError",self.SOCKET_ERROR.CONNECTION_FAILED,error,fallbackType,clone(self._socketSession)):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_FAILED,error,fallbackType,clone(self._socketSession)),void self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ABORTED,new Error("Reconnection aborted as there no more available ports, transports and final attempts left."),fallbackType,clone(self._socketSession))}socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),socket.on("reconnect_failed",function(){fallbackType===self.SOCKET_FALLBACK.NON_FALLBACK?self._trigger("socketError",self.SOCKET_ERROR.CONNECTION_FAILED,new Error('Failed connection with transport "'+type+'" and port '+self._signalingServerPort+"."),fallbackType,clone(self._socketSession)):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_FAILED,new Error('Failed reconnection with transport "'+type+'" and port '+self._signalingServerPort+"."),fallbackType,clone(self._socketSession)),self._socketSession.finalAttempts<2?self._createSocket(type,joinRoomTimestamp):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ABORTED,new Error("Reconnection aborted as there no more available ports, transports and final attempts left."),fallbackType,clone(self._socketSession))}),socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),socket.on("error",function(error){if(error&&error.message.indexOf("xhr poll error")>-1)return log.error([null,"Socket",null,"XHR poll connection unstable. Disconnecting.. ->"],error),void self._closeChannel();log.error([null,"Socket",null,"Exception occurred ->"],error),self._trigger("channelError",error,clone(self._socketSession))}),socket.on("disconnect",function(){self._channelOpen&&(self._channelOpen=!1,self._trigger("channelClose",clone(self._socketSession)),log.log([null,"Socket",null,"Channel closed"]),self._inRoom&&self._user&&self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo())))}),socket.on("message",function(messageStr){var message=JSON.parse(messageStr);if(log.log([null,"Socket",null,"Received message ->"],message),message.type===self._SIG_MESSAGE_TYPE.GROUP){log.debug("Bundle of "+message.lists.length+" messages");for(var i=0;i",message);for(var i=0;i-1:state===self.RECORDING_STATE.STOP})}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.STOP_RECORDING,rid:self._room.id,target:"MCU"}),log.debug(["MCU","Recording",null,"Stopping recording"])},Skylink.prototype.getRecordings=function(){return clone(this._recordings)},Skylink.prototype._processSigMessage=function(message,session){var origin=message.mid;if(origin&&origin!==this._user.sid||(origin="Server"),log.debug([origin,"Socket",message.type,"Received from peer ->"],clone(message)),message.mid===this._user.sid&&message.type!==this._SIG_MESSAGE_TYPE.REDIRECT&&message.type!==this._SIG_MESSAGE_TYPE.IN_ROOM)return void log.debug([origin,"Socket",message.type,"Ignoring message ->"],clone(message));switch(message.type){case this._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE:this._publicMessageHandler(message);break;case this._SIG_MESSAGE_TYPE.PRIVATE_MESSAGE:this._privateMessageHandler(message);break;case this._SIG_MESSAGE_TYPE.IN_ROOM:this._inRoomHandler(message);break;case this._SIG_MESSAGE_TYPE.ENTER:this._enterHandler(message);break;case this._SIG_MESSAGE_TYPE.WELCOME:this._welcomeHandler(message);break;case this._SIG_MESSAGE_TYPE.RESTART:this._restartHandler(message);break;case this._SIG_MESSAGE_TYPE.OFFER:this._offerHandler(message);break;case this._SIG_MESSAGE_TYPE.ANSWER:this._answerHandler(message);break;case this._SIG_MESSAGE_TYPE.CANDIDATE:this._candidateHandler(message);break;case this._SIG_MESSAGE_TYPE.BYE:this._byeHandler(message);break;case this._SIG_MESSAGE_TYPE.REDIRECT:this._redirectHandler(message);break;case this._SIG_MESSAGE_TYPE.UPDATE_USER:this._updateUserEventHandler(message);break;case this._SIG_MESSAGE_TYPE.MUTE_VIDEO:this._muteVideoEventHandler(message);break;case this._SIG_MESSAGE_TYPE.MUTE_AUDIO:this._muteAudioEventHandler(message);break;case this._SIG_MESSAGE_TYPE.STREAM:this._streamEventHandler(message);break;case this._SIG_MESSAGE_TYPE.ROOM_LOCK:this._roomLockEventHandler(message);break;case this._SIG_MESSAGE_TYPE.PEER_LIST:this._peerListEventHandler(message);break;case this._SIG_MESSAGE_TYPE.INTRODUCE_ERROR:this._introduceErrorEventHandler(message);break;case this._SIG_MESSAGE_TYPE.APPROACH:this._approachEventHandler(message);break;case this._SIG_MESSAGE_TYPE.RECORDING:this._recordingEventHandler(message);break;case this._SIG_MESSAGE_TYPE.END_OF_CANDIDATES:this._endOfCandidatesHandler(message);break;default:log.error([message.mid,"Socket",message.type,"Unsupported message ->"],clone(message))}},Skylink.prototype._peerListEventHandler=function(message){var self=this;self._peerList=message.result,log.log(["Server",null,message.type,"Received list of peers"],self._peerList),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.RECEIVED,self._user.sid,self._peerList)},Skylink.prototype._endOfCandidatesHandler=function(message){var self=this,targetMid=message.mid;self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&(self._peerEndOfCandidatesCounter[targetMid].expectedLen=message.noOfExpectedCandidates||0,self._signalingEndOfCandidates(targetMid))},Skylink.prototype._introduceErrorEventHandler=function(message){var self=this;log.log(["Server",null,message.type,"Introduce failed. Reason: "+message.reason]),self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,message.sendingPeerId,message.receivingPeerId,message.reason)},Skylink.prototype._approachEventHandler=function(message){var self=this;log.log(["Server",null,message.type,"Approaching peer"],message.target),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._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||{}).iceServers||[]),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:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._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:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "enter" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid)}self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0};var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),receiveOnly:self.getPeerInfo().config.receiveOnly,os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg),isNewPeer&&self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._restartHandler=function(message){var self=this,targetMid=message.mid,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "restart" received ->'],message),!self._peerInformations[targetMid])return void log.error([targetMid,"RTCPeerConnection",null,"Peer does not have an existing session. Ignoring restart process."]);if("MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId or publishOnly case ->'],message);if(self._hasMCU&&!self._mcuUseRenegoRestart)return log.warn([targetMid,"RTCPeerConnection",null,"Dropping restart request as MCU does not support re-negotiation. Restart workaround is to re-join Room for Peer."]),void self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!1);if(self._peerInformations[targetMid]=userInfo,self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid].len=0,self._peerPriorityWeight>message.weight){if(log.debug([targetMid,"RTCPeerConnection",null,"Re-negotiating new offer/answer."]),self._peerMessagesStamps[targetMid].hasRestart)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "restart" received.']);self._peerMessagesStamps[targetMid].hasRestart=!0,self._doOffer(targetMid,!0===message.doIceRestart,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start re-negotiation."]);var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===message.doIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,isRestartResend:!0,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._sendChannelMessage(restartMsg)}self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!0===message.doIceRestart)},Skylink.prototype._welcomeHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "welcome" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)}if(self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0,hasWelcome:!1},self._hasMCU||self._peerPriorityWeight>message.weight){if(self._peerMessagesStamps[targetMid].hasWelcome)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "welcome" received.']);log.debug([targetMid,"RTCPeerConnection",null,"Starting negotiation"]),self._peerMessagesStamps[targetMid].hasWelcome=!0,self._doOffer(targetMid,!1,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start negotiation."]);var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg)}};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._offerHandler=function(message){var self=this,targetMid=message.mid,pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for offer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}log.log([targetMid,null,message.type,"Received offer from peer. Session description:"],clone(message));var offer={type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],offer),offer.sdp=self._removeSDPFilteredCandidates(targetMid,offer),offer.sdp=self._setSDPCodec(targetMid,offer),offer.sdp=self._setSDPBitrate(targetMid,offer),offer.sdp=self._setSDPCodecParams(targetMid,offer),offer.sdp=self._removeSDPCodecs(targetMid,offer),offer.sdp=self._removeSDPREMBPackets(targetMid,offer),offer.sdp=self._handleSDPConnectionSettings(targetMid,offer,"remote"),offer.sdp=self._removeSDPUnknownAptRtx(targetMid,offer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "stable" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.resend});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,offer);var onSuccessCbFn=function(){log.debug([targetMid,"RTCSessionDescription",message.type,"Remote description set"]),pc.setOffer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.OFFER,targetMid),self._addIceCandidateFromQueue(targetMid),self._doAnswer(targetMid)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,offer:offer})};pc.setRemoteDescription(new RTCSessionDescription(offer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._candidateHandler=function(message){var targetMid=message.mid;if(!message.candidate&&!message.id)return void log.warn([targetMid,"RTCIceCandidate",null,"Received invalid ICE candidate message ->"],message);var canId="can-"+(new Date).getTime(),candidateType=message.candidate.split(" ")[7]||"",candidate=new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate,sdpMid:message.id});if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Received ICE candidate ->"],candidate),this._peerEndOfCandidatesCounter[targetMid]=this._peerEndOfCandidatesCounter[targetMid]||{},this._peerEndOfCandidatesCounter[targetMid].len=this._peerEndOfCandidatesCounter[targetMid].len||0,this._peerEndOfCandidatesCounter[targetMid].hasSet=!1,this._peerEndOfCandidatesCounter[targetMid].len++,this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.RECEIVED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!this._peerConnections[targetMid]||this._peerConnections[targetMid].signalingState===this.PEER_CONNECTION_STATE.CLOSED)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed.")),void this._signalingEndOfCandidates(targetMid);if(this._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};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],answer),answer.sdp=self._removeSDPFilteredCandidates(targetMid,answer),answer.sdp=self._setSDPCodec(targetMid,answer),answer.sdp=self._setSDPBitrate(targetMid,answer),answer.sdp=self._setSDPCodecParams(targetMid,answer),answer.sdp=self._removeSDPCodecs(targetMid,answer),answer.sdp=self._removeSDPREMBPackets(targetMid,answer),answer.sdp=self._handleSDPConnectionSettings(targetMid,answer,"remote"),answer.sdp=self._removeSDPUnknownAptRtx(targetMid,answer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "have-local-offer" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.restart});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,answer);var onSuccessCbFn=function(){log.debug([targetMid,null,message.type,"Remote description set"]),pc.setAnswer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ANSWER,targetMid),self._addIceCandidateFromQueue(targetMid),self._peerMessagesStamps[targetMid]&&(self._peerMessagesStamps[targetMid].hasRestart=!1),self._dataChannels[targetMid]&&(-1===pc.remoteDescription.sdp.indexOf("m=application")||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,answer:answer})};pc.setRemoteDescription(new RTCSessionDescription(answer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=(agentVer||"").split("."),partsB=(requiredVer||"").split("."),i=0;i0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for sendStream() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream);else{var notInRoomAgainError="Unable to send stream as user is not in the Room.";log.error(notInRoomAgainError,stream),"function"==typeof callback&&callback(new Error(notInRoomAgainError),null)}};if(!("object"==typeof options&&null!==options||AdapterJS&&AdapterJS.WebRTCPlugin&&AdapterJS.WebRTCPlugin.plugin&&["function","object"].indexOf(typeof options)>-1)){var invalidOptionsError="Provided stream settings is invalid";return log.error(invalidOptionsError,options),void("function"==typeof callback&&callback(new Error(invalidOptionsError),null))}if(!self._inRoom){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"===AdapterJS.webrtcDetectedBrowser){var edgeNotSupportError="Edge browser currently does not support renegotiation.";return log.error(edgeNotSupportError,options),void("function"==typeof callback&&callback(new Error(edgeNotSupportError),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0&&(useMediaSource=enableAudioArr)}else enableAudio&&"object"==typeof enableAudio?enableAudioSettings={usedtx:"boolean"==typeof enableAudio.usedtx?enableAudio.usedtx:null,useinbandfec:"boolean"==typeof enableAudio.useinbandfec?enableAudio.useinbandfec:null,stereo:!0===enableAudio.stereo,echoCancellation:!1!==enableAudio.echoCancellation,deviceId:enableAudio.deviceId}:!0===enableAudio?enableAudioSettings=!0===enableAudio&&{usedtx:null,useinbandfec:null,stereo:!1,echoCancellation:!0,deviceId:null}:"function"==typeof enableAudio&&(callback=enableAudio,enableAudio=!1);if(mediaSource&&"string"==typeof mediaSource)checkIfSourceExistsFn(mediaSource)&&(useMediaSource=[mediaSource]);else if(Array.isArray(mediaSource)){for(var mediaSourceArr=[],i=0;i0&&(useMediaSource=mediaSourceArr)}else"function"==typeof mediaSource&&(callback=mediaSource);useMediaSource.indexOf("audio")>-1&&-1===useMediaSource.indexOf("tab")&&(useMediaSource.splice(useMediaSource.indexOf("audio"),1),0===useMediaSource.length&&(useMediaSource=[self.MEDIA_SOURCE.SCREEN])),self._throttle(function(runFn){if(runFn){var settings={settings:{audio:enableAudioSettings,video:{screenshare:!0,exactConstraints:!1}},getUserMediaSettings:{audio:!1,video:{mediaSource:useMediaSource}}},mediaAccessSuccessFn=function(stream){self.off("mediaAccessError",mediaAccessErrorFn),self._inRoom?(self._trigger("incomingStream",self._user.sid,stream,!0,self.getPeerInfo(),!0,stream.id||stream.label),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0),Object.keys(self._peerConnections).length>0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for shareScreen() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream)):"function"==typeof callback&&callback(null,stream)},mediaAccessErrorFn=function(error){self.off("mediaAccessSuccess",mediaAccessSuccessFn),"function"==typeof callback&&callback(error,null)};self.once("mediaAccessSuccess",mediaAccessSuccessFn,function(stream,isScreensharing){return isScreensharing}),self.once("mediaAccessError",mediaAccessErrorFn,function(error,isScreensharing){return isScreensharing});var getUserMediaAudioSettings=!!enableAudioSettings&&{echoCancellation:enableAudioSettings.echoCancellation};try{var hasDefaultAudioTrack=!1;enableAudioSettings&&("firefox"===AdapterJS.webrtcDetectedBrowser?(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio=getUserMediaAudioSettings):useMediaSource.indexOf("audio")>-1&&useMediaSource.indexOf("tab")>-1&&(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio={}));var onSuccessCbFn=function(stream){if(hasDefaultAudioTrack||!enableAudioSettings)return void self._onStreamAccessSuccess(stream,settings,!0,!1);settings.getUserMediaSettings.audio=getUserMediaAudioSettings;var onAudioSuccessCbFn=function(audioStream){try{audioStream.addTrack(stream.getVideoTracks()[0]),self.once("mediaAccessSuccess",function(){self._streams.screenshare.streamClone=stream},function(stream,isScreensharing){return isScreensharing}),self._onStreamAccessSuccess(audioStream,settings,!0,!1)}catch(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)}},onAudioErrorCbFn=function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)};navigator.getUserMedia({audio:getUserMediaAudioSettings},onAudioSuccessCbFn,onAudioErrorCbFn)},onErrorCbFn=function(error){self._onStreamAccessError(error,settings,!0,!1)};if("function"!=typeof(AdapterJS||{}).webRTCReady)return onErrorCbFn(new Error("Failed to call getUserMedia() as AdapterJS is not yet loaded!"));AdapterJS.webRTCReady(function(){navigator.getUserMedia(settings.getUserMediaSettings,onSuccessCbFn,onErrorCbFn)})}catch(error){self._onStreamAccessError(error,settings,!0,!1)}}else if(self._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"!==AdapterJS.webrtcDetectedBrowser&&("boolean"==typeof options.audio.echoCancellation&&(settings.settings.audio.echoCancellation=options.audio.echoCancellation,settings.getUserMediaSettings.audio.echoCancellation=options.audio.echoCancellation),Array.isArray(options.audio.optional)&&(settings.settings.audio.optional=clone(options.audio.optional),settings.getUserMediaSettings.audio.optional=clone(options.audio.optional)),options.audio.deviceId&&"string"==typeof options.audio.deviceId&&"firefox"!==AdapterJS.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,settings.getUserMediaSettings.audio.deviceId=options.useExactConstraints?{exact:options.audio.deviceId}:{ideal:options.audio.deviceId}))),"edge"===AdapterJS.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio=!0)),options.video&&(settings.settings.video={resolution:clone(this.VIDEO_RESOLUTION.VGA),screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video={},"object"==typeof options.video?("boolean"==typeof options.video.mute&&(settings.mutedSettings.shouldVideoMuted=options.video.mute),Array.isArray(options.video.optional)&&(settings.settings.video.optional=clone(options.video.optional),settings.getUserMediaSettings.video.optional=clone(options.video.optional)),options.video.deviceId&&"string"==typeof options.video.deviceId&&"firefox"!==AdapterJS.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,settings.getUserMediaSettings.video.deviceId=options.useExactConstraints?{exact:options.video.deviceId}:{ideal:options.video.deviceId}),options.video.resolution&&"object"==typeof options.video.resolution&&((options.video.resolution.width&&"object"==typeof options.video.resolution.width||"number"==typeof options.video.resolution.width)&&(settings.settings.video.resolution.width=options.video.resolution.width),(options.video.resolution.height&&"object"==typeof options.video.resolution.height||"number"==typeof options.video.resolution.height)&&(settings.settings.video.resolution.height=options.video.resolution.height)),settings.getUserMediaSettings.video.width="object"==typeof settings.settings.video.resolution.width?settings.settings.video.resolution.width:options.useExactConstraints?{exact:settings.settings.video.resolution.width}:{max:settings.settings.video.resolution.width},settings.getUserMediaSettings.video.height="object"==typeof settings.settings.video.resolution.height?settings.settings.video.resolution.height:options.useExactConstraints?{exact:settings.settings.video.resolution.height}:{max:settings.settings.video.resolution.height},(options.video.frameRate&&"object"==typeof options.video.frameRate||"number"==typeof options.video.frameRate&&"plugin"!==AdapterJS.webrtcDetectedType)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}),options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&"plugin"===AdapterJS.webrtcDetectedType&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):settings.getUserMediaSettings.video={width:options.useExactConstraints?{exact:settings.settings.video.resolution.width}:{max:settings.settings.video.resolution.width},height:options.useExactConstraints?{exact:settings.settings.video.resolution.height}:{max:settings.settings.video.resolution.height}},"edge"===AdapterJS.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,streamHasEnded=!1;if(log.log([null,"MediaStream",streamId,"Has access to stream ->"],stream),!isScreenSharing&&self._streams.userMedia?self._stopStreams({userMedia:!0,screenshare:!1}):isScreenSharing&&self._streams.screenshare&&self._stopStreams({userMedia:!1,screenshare:!0}),self._streamsStoppedCbs[streamId]=function(){log.log([null,"MediaStream",streamId,"Stream has ended"]),streamHasEnded=!0,self._trigger("mediaAccessStopped",!!isScreenSharing,!!isAudioFallback,streamId),self._inRoom&&(log.debug([null,"MediaStream",streamId,"Sending Stream ended status to Peers"]),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.STREAM,mid:self._user.sid,rid:self._room.id,cid:self._key,streamId:streamId,settings:settings.settings,status:"ended"}),self._trigger("streamEnded",self._user.sid,self.getPeerInfo(),!0,!!isScreenSharing,streamId),isScreenSharing&&self._streams.screenshare&&self._streams.screenshare.stream&&(self._streams.screenshare.stream.id||self._streams.screenshare.stream.label)===streamId?self._streams.screenshare=null:!isScreenSharing&&self._streams.userMedia&&self._streams.userMedia.stream&&(self._streams.userMedia.stream.id||self._streams.userMedia.stream.label)===streamId&&(self._streams.userMedia=null))},["chrome","opera"].indexOf(AdapterJS.webrtcDetectedBrowser)>-1?(stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},isScreenSharing&&stream.getVideoTracks().length>0&&(stream.getVideoTracks()[0].onended=function(){setTimeout(function(){!streamHasEnded&&self._inRoom&&self.stopScreen()},350)})):"firefox"===AdapterJS.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._audioFallback){log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0);var onAudioSuccessCbFn=function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},onAudioErrorCbFn=function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)};return void navigator.getUserMedia({audio:!0},onAudioSuccessCbFn,onAudioErrorCbFn)}log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this,streamId=self._peerConnections[targetMid]&&self._peerConnections[targetMid].remoteStreamId||stream.id||stream.label;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",streamId,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",streamId,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",streamId,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,streamId),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId];if(pc){var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)&&self._getSDPCommonSupports(peerId,pc.remoteDescription).video,offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPCommonSupports(peerId,pc.remoteDescription).audio;if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){if(!updatedStream||(!pc.localStreamId||updatedStream.id!==pc.localStreamId)){if("edge"!==AdapterJS.webrtcDetectedBrowser||self._useEdgeWebRTC&&window.msRTCPeerConnection?pc.getLocalStreams().forEach(function(stream){pc.removeStream(stream)}):pc.getSenders().forEach(function(sender){pc.removeTrack(sender)}),!offerToReceiveAudio&&!offerToReceiveVideo)return;updatedStream&&("edge"!==AdapterJS.webrtcDetectedBrowser||self._useEdgeWebRTC&&window.msRTCPeerConnection?pc.addStream(updatedStream):updatedStream.getTracks().forEach(function(track){"audio"===track.kind&&!offerToReceiveAudio||"video"===track.kind&&!offerToReceiveVideo||pc.addTrack(track,updatedStream)}),pc.localStreamId=updatedStream.id||updatedStream.label,pc.localStream=updatedStream)}};self._streams.screenshare&&self._streams.screenshare.stream?(log.debug([peerId,"MediaStream",null,"Sending screen"],self._streams.screenshare.stream),updateStreamFn(self._streams.screenshare.stream)):self._streams.userMedia&&self._streams.userMedia.stream?(log.debug([peerId,"MediaStream",null,"Sending stream"],self._streams.userMedia.stream),updateStreamFn(self._streams.userMedia.stream)):(log.warn([peerId,"MediaStream",null,"No media to send. Will be only receiving"]),updateStreamFn(null))}else log.warn([peerId,"MediaStream",null,"Not adding any stream as signalingState is closed"])}else log.warn([peerId,"MediaStream",self._mediaStream,"Not adding stream as peerconnection object does not exists"])}catch(error){(error.message||"").indexOf("already added")>-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){if(self._streamsSession[peerId][streamId]){var peerInfo=clone(self.getPeerInfo(peerId));peerInfo.settings.audio=clone(self._streamsSession[peerId][streamId].audio),peerInfo.settings.video=clone(self._streamsSession[peerId][streamId].video);var hasScreenshare=peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&!!peerInfo.settings.video.screenshare;self._streamsSession[peerId][streamId]=!1,self._trigger("streamEnded",peerId,peerInfo,!1,hasScreenshare,streamId)}};if(checkStreamId)renderEndedFn(checkStreamId);else if(self._peerConnections[peerId])for(var streamId in self._streamsSession[peerId])self._streamsSession[peerId].hasOwnProperty(streamId)&&self._streamsSession[peerId][streamId]&&renderEndedFn(streamId)},Skylink.prototype._setSDPCodecParams=function(targetMid,sessionDescription){var self=this,parseFn=function(type,codecName,samplingRate,settings){var mLine=sessionDescription.sdp.match(new RegExp("m="+type+" .*\r\n","gi"));if(Array.isArray(mLine)&&mLine.length>0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-1===cLineIndex?void log.error([targetMid,"RTCSessionDesription",sessionDescription.type,'Failed setting "'+type+'" bandwidth as c-line is missing.']):(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Limiting maximum sending "'+type+'" bandwidth ->'],bw),void sdpLines.splice(cLineIndex+1,0,"firefox"===window.webrtcDetectedBrowser?"b=TIAS:"+(1e3*bw*(window.webrtcDetectedVersion>52&&window.webrtcDetectedVersion<55?1e3:1)).toFixed(0):"b=AS:"+bw)):void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not limiting "'+type+'" bandwidth'])},bASAudioBw=this._streamsBandwidthSettings.bAS.audio,bASVideoBw=this._streamsBandwidthSettings.bAS.video,bASDataBw=this._streamsBandwidthSettings.bAS.data,googleXMinBw=this._streamsBandwidthSettings.googleX.min,googleXMaxBw=this._streamsBandwidthSettings.googleX.max;if(this._peerCustomConfigs[targetMid]&&(this._peerCustomConfigs[targetMid].bandwidth&&"object"==typeof this._peerCustomConfigs[targetMid].bandwidth&&("number"==typeof this._peerCustomConfigs[targetMid].bandwidth.audio&&(bASAudioBw=this._peerCustomConfigs[targetMid].bandwidth.audio),"number"==typeof this._peerCustomConfigs[targetMid].bandwidth.video&&(bASVideoBw=this._peerCustomConfigs[targetMid].bandwidth.video),"number"==typeof this._peerCustomConfigs[targetMid].bandwidth.data&&(bASDataBw=this._peerCustomConfigs[targetMid].bandwidth.data)),this._peerCustomConfigs[targetMid].googleXBandwidth&&"object"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth&&("number"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth.min&&(googleXMinBw=this._peerCustomConfigs[targetMid].googleXBandwidth.min),"number"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth.max&&(googleXMaxBw=this._peerCustomConfigs[targetMid].googleXBandwidth.max))),parseFn("audio",bASAudioBw),parseFn("video",bASVideoBw),parseFn("data",bASDataBw),"number"==typeof googleXMinBw||"number"==typeof googleXMaxBw){for(var codec=null,codecRtpMapLineIndex=-1,codecFmtpLineIndex=-1,j=0;j-1){var xGoogleParams="";"number"==typeof googleXMinBw&&(xGoogleParams+="x-google-min-bitrate="+googleXMinBw+";"),"number"==typeof googleXMaxBw&&(xGoogleParams+="x-google-max-bitrate="+googleXMaxBw+";"),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Limiting x-google-bitrate ->"],xGoogleParams),codecFmtpLineIndex>-1?sdpLines[codecFmtpLineIndex]+=(sdpLines[codecFmtpLineIndex].split(" ")[1]?";":"")+xGoogleParams:sdpLines.splice(codecRtpMapLineIndex+1,0,"a=fmtp:"+codec+" "+xGoogleParams)}}return sdpLines.join("\r\n")},Skylink.prototype._setSDPCodec=function(targetMid,sessionDescription,overrideSettings){var self=this,parseFn=function(type,codecSettings){var codec="object"==typeof codecSettings?codecSettings.codec:codecSettings,samplingRate="object"==typeof codecSettings?codecSettings.samplingRate:null,channels="object"==typeof codecSettings?codecSettings.channels:null;if(codec===self["audio"===type?"AUDIO_CODEC":"VIDEO_CODEC"].AUTO)return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not preferring any codec for "'+type+'" streaming. Using browser selection.']);var mLine=sessionDescription.sdp.match(new RegExp("m="+type+" .*\r\n","gi"));if(!(Array.isArray(mLine)&&mLine.length>0))return void log.error([targetMid,"RTCSessionDesription",sessionDescription.type,'Not preferring any codec for "'+type+'" streaming as m= line is not found.']);var setLineFn=function(codecsList,isSROk,isChnlsOk){if(Array.isArray(codecsList)&&codecsList.length>0){isSROk||(samplingRate=null),isChnlsOk||(channels=null),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Preferring "'+codec+'" (samplingRate: '+(samplingRate||"n/a")+", channels: "+(channels||"n/a")+') for "'+type+'" streaming.']);var line=mLine[0],lineParts=line.replace("\r\n","").split(" ");line=lineParts[0]+" "+lineParts[1]+" "+lineParts[2]+" ",lineParts.splice(0,3);for(var i=0;i0?(lineParts.splice(j,1),j--):sessionDescription.sdp.match(new RegExp("a=rtpmap:"+lineParts[j]+" "+codec+"/.*\r\n","gi"))&&(line+=lineParts[j]+" ",lineParts.splice(j,1),j--);return line+=lineParts.join(" ")+"\r\n",sessionDescription.sdp=sessionDescription.sdp.replace(mLine[0],line),!0}};if(samplingRate){if("audio"===type&&channels&&setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/"+samplingRate+(1===channels?"[/1]*":"/"+channels)+"\r\n","gi")),!0,!0))return;if(setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/"+samplingRate+"[/]*.*\r\n","gi")),!0))return}"audio"===type&&channels&&setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/.*/"+channels+"\r\n","gi")),!1,!0)||setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/.*\r\n","gi")))};return parseFn("audio",overrideSettings?overrideSettings.audio:self._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._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var mediaLines=(sessionDescription.sdp.split("\r\n"),sessionDescription.sdp.split("m=")),formatRtx=function(str){return(str.match(/a=rtpmap:.*\ rtx\/.*\r\n/gi)||[]).forEach(function(line){var payload=(line.split("a=rtpmap:")[1]||"").split(" ")[0]||"",fmtpLine=(str.match(new RegExp("a=fmtp:"+payload+" .*\r\n","gi"))||[])[0];if(!fmtpLine)return void(str=str.replace(new RegExp(line,"g"),""));var codecPayload=(fmtpLine.split(" apt=")[1]||"").replace(/\r\n/gi,"");str.match(new RegExp("a=rtpmap:"+codecPayload+" .*\r\n","gi"))||(str=str.replace(new RegExp(line,"g"),""),str=str.replace(new RegExp(fmtpLine,"g"),""))}),str},formatFmtpRtcpFb=function(str){return(str.match(/a=(fmtp|rtcp-fb):.*\ rtx\/.*\r\n/gi)||[]).forEach(function(line){var payload=(line.split("a="+(line.indexOf("rtcp")>0?"rtcp-fb":"fmtp"))[1]||"").split(" ")[0]||"";str.match(new RegExp("a=rtpmap:"+payload+" .*\r\n","gi"))||(str=str.replace(new RegExp(line,"g"),""))}),str},m=0;m0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._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){var codecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index&&0===mediaItem.indexOf(type+" ")){var codecs=(mediaItem.split("\r\n")[0]||"").split(" ");codecs.splice(0,3);for(var i=0;i-1)){codecInfo.name=parts[0],codecInfo.clockRate=parseInt(parts[1],10)||0,codecInfo.channels=parseInt(parts[2]||"1",10)||1,codecInfo.payloadType=parseInt(codecs[i],10),codecInfo.params="";(mediaItem.match(new RegExp("a=fmtp:"+codecs[i]+".*\r\n","gi"))||[]).forEach(function(paramItem){codecInfo.params+=paramItem.replace(new RegExp("a=fmtp:"+codecs[i],"gi"),"").replace(/\ /g,"").replace(/\r\n/g,"")});break}}}}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,'Parsing session description "'+type+'" codecs ->'],codecInfo),codecInfo):codecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._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);if(self._currentCodecSupport={audio:{},video:{}},"AppleWebKit"===AdapterJS.webrtcDetectedType)return self._currentCodecSupport.audio={opus:["48000/2"]},self._currentCodecSupport.video={h264:["48000"]},callback(null);try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints="plugin"!==AdapterJS.webrtcDetectedType?{offerToReceiveAudio:!0,offerToReceiveVideo:!0}:{mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}};try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){self._currentCodecSupport=self._getSDPCodecsSupport(null,offer),callback(null)},function(error){callback(error)},offerConstraints)}}catch(error){callback(error)}},Skylink.prototype._handleSDPConnectionSettings=function(targetMid,sessionDescription,direction){var self=this;if(!self._sdpSessions[targetMid])return sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;"remote"!==direction||self.getPeerInfo(targetMid).config.enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",mediaType=(self._peerInformations[targetMid],""),bundleLineIndex=-1,bundleLineMids=[],mLineIndex=-1,settings=clone(self._sdpSettings);if("MCU"===targetMid&&(settings.connection.audio=!0,settings.connection.video=!0,settings.connection.data=!0),self._hasMCU){var peerStreamSettings=clone(self.getPeerInfo(targetMid)).settings||{};settings.direction.audio.receive="MCU"!==targetMid&&!!peerStreamSettings.audio,settings.direction.audio.send="MCU"===targetMid,settings.direction.video.receive="MCU"!==targetMid&&!!peerStreamSettings.video,settings.direction.video.send="MCU"===targetMid}if("remote"===direction){var offerCodecs=self._getSDPCommonSupports(targetMid,sessionDescription);offerCodecs.audio||(settings.connection.audio=!1),offerCodecs.video||(settings.connection.video=!1)}self._sdpSessions[targetMid][direction].mLines=[],self._sdpSessions[targetMid][direction].bundleLine="",self._sdpSessions[targetMid][direction].connection={audio:null,video:null,data:null};for(var i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");else if(mediaType&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){if(-1===["audio","video"].indexOf(mediaType)){self._sdpSessions[targetMid][direction].connection.data=sdpLines[i];continue}if("local"===direction)settings.direction[mediaType].send&&!settings.direction[mediaType].receive?sdpLines[i]=sdpLines[i].indexOf("send")>-1?"a=sendonly":"a=inactive":!settings.direction[mediaType].send&&settings.direction[mediaType].receive?sdpLines[i]=sdpLines[i].indexOf("recv")>-1?"a=recvonly":"a=inactive":settings.direction[mediaType].send||settings.direction[mediaType].receive||(sdpLines[i]="a=inactive"),self._hasMCU||"firefox"===window.webrtcDetectedBrowser||"firefox"!==peerAgent||sessionDescription.type!==self.HANDSHAKE_PROGRESS.OFFER||"a=recvonly"!==sdpLines[i]||(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Overriding any original settings to receive only to send and receive to resolve chrome BUNDLE errors."]),sdpLines[i]="a=sendrecv",settings.direction[mediaType].send=!0,settings.direction[mediaType].receive=!0);else if(sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER){var localOfferRes=self._sdpSessions[targetMid].local.connection[mediaType];"a=sendonly"===localOfferRes?sdpLines[i]=-1===["a=inactive","a=recvonly"].indexOf(sdpLines[i])?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=-1===["a=inactive","a=sendonly"].indexOf(sdpLines[i])?"a=recvonly"===sdpLines[i]?"a=inactive":"a=sendonly":sdpLines[i]:"a=inactive"===localOfferRes&&(sdpLines[i]="a=inactive")}self._sdpSessions[targetMid][direction].connection[mediaType]=sdpLines[i]}}else sdpLines.splice(i,1),i--;(sdpLines[i]||"").replace(/\n|\r|\s|\ /gi,"")||(sdpLines.splice(i,1),i--)}return bundleLineIndex>-1&&(self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE?sdpLines[bundleLineIndex]="a=group:BUNDLE "+bundleLineMids.join(" "):self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.NONE&&sdpLines.splice(bundleLineIndex,1)),"edge"!==window.webrtcDetectedBrowser&&(sdpLines[sdpLines.length-1].replace(/\n|\r|\s/gi,"")?sdpLines.push(""):sdpLines[sdpLines.length-1]=""),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Handling connection lines and direction ->"],settings),sdpLines.join("\r\n")},Skylink.prototype._getSDPFingerprint=function(targetMid,sessionDescription,beSilentOnLogs){var fingerprint={fingerprint:null,fingerprintAlgorithm:null,derBase64:null};if(!sessionDescription||!sessionDescription.sdp)return fingerprint;for(var sdpLines=sessionDescription.sdp.split("\r\n"),i=0;i"],fingerprint),fingerprint},Skylink.prototype._renderSDPOutput=function(targetMid,sessionDescription){var self=this,localStream=null,localStreamId=null;if(sessionDescription&&sessionDescription.sdp){if(!self._peerConnections[targetMid])return sessionDescription.sdp;self._peerConnections[targetMid].localStream&&(localStream=self._peerConnections[targetMid].localStream,localStreamId=self._peerConnections[targetMid].localStreamId||self._peerConnections[targetMid].localStream.id);var sdpLines=(self._enableIceTrickle?sessionDescription.sdp:sessionDescription.sdp.replace(/a=end-of-candidates\r\n/g,"")).split("\r\n");self._peerInformations[targetMid];if(localStream)for(var mediaType="",i=0;i0?ssrcParts=sdpLines[i].split(" msid:"):sdpLines[i].indexOf(" mslabel:")>0&&(ssrcParts=sdpLines[i].split(" mslabel:")),ssrcParts){var ssrcMsidParts=(ssrcParts[1]||"").split(" ");ssrcMsidParts[0]=localStreamId,ssrcParts[1]=ssrcMsidParts.join(" "),sdpLines[i].indexOf(" msid:")>0?sdpLines[i]=ssrcParts.join(" msid:"):sdpLines[i].indexOf(" mslabel:")>0&&(sdpLines[i]=ssrcParts.join(" mslabel:"))}}if(!self._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var e=0;e"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),log.info([targetMid,"RTCSessionDescription",sessionDescription.type,"Formatted output ->"],sdpLines.join("\r\n")),sdpLines.join("\r\n")}},Skylink.prototype._parseSDPMediaStreamIDs=function(targetMid,sessionDescription){if(this._peerConnections[targetMid]){if(!sessionDescription||!sessionDescription.sdp)return void(this._peerConnections[targetMid].remoteStreamId=null);for(var sdpLines=sessionDescription.sdp.split("\r\n"),currentStreamId=null,i=0;i0){currentStreamId=(sdpLines[i].split(" msid:")[1]||"").split(" ")[0];break}}currentStreamId?currentStreamId!==this._peerConnections[targetMid].remoteStreamId?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"New remote stream is sent ->"],currentStreamId),this._peerConnections[targetMid].remoteStreamId=currentStreamId):log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Same remote stream is sent ->"],currentStreamId):(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"No remote stream is sent."]),this._peerConnections[targetMid].remoteStreamId=null)}},Skylink.prototype._getSDPICECandidates=function(targetMid,sessionDescription,beSilentOnLogs){var candidates={host:[],srflx:[],relay:[]};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index){var sdpMid=((mediaItem.match(/a=mid:.*\r\n/gi)||[])[0]||"").replace(/a=mid:/gi,"").replace(/\r\n/,""),sdpMLineIndex=index-1;(mediaItem.match(/a=candidate:.*\r\n/gi)||[]).forEach(function(item){var canType=(item.split(" ")[7]||"host").replace(/\r\n/g,"");candidates[canType]=candidates[canType]||[],candidates[canType].push(new RTCIceCandidate({sdpMid:sdpMid,sdpMLineIndex:sdpMLineIndex,candidate:(item.split("a=")[1]||"").replace(/\r\n/g,"")}))})}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,"Parsing session description ICE candidates ->"],candidates),candidates):candidates},Skylink.prototype._getSDPMediaSSRC=function(targetMid,sessionDescription,beSilentOnLogs){var ssrcs={audio:0,video:0};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index){var mediaType=mediaItem.split(" ")[0]||"",ssrcLine=(mediaItem.match(/a=ssrc:.*\r\n/)||[])[0];"number"==typeof ssrcs[mediaType]&&ssrcLine&&(ssrcs[mediaType]=parseInt((ssrcLine.split("a=ssrc:")[1]||"").split(" ")[0],10)||0)}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,"Parsing session description media SSRCs ->"],ssrcs),ssrcs):ssrcs},Skylink.prototype._getSDPCodecsSupport=function(targetMid,sessionDescription){var codecs={audio:{},video:{}};if(!sessionDescription||!sessionDescription.sdp)return codecs;for(var sdpLines=sessionDescription.sdp.split("\r\n"),mediaType="",i=0;i-1)continue;codecs[mediaType][codec]=codecs[mediaType][codec]||[],-1===codecs[mediaType][codec].indexOf(info)&&codecs[mediaType][codec].push(info)}}else if(mediaType=(sdpLines[i].split("m=")[1]||"").split(" ")[0],-1===["audio","video"].indexOf(mediaType))break;return log.info([targetMid||null,"RTCSessionDescription",sessionDescription.type,"Parsed codecs support ->"],codecs),codecs},Skylink.prototype._getSDPCommonSupports=function(targetMid,sessionDescription){var self=this,offer={audio:!1,video:!1};if(!targetMid||!sessionDescription||!sessionDescription.sdp){if(offer.video=!(!self._currentCodecSupport.video.h264&&!self._currentCodecSupport.video.vp8),offer.audio=!!self._currentCodecSupport.audio.opus,targetMid){var peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"";AdapterJS.webrtcDetectedBrowser===peerAgent&&(offer.video=Object.keys(self._currentCodecSupport.video).length>0,offer.audio=Object.keys(self._currentCodecSupport.audio).length>0)}return offer}var remoteCodecs=self._getSDPCodecsSupport(targetMid,sessionDescription),localCodecs=self._currentCodecSupport;for(var ac in localCodecs.audio)if(localCodecs.audio.hasOwnProperty(ac)&&localCodecs.audio[ac]&&remoteCodecs.audio[ac]){offer.audio=!0;break}for(var vc in localCodecs.video)if(localCodecs.video.hasOwnProperty(vc)&&localCodecs.video[vc]&&remoteCodecs.video[vc]){offer.video=!0;break}return offer},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this);
\ No newline at end of file
diff --git a/publish/skylink.debug.js b/publish/skylink.debug.js
index 7e54fe349..5d7f3cdfc 100644
--- a/publish/skylink.debug.js
+++ b/publish/skylink.debug.js
@@ -1,4 +1,4 @@
-/*! skylinkjs - v0.6.25 - Fri Sep 08 2017 17:34:14 GMT+0800 (+08) */
+/*! skylinkjs - v0.6.26 - Fri Sep 15 2017 15:25:49 GMT+0800 (+08) */
(function(globals) {
@@ -259,12 +259,12 @@ function Skylink() {
* Stores the flag that indicates if public STUN ICE servers should be used when constructing Peer connection.
* @attribute _usePublicSTUN
* @type Boolean
- * @default true
+ * @default false
* @private
* @for Skylink
* @since 0.6.1
*/
- this._usePublicSTUN = true;
+ this._usePublicSTUN = false;
/**
* Stores the global number of Peer connection retries that would increase the wait-for-response timeout
@@ -623,7 +623,17 @@ function Skylink() {
* @for Skylink
* @since 0.5.4
*/
- this._socketTimeout = 20000;
+ this._socketTimeout = 7000;
+
+ /**
+ * Stores the response timeout when establishing connection to the API (auth) server.
+ * @attribute _apiTimeout
+ * @type Number
+ * @private
+ * @for Skylink
+ * @since 0.6.26
+ */
+ this._apiTimeout = 4000;
/**
* Stores the flag that indicates if XDomainRequest is used for IE 8/9.
@@ -661,12 +671,12 @@ function Skylink() {
* HTTPS connections are enforced if App is accessing from HTTPS domains.
* @attribute _forceSSL
* @type Boolean
- * @default false
+ * @default true
* @private
* @for Skylink
* @since 0.5.4
*/
- this._forceSSL = false;
+ this._forceSSL = true;
/**
* Stores the flag if TURNS connections should be enforced when connecting to
@@ -1176,6 +1186,19 @@ function Skylink() {
* @since 0.6.19
*/
this._useEdgeWebRTC = false;
+
+ /**
+ * Stores the flag to temporarily halt joinRoom() from processing.
+ * @attribute _joinRoomManager
+ * @type Boolean
+ * @private
+ * @for Skylink
+ * @since 0.6.19
+ */
+ this._joinRoomManager = {
+ timestamp: 0,
+ socketsFn: []
+ };
}
Skylink.prototype.DATA_CHANNEL_STATE = {
@@ -5176,214 +5199,119 @@ Skylink.prototype.TURN_TRANSPORT = {
* @for Skylink
* @since 0.5.4
*/
-Skylink.prototype._setIceServers = function(givenConfig) {
+Skylink.prototype._setIceServers = function(passedIceServers) {
var self = this;
- var givenIceServers = clone(givenConfig.iceServers);
- var iceServersList = {};
- var newIceServers = [];
- // TURN SSL config
- var useTURNSSLProtocol = false;
- var useTURNSSLPort = false;
-
-
-
- if (self._forceTURNSSL) {
- if (AdapterJS.webrtcDetectedBrowser === 'firefox' && AdapterJS.webrtcDetectedVersion < 53) {
- useTURNSSLPort = true;
- } else {
- useTURNSSLProtocol = true;
- }
- }
-
- log.log('TURN server connections SSL configuration', {
- useTURNSSLProtocol: useTURNSSLProtocol,
- useTURNSSLPort: useTURNSSLPort
- });
-
- var pushIceServer = function (username, credential, url, index) {
- if (!iceServersList[username]) {
- iceServersList[username] = {};
- }
-
- if (!iceServersList[username][credential]) {
- iceServersList[username][credential] = [];
- }
-
- if (iceServersList[username][credential].indexOf(url) === -1) {
- if (typeof index === 'number') {
- iceServersList[username][credential].splice(index, 0, url);
+ var iceServerName = null;
+ var iceServerProtocol = 'stun';
+ var iceServerPorts = {
+ udp: [3478, 19302, 19303, 19304],
+ tcp: [80, 443],
+ both: [19305, 19306, 19307, 19308]
+ };
+ var iceServers = [
+ // Public
+ { urls: [] },
+ // Private
+ { urls: [] }
+ ];
+
+ // Note: Provide only 1 single TURN! turn:xxxx.io for custom TURN servers. Ignores custom ports.
+ passedIceServers.forEach(function (server) {
+ if (server.url.indexOf('stun:') === 0) {
+ if (server.url.indexOf('temasys') > 0) {
+ // server[?transport=xxx]
+ iceServerName = (server.url.split(':')[1] || '').split('?')[0] || null;
} else {
- iceServersList[username][credential].push(url);
+ iceServers[0].urls.push(server.url);
}
- }
- };
-
- var i, serverItem;
- for (i = 0; i < givenIceServers.length; i++) {
- var server = givenIceServers[i];
+ } else if (server.url.indexOf('turn:') === 0 && server.url.indexOf('@') > 0 && server.credential &&
+ !(iceServers[1].username || iceServers[1].credential)) {
+ var parts = server.url.split(':');
+ var urlParts = (parts[1] || '').split('@');
- if (typeof server.url !== 'string') {
- log.warn('Ignoring ICE server provided at index ' + i, clone(server));
- continue;
+ // server[?transport=xxx]
+ iceServerName = (urlParts[1] || '').split('?')[0];
+ iceServers[1].username = urlParts[0];
+ iceServers[1].credential = server.credential;
+ iceServerProtocol = 'turn';
}
+ });
- if (server.url.indexOf('stun') === 0) {
- if (!self._enableSTUN) {
- log.warn('Ignoring STUN server provided at index ' + i, clone(server));
- continue;
- }
-
- if (!self._usePublicSTUN && server.url.indexOf('temasys') === -1) {
- log.warn('Ignoring public STUN server provided at index ' + i, clone(server));
- continue;
- }
+ if (self._iceServer) {
+ iceServers = [{
+ urls: self._iceServer.urls,
+ username: iceServers[1].username,
+ credential: iceServers[1].credential
+ }];
- } else if (server.url.indexOf('turn') === 0) {
- if (!self._enableTURN) {
- log.warn('Ignoring TURN server provided at index ' + i, clone(server));
- continue;
- }
+ } else {
+ iceServerName = iceServerName || 'turn.temasys.io';
- if (server.url.indexOf(':443') === -1 && useTURNSSLPort) {
- log.log('Ignoring TURN Server (non-SSL port) provided at index ' + i, clone(server));
- continue;
- }
+ if (AdapterJS.webrtcDetectedBrowser === 'edge') {
+ iceServerPorts.udp = [3478];
+ iceServerPorts.tcp = [];
+ iceServerPorts.both = [];
+ iceServerProtocol = 'turn';
+
+ } else if (self._forceTURNSSL) {
+ if (AdapterJS.webrtcDetectedBrowser === 'firefox' && AdapterJS.webrtcDetectedVersion < 53) {
+ iceServerPorts.udp = [];
+ iceServerPorts.tcp = [443];
+ iceServerPorts.both = [];
+ iceServerProtocol = 'turn';
- if (useTURNSSLProtocol) {
- var parts = server.url.split(':');
- parts[0] = 'turns';
- server.url = parts.join(':');
+ } else {
+ iceServerPorts.udp = [];
+ iceServerProtocol = 'turns';
}
- }
- // parse "@" settings
- if (server.url.indexOf('@') > 0) {
- var protocolParts = server.url.split(':');
- var urlParts = protocolParts[1].split('@');
- server.username = urlParts[0];
- server.url = protocolParts[0] + ':' + urlParts[1];
-
- // add the ICE server port
- // Edge uses 3478 with ?transport=udp for now
- if (AdapterJS.webrtcDetectedBrowser === 'edge') {
- server.url += ':3478';
- } else if (protocolParts[2]) {
- server.url += ':' + protocolParts[2];
- }
+ // Limit the number of ports..
+ } else if (AdapterJS.webrtcDetectedBrowser === 'firefox') {
+ iceServerPorts.udp = [3478];
+ iceServerPorts.tcp = [443, 80];
}
- var username = typeof server.username === 'string' ? server.username : 'none';
- var credential = typeof server.credential === 'string' ? server.credential : 'none';
-
- if (server.url.indexOf('turn') === 0) {
- if (self._TURNTransport === self.TURN_TRANSPORT.ANY) {
- pushIceServer(username, credential, server.url);
-
- } else {
- var rawUrl = server.url;
+ if (self._TURNTransport === self.TURN_TRANSPORT.UDP && !self._forceTURNSSL) {
+ iceServerPorts.udp = iceServerPorts.udp.concat(iceServerPorts.both);
+ iceServerPorts.tcp = [];
+ iceServerPorts.both = [];
- if (rawUrl.indexOf('?transport=') > 0) {
- rawUrl = rawUrl.split('?transport=')[0];
- }
+ } else if (self._TURNTransport === self.TURN_TRANSPORT.TCP) {
+ iceServerPorts.tcp = iceServerPorts.tcp.concat(iceServerPorts.both);
+ iceServerPorts.udp = [];
+ iceServerPorts.both = [];
- if (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) {
- pushIceServer(username, credential, rawUrl + '?transport=tcp');
- pushIceServer(username, credential, rawUrl + '?transport=udp');
- } else {
- log.warn('Invalid TURN transport option "' + self._TURNTransport +
- '". Ignoring TURN server at index' + i, clone(server));
- continue;
- }
- }
- } else {
- pushIceServer(username, credential, server.url);
+ } else if (self._TURNTransport === self.TURN_TRANSPORT.NONE) {
+ iceServerPorts.tcp = [];
+ iceServerPorts.udp = [];
}
- }
- // add mozilla STUN for firefox
- if (self._enableSTUN && self._usePublicSTUN && AdapterJS.webrtcDetectedBrowser === 'firefox') {
- pushIceServer('none', 'none', 'stun:stun.services.mozilla.com', 0);
- }
+ if (iceServerProtocol === 'stun') {
+ iceServerPorts.tcp = [];
+ }
- var hasUrlsSupport =
- (AdapterJS.webrtcDetectedBrowser === 'chrome' && AdapterJS.webrtcDetectedVersion > 34) ||
- (AdapterJS.webrtcDetectedBrowser === 'firefox' && AdapterJS.webrtcDetectedVersion > 38) ||
- (AdapterJS.webrtcDetectedBrowser === 'opera' && AdapterJS.webrtcDetectedVersion > 31) ||
- (['plugin', 'AppleWebKit'].indexOf(AdapterJS.webrtcDetectedType) > -1) ||
- (['bowser', 'edge'].indexOf(AdapterJS.webrtcDetectedBrowser) > -1);
+ iceServerPorts.tcp.forEach(function (tcpPort) {
+ iceServers[1].urls.push(iceServerProtocol + ':' + iceServerName + ':' + tcpPort + '?transport=tcp');
+ });
- 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 (serverUsername !== 'none') {
- urlsItem.username = serverUsername;
- }
- if (serverCred !== 'none') {
- urlsItem.credential = serverCred;
- }
+ iceServerPorts.udp.forEach(function (udpPort) {
+ iceServers[1].urls.push(iceServerProtocol + ':' + iceServerName + ':' + udpPort + '?transport=udp');
+ });
- // Edge uses 1 url only for now
- if (AdapterJS.webrtcDetectedBrowser === 'edge') {
- if (urlsItem.username && urlsItem.credential) {
- urlsItem.urls = [urlsItem.urls[0]];
- newIceServers.push(urlsItem);
- break;
- }
- } else {
- newIceServers.push(urlsItem);
- }
- } else {
- for (var j = 0; j < iceServersList[serverUsername][serverCred].length; j++) {
- var urlItem = {
- url: iceServersList[serverUsername][serverCred][j]
- };
- if (serverUsername !== 'none') {
- urlItem.username = serverUsername;
- }
- if (serverCred !== 'none') {
- urlItem.credential = serverCred;
- }
- newIceServers.push(urlItem);
- }
- }
- }
- }
- }
+ iceServerPorts.both.forEach(function (bothPort) {
+ iceServers[1].urls.push(iceServerProtocol + ':' + iceServerName + ':' + bothPort);
+ });
}
- if (self._iceServer) {
- var nUsername = null, nCredential = null;
- for (i = 0; i < newIceServers.length; i++) {
- if (newIceServers[i].username) {
- nUsername = newIceServers[i].username;
- }
- if (newIceServers[i].credential) {
- nCredential = newIceServers[i].credential;
- }
- }
- newIceServers = [{
- urls: self._iceServer.urls,
- username: nUsername,
- credential: nCredential
- }];
+ if (!self._usePublicSTUN) {
+ iceServers.splice(0, 1);
}
- log.log('Output iceServers configuration:', newIceServers);
+ log.log('Output iceServers configuration:', iceServers);
return {
- iceServers: newIceServers
+ iceServers: iceServers
};
};
Skylink.prototype.PEER_CONNECTION_STATE = {
@@ -9316,6 +9244,8 @@ Skylink.prototype.joinRoom = function(room, options, callback) {
var selectedRoom = self._defaultRoom;
var previousRoom = self._selectedRoom;
var mediaOptions = {};
+ var timestamp = (new Date()).getTime() + Math.floor(Math.random() * 10000);
+ self._joinRoomManager.timestamp = timestamp;
if (room && typeof room === 'string') {
selectedRoom = room;
@@ -9344,16 +9274,30 @@ Skylink.prototype.joinRoom = function(room, options, callback) {
};
var joinRoomFn = function () {
+ // If room has been stopped but does not matches timestamp skip.
+ if (self._joinRoomManager.timestamp !== timestamp) {
+ resolveAsErrorFn('joinRoom() process did not complete', selectedRoom);
+ return;
+ }
+
self._initSelectedRoom(selectedRoom, function(initError, initSuccess) {
if (initError) {
resolveAsErrorFn(initError.error, self._selectedRoom, self._readyState);
return;
+ // If details has been initialised but does not matches timestamp skip.
+ } else if (self._joinRoomManager.timestamp !== timestamp) {
+ resolveAsErrorFn('joinRoom() process did not complete', selectedRoom);
+ return;
}
- self._waitForOpenChannel(mediaOptions, function (error, success) {
+ self._waitForOpenChannel(mediaOptions || {}, timestamp, function (error, success) {
if (error) {
resolveAsErrorFn(error, self._selectedRoom, self._readyState);
return;
+ // If socket and stream has been retrieved but socket connection does not matches timestamp skip.
+ } else if (self._joinRoomManager.timestamp !== timestamp) {
+ resolveAsErrorFn('joinRoom() process did not complete', selectedRoom);
+ return;
}
if (AdapterJS.webrtcDetectedType === 'AppleWebKit') {
@@ -9438,14 +9382,26 @@ Skylink.prototype.joinRoom = function(room, options, callback) {
return;
}
- if (self._inRoom) {
- var stopStream = mediaOptions.audio === false && mediaOptions.video === false;
+ self._joinRoomManager.socketsFn.forEach(function (fnItem) {
+ fnItem(timestamp);
+ });
- self.leaveRoom(stopStream, function (lRError, lRSuccess) {
+ self._joinRoomManager.socketsFn = [];
+
+ var stopStream = mediaOptions.audio === false && mediaOptions.video === false;
+
+ if (self._inRoom) {
+ self.leaveRoom({
+ userMedia: stopStream
+ }, function (lRError, lRSuccess) {
log.debug([null, 'Room', previousRoom, 'Leave Room callback result ->'], [lRError, lRSuccess]);
joinRoomFn();
});
} else {
+ if (stopStream) {
+ self.stopStream();
+ }
+
joinRoomFn();
}
};
@@ -9641,7 +9597,7 @@ Skylink.prototype.unlockRoom = function() {
* @for Skylink
* @since 0.5.5
*/
-Skylink.prototype._waitForOpenChannel = function(mediaOptions, callback) {
+Skylink.prototype._waitForOpenChannel = function(mediaOptions, joinRoomTimestamp, callback) {
var self = this;
// when reopening room, it should stay as 0
self._socketCurrentReconnectionAttempt = 0;
@@ -9858,7 +9814,7 @@ Skylink.prototype._waitForOpenChannel = function(mediaOptions, callback) {
self.once('socketError', onChannelError, function (errorState) {
return errorState === self.SOCKET_ERROR.RECONNECTION_ABORTED;
});
- self._openChannel();
+ self._openChannel(joinRoomTimestamp);
} else {
onChannelOpen();
}
@@ -9867,7 +9823,7 @@ Skylink.prototype._waitForOpenChannel = function(mediaOptions, callback) {
});
};
-Skylink.prototype.VERSION = '0.6.25';
+Skylink.prototype.VERSION = '0.6.26';
/**
* The list of init() method ready states.
@@ -9947,6 +9903,8 @@ Skylink.prototype.READY_STATE_CHANGE = {
* roomServer configuration, contact our support portal.
* @param {Number} XML_HTTP_REQUEST_ERROR Value -1
* The value of the failure code when requesting to Auth server has timed out.
+ * @param {Number} XML_HTTP_NO_REPONSE_ERROR Value -2
+ * The value of the failure code when response from Auth server is empty or timed out.
* @param {Number} NO_SOCKET_IO Value 1
* The value of the failure code when dependency Socket.IO client is not loaded.
* To resolve this, ensure that the Socket.IO client dependency is loaded before the Skylink SDK.
@@ -9990,6 +9948,7 @@ Skylink.prototype.READY_STATE_CHANGE_ERROR = {
API_RETRIEVAL_FAILED: 4021,
API_WRONG_ACCESS_DOMAIN: 5005,
XML_HTTP_REQUEST_ERROR: -1,
+ XML_HTTP_NO_REPONSE_ERROR: -2,
NO_SOCKET_IO: 1,
NO_XMLHTTPREQUEST_SUPPORT: 2,
NO_WEBRTC_SUPPORT: 3,
@@ -10097,7 +10056,7 @@ Skylink.prototype.generateUUID = function() {
* configuration is not honoured as Peers connected with MCU is similar as a forced TURN connection. The flags
* will act as if the value is false and ICE candidates will never be filtered regardless of the
* options.filterCandidatesType configuration.
- * @param {Boolean} [options.usePublicSTUN=true] The flag if publicly available STUN ICE servers should
+ * @param {Boolean} [options.usePublicSTUN=false] The flag if publicly available STUN ICE servers should
* be used if options.enableSTUNServer is enabled.
* @param {Boolean} [options.TURNServerTransport]
* Note that configuring the protocol may not necessarily result in the desired network transports protocol
@@ -10159,7 +10118,7 @@ Skylink.prototype.generateUUID = function() {
* @param {Boolean} [options.audioFallback=false] The flag if
* getUserMedia() method should fallback to retrieve only audio Stream when
* retrieving audio and video Stream fails.
- * @param {Boolean} [options.forceSSL=false] The flag if HTTPS connections should be enforced
+ * @param {Boolean} [options.forceSSL=true] The flag if HTTPS connections should be enforced
* during request to Auth server and socket connections to Signaling server
* when accessing window.location.protocol value is "http:".
* By default, "https:" protocol connections uses HTTPS connections.
@@ -10186,11 +10145,12 @@ Skylink.prototype.generateUUID = function() {
* The value must not be AUTO.
* [Rel: Skylink.VIDEO_CODEC]
* @param {Number} [options.videoCodec.samplingRate] The video codec sampling to prefer to encode sending video data when available.
- * @param {Number} [options.socketTimeout=20000] The timeout for each attempts for socket connection
+ * @param {Number} [options.socketTimeout=7000] The timeout for each attempts for socket connection
* with the Signaling server to indicate that connection has timed out and has failed to establish.
* Note that the mininum timeout value is 5000. If less, this value will be 5000.
- * Note that it is recommended to use 12000 as the lowest timeout value if Peers are connecting
+ * Note that it is recommended to use 7000 as the lowest timeout value if Peers are connecting
* using Polling transports to prevent connection errors.
+ * @param {Number} [options.apiTimeout=4000] The timeout to wait for response from Auth server.
* @param {Boolean} [options.forceTURNSSL=false]
* Note that currently Firefox does not support the TURNS protocol, and that if TURNS is required,
* TURN ICE servers using port 443 will be used instead.
@@ -10366,6 +10326,7 @@ Skylink.prototype.generateUUID = function() {
* @param {String|JSON} callback.success.audioCodec The configured value of the options.audioCodec.
* @param {String|JSON} callback.success.videoCodec The configured value of the options.videoCodec.
* @param {Number} callback.success.socketTimeout The configured value of the options.socketTimeout.
+ * @param {Number} callback.success.apiTimeout The configured value of the options.apiTimeout.
* @param {Boolean} callback.success.forceTURNSSL The configured value of the options.forceTURNSSL.
* @param {Boolean} callback.success.forceTURN The configured value of the options.forceTURN.
* @param {Boolean} callback.success.usePublicSTUN The configured value of the options.usePublicSTUN.
@@ -10468,13 +10429,14 @@ Skylink.prototype.init = function(options, callback) {
var enableTURNServer = true;
var TURNTransport = self.TURN_TRANSPORT.ANY;
var audioFallback = false;
- var forceSSL = false;
- var socketTimeout = 20000;
+ var forceSSL = true;
+ var socketTimeout = 7000;
+ var apiTimeout = 4000;
var forceTURNSSL = false;
var audioCodec = self.AUDIO_CODEC.AUTO;
var videoCodec = self.VIDEO_CODEC.AUTO;
var forceTURN = false;
- var usePublicSTUN = true;
+ var usePublicSTUN = false;
var disableVideoFecCodecs = false;
var disableComfortNoiseCodec = false;
var disableREMB = false;
@@ -10537,11 +10499,12 @@ Skylink.prototype.init = function(options, callback) {
// set the force ssl always option
forceSSL = (typeof options.forceSSL === 'boolean') ?
options.forceSSL : forceSSL;
- // set the socket timeout option
- socketTimeout = (typeof options.socketTimeout === 'number') ?
- options.socketTimeout : socketTimeout;
// set the socket timeout option to be above 5000
- socketTimeout = (socketTimeout < 5000) ? 5000 : socketTimeout;
+ socketTimeout = (typeof options.socketTimeout === 'number' && socketTimeout < 5000 && socketTimeout > 0) ?
+ options.socketTimeout : socketTimeout;
+ // set the api timeout option
+ apiTimeout = (typeof options.apiTimeout === 'number' && options.apiTimeout > 0) ?
+ options.apiTimeout : apiTimeout;
// set the force turn ssl always option
forceTURNSSL = (typeof options.forceTURNSSL === 'boolean') ?
options.forceTURNSSL : forceTURNSSL;
@@ -10818,6 +10781,7 @@ Skylink.prototype.init = function(options, callback) {
self._audioFallback = audioFallback;
self._forceSSL = forceSSL;
self._socketTimeout = socketTimeout;
+ self._apiTimeout = apiTimeout;
self._forceTURNSSL = forceTURNSSL;
self._selectedAudioCodec = audioCodec;
self._selectedVideoCodec = videoCodec;
@@ -10852,6 +10816,7 @@ Skylink.prototype.init = function(options, callback) {
audioFallback: self._audioFallback,
forceSSL: self._forceSSL,
socketTimeout: self._socketTimeout,
+ apiTimeout: self._apiTimeout,
forceTURNSSL: self._forceTURNSSL,
audioCodec: self._selectedAudioCodec,
videoCodec: self._selectedVideoCodec,
@@ -10900,6 +10865,7 @@ Skylink.prototype.init = function(options, callback) {
audioFallback: self._audioFallback,
forceSSL: self._forceSSL,
socketTimeout: self._socketTimeout,
+ apiTimeout: self._apiTimeout,
forceTURNSSL: self._forceTURNSSL,
audioCodec: self._selectedAudioCodec,
videoCodec: self._selectedVideoCodec,
@@ -10949,69 +10915,99 @@ Skylink.prototype.init = function(options, callback) {
*/
Skylink.prototype._requestServerInfo = function(method, url, callback, params) {
var self = this;
- // XDomainRequest is supported in IE8 - 9
- var useXDomainRequest = typeof window.XDomainRequest === 'function' ||
- typeof window.XDomainRequest === 'object';
-
- self._socketUseXDR = useXDomainRequest;
- var xhr;
+ var retries = 0;
- // set force SSL option
+ // XDomainRequest is supported in IE8 - 9 for CORS connection.
+ self._socketUseXDR = typeof window.XDomainRequest === 'function' || typeof window.XDomainRequest === 'object';
url = (self._forceSSL) ? 'https:' + url : url;
- if (useXDomainRequest) {
- log.debug([null, 'XMLHttpRequest', method, 'Using XDomainRequest. ' +
- 'XMLHttpRequest is now XDomainRequest'], {
- agent: AdapterJS.webrtcDetectedBrowser,
- version: AdapterJS.webrtcDetectedVersion
- });
- xhr = new XDomainRequest();
- xhr.setContentType = function (contentType) {
- xhr.contentType = contentType;
+ (function requestFn () {
+ var xhr = new XMLHttpRequest();
+ var completed = false;
+
+ if (self._socketUseXDR) {
+ log.debug([null, 'XMLHttpRequest', method, 'Using XDomainRequest for CORS authentication.']);
+ xhr = new XDomainRequest();
+ xhr.setContentType = function (contentType) {
+ xhr.contentType = contentType;
+ };
+ }
+
+ xhr.onload = function () {
+ if (completed) {
+ return;
+ }
+ completed = true;
+ var response = JSON.parse(xhr.responseText || xhr.response || '{}');
+ var status = xhr.status || 200;
+ log.debug([null, 'XMLHttpRequest', method, 'Received sessions parameters ->'], response);
+ callback(status, response);
};
- } else {
- log.debug([null, 'XMLHttpRequest', method, 'Using XMLHttpRequest'], {
- agent: AdapterJS.webrtcDetectedBrowser,
- version: AdapterJS.webrtcDetectedVersion
- });
- xhr = new window.XMLHttpRequest();
- xhr.setContentType = function (contentType) {
- xhr.setRequestHeader('Content-type', contentType);
+
+ xhr.onerror = function (error) {
+ if (completed) {
+ return;
+ }
+ completed = true;
+ log.error([null, 'XMLHttpRequest', method, 'Failed retrieving information with 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.onload = function () {
- var response = xhr.responseText || xhr.response;
- var status = xhr.status || 200;
- log.debug([null, 'XMLHttpRequest', method, 'Received sessions parameters'],
- JSON.parse(response || '{}'));
- callback(status, JSON.parse(response || '{}'));
- };
+ xhr.onprogress = function () {
+ log.debug([null, 'XMLHttpRequest', method, 'Retrieving information and config from webserver ->'], {
+ url: url,
+ params: params
+ });
+ };
- 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);
- };
+ try {
+ xhr.open(method, url, true);
+ if (params) {
+ xhr.setContentType('application/json;charset=UTF-8');
+ xhr.send(JSON.stringify(params));
+ } else {
+ xhr.send();
+ }
+ } catch (error) {
+ completed = true;
+ self._readyState = -1;
+ self._trigger('readyStateChange', self.READY_STATE_CHANGE.ERROR, {
+ status: xhr.status || null,
+ content: 'Failed starting XHR process.',
+ errorCode: self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR
+ }, self._selectedRoom);
+ return;
+ }
- xhr.onprogress = function () {
- log.debug([null, 'XMLHttpRequest', method,
- 'Retrieving information and config from webserver. Url:'], url);
- log.debug([null, 'XMLHttpRequest', method, 'Provided parameters:'], params);
- };
+ setTimeout(function () {
+ if (completed) {
+ return;
+ }
+ completed = true;
+ xhr.onload = null;
+ xhr.onerror = null;
+ xhr.onprogress = null;
- xhr.open(method, url, true);
- if (params) {
- xhr.setContentType('application/json;charset=UTF-8');
- xhr.send(JSON.stringify(params));
- } else {
- xhr.send();
- }
+ if (retries < 2) {
+ retries++;
+ requestFn();
+
+ } else {
+ self._readyState = -1;
+ self._trigger('readyStateChange', self.READY_STATE_CHANGE.ERROR, {
+ status: xhr.status || null,
+ content: 'Response timed out from API server',
+ errorCode: self.READY_STATE_CHANGE_ERROR.XML_HTTP_NO_REPONSE_ERROR
+ }, self._selectedRoom);
+ }
+ }, self._apiTimeout);
+ })();
};
/**
@@ -11070,8 +11066,8 @@ Skylink.prototype._parseInfo = function(info) {
// set the socket ports
this._socketPorts = {
- 'http:': info.httpPortList,
- 'https:': info.httpsPortList
+ 'http:': Array.isArray(info.httpPortList) && info.httpPortList.length > 0 ? info.httpPortList : [80, 3000],
+ 'https:': Array.isArray(info.httpsPortList) && info.httpsPortList.length > 0 ? info.httpsPortList : [443, 3443]
};
// use default bandwidth and media resolution provided by server
@@ -11236,6 +11232,7 @@ Skylink.prototype._initSelectedRoom = function(room, callback) {
audioFallback: self._audioFallback,
forceSSL: self._forceSSL,
socketTimeout: self._socketTimeout,
+ apiTimeout: self._apiTimeout,
forceTURNSSL: self._forceTURNSSL,
audioCodec: self._selectedAudioCodec,
videoCodec: self._selectedVideoCodec,
@@ -11273,7 +11270,6 @@ Skylink.prototype._initSelectedRoom = function(room, callback) {
};
-
Skylink.prototype.LOG_LEVEL = {
DEBUG: 4,
LOG: 3,
@@ -11357,6 +11353,18 @@ var _enableDebugStack = false;
*/
var _enableDebugTrace = false;
+/**
+ * Stores the flag if logs should print timestamp.
+ * @attribute _printTimestamp
+ * @type Boolean
+ * @default false
+ * @private
+ * @scoped true
+ * @for Skylink
+ * @since 0.6.26
+ */
+var _printTimestamp = false;
+
/**
* Stores the logs used for SkylinkLogs object.
* @attribute _storedLogs
@@ -11507,7 +11515,8 @@ var SkylinkLogs = {
* @since 0.5.5
*/
var _logFn = function(logLevel, message, debugObject) {
- var outputLog = _LOG_KEY;
+ var outputLog = '';
+ var datetime = (new Date());
if (typeof message === 'object') {
outputLog += (message[0]) ? ' [' + message[0] + '] -' : ' -';
@@ -11529,7 +11538,7 @@ var _logFn = function(logLevel, message, debugObject) {
if (_enableDebugMode && _enableDebugStack) {
// store the logs
- var logItem = [(new Date()), _LOG_LEVELS[logLevel], outputLog];
+ var logItem = [datetime, _LOG_LEVELS[logLevel], outputLog];
if (typeof debugObject !== 'undefined') {
logItem.push(debugObject);
@@ -11537,6 +11546,8 @@ var _logFn = function(logLevel, message, debugObject) {
_storedLogs.push(logItem);
}
+ outputLog = _LOG_KEY + (_printTimestamp ? ' :: ' + datetime.toISOString() : '') + outputLog;
+
if (_logLevel >= logLevel) {
// Fallback to log if failure
logLevel = (typeof console[_LOG_LEVELS[logLevel]] === 'undefined') ? 3 : logLevel;
@@ -11653,6 +11664,7 @@ Skylink.prototype.setLogLevel = function(logLevel) {
* will fallback to use console.log() API.
* @param {Boolean} [options.storeLogs=false] The flag if SDK should store the console logs.
* This is required to be enabled for SkylinkLogs API.
+ * @param {Boolean} [options.printTimestamp=false] The flag if SDK should print the timestamp of the console logs.
* @example
* // Example 1: Enable both options.storeLogs and options.trace
* skylinkDemo.setDebugMode(true);
@@ -11671,16 +11683,19 @@ Skylink.prototype.setDebugMode = function(isDebugMode) {
_enableDebugMode = true;
_enableDebugTrace = isDebugMode.trace === true;
_enableDebugStack = isDebugMode.storeLogs === true;
+ _printTimestamp = isDebugMode.printTimestamp === true;
// setDebugMode(true)
} else if (isDebugMode === true) {
_enableDebugMode = true;
_enableDebugTrace = true;
_enableDebugStack = true;
+ _printTimestamp = false;
// setDebugMode()
} else {
_enableDebugMode = false;
_enableDebugTrace = false;
_enableDebugStack = false;
+ _printTimestamp = false;
}
};
var _eventsDocs = {
@@ -13508,7 +13523,7 @@ Skylink.prototype._sendChannelMessage = function(message) {
* @for Skylink
* @since 0.5.10
*/
-Skylink.prototype._createSocket = function (type) {
+Skylink.prototype._createSocket = function (type, joinRoomTimestamp) {
var self = this;
var options = {
forceNew: true,
@@ -13548,7 +13563,7 @@ Skylink.prototype._createSocket = function (type) {
options.transports = ['xhr-polling', 'jsonp-polling', 'polling'];
}
- var url = self._signalingServerProtocol + '//' + self._signalingServer + ':' + self._signalingServerPort;
+ var url = self._signalingServerProtocol + '//' + self._signalingServer + ':' + self._signalingServerPort + '?rand=' + Date.now();
var retries = 0;
if (self._socketServer) {
@@ -13581,8 +13596,10 @@ Skylink.prototype._createSocket = function (type) {
log.log('Opening channel with signaling server url:', clone(self._socketSession));
+ var socket = null;
+
try {
- self._socket = io.connect(url, options);
+ socket = io.connect(url, options);
} catch (error){
log.error('Failed creating socket connection object ->', error);
if (fallbackType === self.SOCKET_FALLBACK.NON_FALLBACK) {
@@ -13595,13 +13612,13 @@ Skylink.prototype._createSocket = function (type) {
return;
}
- self._socket.on('reconnect_attempt', function (attempt) {
+ 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 () {
+ socket.on('reconnect_failed', function () {
if (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));
@@ -13611,14 +13628,14 @@ Skylink.prototype._createSocket = function (type) {
}
if (self._socketSession.finalAttempts < 2) {
- self._createSocket(type);
+ self._createSocket(type, joinRoomTimestamp);
} else {
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 () {
+ socket.on('connect', function () {
if (!self._channelOpen) {
log.log([null, 'Socket', null, 'Channel opened']);
self._channelOpen = true;
@@ -13626,7 +13643,7 @@ Skylink.prototype._createSocket = function (type) {
}
});
- self._socket.on('reconnect', function () {
+ socket.on('reconnect', function () {
if (!self._channelOpen) {
log.log([null, 'Socket', null, 'Channel opened']);
self._channelOpen = true;
@@ -13634,7 +13651,7 @@ Skylink.prototype._createSocket = function (type) {
}
});
- self._socket.on('error', function(error) {
+ socket.on('error', function(error) {
if (error ? error.message.indexOf('xhr poll error') > -1 : false) {
log.error([null, 'Socket', null, 'XHR poll connection unstable. Disconnecting.. ->'], error);
self._closeChannel();
@@ -13644,7 +13661,7 @@ Skylink.prototype._createSocket = function (type) {
self._trigger('channelError', error, clone(self._socketSession));
});
- self._socket.on('disconnect', function() {
+ socket.on('disconnect', function() {
if (self._channelOpen) {
self._channelOpen = false;
self._trigger('channelClose', clone(self._socketSession));
@@ -13657,7 +13674,7 @@ Skylink.prototype._createSocket = function (type) {
}
});
- self._socket.on('message', function(messageStr) {
+ socket.on('message', function(messageStr) {
var message = JSON.parse(messageStr);
log.log([null, 'Socket', null, 'Received message ->'], message);
@@ -13674,6 +13691,13 @@ Skylink.prototype._createSocket = function (type) {
self._trigger('channelMessage', message, clone(self._socketSession));
}
});
+
+ self._joinRoomManager.socketsFn.push(function (currentJoinRoomTimestamp) {
+ if (currentJoinRoomTimestamp !== joinRoomTimestamp) {
+ socket.disconnect();
+ }
+ });
+ self._socket = socket;
};
/**
@@ -13684,7 +13708,7 @@ Skylink.prototype._createSocket = function (type) {
* @for Skylink
* @since 0.5.5
*/
-Skylink.prototype._openChannel = function() {
+Skylink.prototype._openChannel = function(joinRoomTimestamp) {
var self = this;
if (self._channelOpen) {
log.error([null, 'Socket', null, 'Unable to instantiate a new channel connection ' +
@@ -13717,7 +13741,7 @@ Skylink.prototype._openChannel = function() {
self._signalingServerPort = null;
// Begin with a websocket connection
- self._createSocket(socketType);
+ self._createSocket(socketType, joinRoomTimestamp);
};
/**
@@ -14719,7 +14743,7 @@ 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._room.connection.peerConfig = self._setIceServers((message.pc_config || {}).iceServers || []);
self._inRoom = true;
self._user.sid = message.sid;
self._peerPriorityWeight = message.tieBreaker + (self._priorityWeightScheme === self.PRIORITY_WEIGHT_SCHEME.AUTO ?
@@ -16227,7 +16251,17 @@ Skylink.prototype.getUserMedia = function(options,callback) {
self._onStreamAccessError(error, settings, false, false);
};
- navigator.getUserMedia(settings.getUserMediaSettings, onSuccessCbFn, onErrorCbFn);
+ try {
+ if (typeof (AdapterJS || {}).webRTCReady !== 'function') {
+ return onErrorCbFn(new Error('Failed to call getUserMedia() as AdapterJS is not yet loaded!'));
+ }
+
+ AdapterJS.webRTCReady(function () {
+ navigator.getUserMedia(settings.getUserMediaSettings, onSuccessCbFn, onErrorCbFn);
+ });
+ } catch (error) {
+ onErrorCbFn(error);
+ }
}, 'getUserMedia', self._throttlingTimeouts.getUserMedia);
};
@@ -17106,8 +17140,13 @@ Skylink.prototype.shareScreen = function (enableAudio, mediaSource, callback) {
self._onStreamAccessError(error, settings, true, false);
};
- navigator.getUserMedia(settings.getUserMediaSettings, onSuccessCbFn, onErrorCbFn);
+ if (typeof (AdapterJS || {}).webRTCReady !== 'function') {
+ return onErrorCbFn(new Error('Failed to call getUserMedia() as AdapterJS is not yet loaded!'));
+ }
+ AdapterJS.webRTCReady(function () {
+ navigator.getUserMedia(settings.getUserMediaSettings, onSuccessCbFn, onErrorCbFn);
+ });
} catch (error) {
self._onStreamAccessError(error, settings, true, false);
}
diff --git a/publish/skylink.min.js b/publish/skylink.min.js
index 9ed6d5922..b562fb67f 100644
--- a/publish/skylink.min.js
+++ b/publish/skylink.min.js
@@ -1,12 +1,12 @@
-/*! skylinkjs - v0.6.25 - 2017-09-08 */
-!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._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=!1,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=this.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,this._peerConnectionConfig={},this._codecParams={},this._priorityWeightScheme=this.PRIORITY_WEIGHT_SCHEME.AUTO,this._bandwidthAdjuster=null,this._peerConnStatus={},this._useEdgeWebRTC=!1}!function(){Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,r=!{toString:null}.propertyIsEnumerable("toString"),e=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],o=e.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var c=[];for(var l in n)t.call(n,l)&&c.push(l);if(r)for(var p=0;o>p;p++)t.call(n,e[p])&&c.push(e[p]);return c}}())}(),function(){function t(t){return 10>t?"0"+t:t}Date.prototype.toISOString=function(){return this.getUTCFullYear()+"-"+t(this.getUTCMonth()+1)+"-"+t(this.getUTCDate())+"T"+t(this.getUTCHours())+":"+t(this.getUTCMinutes())+":"+t(this.getUTCSeconds())+"."+(this.getUTCMilliseconds()/1e3).toFixed(3).slice(2,5)+"Z"}}(),function(){"function"!=typeof Date.now&&(Date.now=function(){return(new Date).getTime()})}(),function(e,t){function n(e){var n=t[e];t[e]=function(e){return o(n(e))}}function a(t,n,a){return(a=this).attachEvent("on"+t,function(t){var t=t||e.event;t.preventDefault=t.preventDefault||function(){t.returnValue=!1},t.stopPropagation=t.stopPropagation||function(){t.cancelBubble=!0},n.call(a,t)})}function o(e,t){if(t=e.length)for(;t--;)e[t].addEventListener=a;else e.addEventListener=a;return e}e.addEventListener||(o([t,e]),"Element"in e?e.Element.prototype.addEventListener=a:(t.attachEvent("onreadystatechange",function(){o(t.all)}),n("getElementsByTagName"),n("getElementById"),n("createElement"),o(t.all)))}(window,document),function(){if("performance"in window==0&&(window.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in window.performance==0){var a=Date.now();performance.timing&&performance.timing.navigationStart&&(a=performance.timing.navigationStart),window.performance.now=function(){return Date.now()-a}}}(),window.BlobBuilder=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,Array.prototype.forEach||(Array.prototype.forEach=function(callback){var T,k;if(null==this)throw new TypeError("this is null or not defined");var O=Object(this),len=O.length>>>0;if("function"!=typeof callback)throw new TypeError(callback+" is not a function");for(arguments.length>1&&(T=arguments[1]),k=0;k"],error),void self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CREATE_ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))}self._dataChannels[peerId]?self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel.label===channelName&&(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING):(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING,self._dataChannels[peerId]={},log.debug([peerId,"RTCDataChannel",channelProp,"initializing main DataChannel"])),dataChannel.onerror=function(evt){var channelError=evt.error||evt;log.error([peerId,"RTCDataChannel",channelProp,"Datachannel has an exception ->"],channelError),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,channelError,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onbufferedamountlow=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel buffering data transfer low"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.BUFFERED_AMOUNT_LOW,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onmessage=function(event){self._processDataChannelData(event.data,peerId,channelName,channelType)};var onOpenHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has opened"]),dataChannel.bufferedAmountLowThreshold=bufferThreshold||0,self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.OPEN,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))};dataChannel.readyState===self.DATA_CHANNEL_STATE.OPEN?setTimeout(onOpenHandlerFn,1):(self._trigger("dataChannelState",dataChannel.readyState,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),dataChannel.onopen=onOpenHandlerFn);var onCloseHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has closed"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSED,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),self._peerConnections[peerId]&&self._peerConnections[peerId].remoteDescription&&self._peerConnections[peerId].remoteDescription.sdp&&(-1===self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")||self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application 0")>0)||channelType===self.DATA_CHANNEL_TYPE.MESSAGING&&setTimeout(function(){self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[peerId].localDescription&&self._peerConnections[peerId].localDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&(log.debug([peerId,"RTCDataChannel",channelProp,"Reviving Datachannel connection"]),self._createDataChannel(peerId,channelName,bufferThreshold,!0))},100)};if("firefox"===AdapterJS.webrtcDetectedBrowser){var hasTriggeredClose=!1,timeBlockAfterClosing=0;dataChannel.onclose=function(){hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())};var onFFClosed=setInterval(function(){dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSED||hasTriggeredClose||5===timeBlockAfterClosing?(clearInterval(onFFClosed),hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())):dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSING&&timeBlockAfterClosing++},1e3)}else dataChannel.onclose=onCloseHandlerFn;channelType===self.DATA_CHANNEL_TYPE.MESSAGING?self._dataChannels[peerId].main={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}:self._dataChannels[peerId][channelName]={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}},Skylink.prototype._getDataChannelBuffer=function(peerId,channelProp){if("object"==typeof peerId)return{bufferedAmountLow:"number"==typeof peerId.bufferedAmountLow?peerId.bufferedAmountLow:parseInt(peerId.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?peerId.bufferedAmountLowThreshold:parseInt(peerId.bufferedAmountLowThreshold,10)||0};if(!(this._dataChannels[peerId]&&this._dataChannels[peerId][channelProp]&&this._dataChannels[peerId][channelProp].channel))return{bufferedAmountLow:0,bufferedAmountLowThreshold:0};var channel=this._dataChannels[peerId][channelProp].channel;return{bufferedAmountLow:"number"==typeof channel.bufferedAmountLow?channel.bufferedAmountLow:parseInt(channel.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof channel.bufferedAmountLowThreshold?channel.bufferedAmountLowThreshold:parseInt(channel.bufferedAmountLowThreshold,10)||0}},Skylink.prototype._sendMessageToDataChannel=function(peerId,data,channelProp,doNotConvert){var self=this;if(channelProp&&channelProp!==peerId||(channelProp="main"),!("object"==typeof data&&data||data&&"string"==typeof data))return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping invalid data ->"],data);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Peer connection does not exists or is closed ->"],data);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Datachannel connection does not exists ->"],data);var channelName=self._dataChannels[peerId][channelProp].channelName,channelType=self._dataChannels[peerId][channelProp].channelType,readyState=self._dataChannels[peerId][channelProp].channel.readyState,messageType="object"==typeof data&&data.type===self._DC_PROTOCOL_TYPE.MESSAGE?self.DATA_CHANNEL_MESSAGE_ERROR.MESSAGE:self.DATA_CHANNEL_MESSAGE_ERROR.TRANSFER;if(readyState!==self.DATA_CHANNEL_STATE.OPEN){var notOpenError='Failed sending message as Datachannel connection state is not opened. Current readyState is "'+readyState+'"';throw log.error([peerId,"RTCDataChannel",channelProp,notOpenError+" ->"],data),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,new Error(notOpenError),channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),new Error(notOpenError)}try{doNotConvert||"object"!=typeof data?(log.debug([peerId,"RTCDataChannel",channelProp,"Sending data with size ->"],data.size||data.length||data.byteLength),self._dataChannels[peerId][channelProp].channel.send(data)):(log.debug([peerId,"RTCDataChannel",channelProp,'Sending "'+data.type+'" protocol message ->'],data),self._dataChannels[peerId][channelProp].channel.send(JSON.stringify(data)))}catch(error){throw log.error([peerId,"RTCDataChannel",channelProp,"Failed sending "+(doNotConvert||"object"!=typeof data?"data":'"'+data.type+'" protocol message')+" ->"],error),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,error,channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),error}},Skylink.prototype._closeDataChannel=function(peerId,channelProp){var self=this;if(!self._dataChannels[peerId])return void log.warn([peerId,"RTCDataChannel",channelProp||null,"Aborting closing Datachannels as Peer connection does not have Datachannel sessions"]);var closeFn=function(rChannelProp){var channelName=self._dataChannels[peerId][rChannelProp].channelName,channelType=self._dataChannels[peerId][rChannelProp].channelType;self._dataChannels[peerId][rChannelProp].readyState!==self.DATA_CHANNEL_STATE.CLOSED&&(log.debug([peerId,"RTCDataChannel",channelProp,"Closing Datachannel"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSING,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(peerId,rChannelProp)),self._dataChannels[peerId][rChannelProp].channel.close(),delete self._dataChannels[peerId][rChannelProp])};if(channelProp){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.");if(!self._enableSimultaneousTransfers)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature requires simultaneous data transfers to be enabled");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},listenToPeerFn=function(peerId,channelProp){var hasStarted=!1;sessions[peerId]=channelProp,self.once("dataStreamState",function(){},function(state,evtTransferId,evtPeerId,evtSessionInfo){if(evtTransferId===transferId&&evtPeerId===peerId){evtSessionInfo.chunk;return delete clone(evtSessionInfo).chunk,state===self.DATA_STREAM_STATE.SENDING_STARTED?void(hasStarted=!0):hasStarted&&[self.DATA_STREAM_STATE.ERROR,self.DATA_STREAM_STATE.SENDING_STOPPED].indexOf(state)>-1?(channelProp===transferId&&self._closeDataChannel(peerId,transferId),self._dataStreams[transferId]&&self._dataStreams[transferId].sessions[peerId]&&(delete self._dataStreams[transferId].sessions[peerId],0===Object.keys(self._dataStreams[transferId].sessions).length&&delete self._dataStreams[transferId]),!0):void 0}})},i=0;i-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');if("MCU"===peerId)for(var mp=0;mpp;p++)t.call(n,e[p])&&c.push(e[p]);return c}}())}(),function(){function t(t){return 10>t?"0"+t:t}Date.prototype.toISOString=function(){return this.getUTCFullYear()+"-"+t(this.getUTCMonth()+1)+"-"+t(this.getUTCDate())+"T"+t(this.getUTCHours())+":"+t(this.getUTCMinutes())+":"+t(this.getUTCSeconds())+"."+(this.getUTCMilliseconds()/1e3).toFixed(3).slice(2,5)+"Z"}}(),function(){"function"!=typeof Date.now&&(Date.now=function(){return(new Date).getTime()})}(),function(e,t){function n(e){var n=t[e];t[e]=function(e){return o(n(e))}}function a(t,n,a){return(a=this).attachEvent("on"+t,function(t){var t=t||e.event;t.preventDefault=t.preventDefault||function(){t.returnValue=!1},t.stopPropagation=t.stopPropagation||function(){t.cancelBubble=!0},n.call(a,t)})}function o(e,t){if(t=e.length)for(;t--;)e[t].addEventListener=a;else e.addEventListener=a;return e}e.addEventListener||(o([t,e]),"Element"in e?e.Element.prototype.addEventListener=a:(t.attachEvent("onreadystatechange",function(){o(t.all)}),n("getElementsByTagName"),n("getElementById"),n("createElement"),o(t.all)))}(window,document),function(){if("performance"in window==0&&(window.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in window.performance==0){var a=Date.now();performance.timing&&performance.timing.navigationStart&&(a=performance.timing.navigationStart),window.performance.now=function(){return Date.now()-a}}}(),window.BlobBuilder=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,Array.prototype.forEach||(Array.prototype.forEach=function(callback){var T,k;if(null==this)throw new TypeError("this is null or not defined");var O=Object(this),len=O.length>>>0;if("function"!=typeof callback)throw new TypeError(callback+" is not a function");for(arguments.length>1&&(T=arguments[1]),k=0;k"],error),void self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CREATE_ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))}self._dataChannels[peerId]?self._dataChannels[peerId].main&&self._dataChannels[peerId].main.channel.label===channelName&&(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING):(channelProp="main",channelType=self.DATA_CHANNEL_TYPE.MESSAGING,self._dataChannels[peerId]={},log.debug([peerId,"RTCDataChannel",channelProp,"initializing main DataChannel"])),dataChannel.onerror=function(evt){var channelError=evt.error||evt;log.error([peerId,"RTCDataChannel",channelProp,"Datachannel has an exception ->"],channelError),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,channelError,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onbufferedamountlow=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel buffering data transfer low"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.BUFFERED_AMOUNT_LOW,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))},dataChannel.onmessage=function(event){self._processDataChannelData(event.data,peerId,channelName,channelType)};var onOpenHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has opened"]),dataChannel.bufferedAmountLowThreshold=bufferThreshold||0,self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.OPEN,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel))};dataChannel.readyState===self.DATA_CHANNEL_STATE.OPEN?setTimeout(onOpenHandlerFn,1):(self._trigger("dataChannelState",dataChannel.readyState,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),dataChannel.onopen=onOpenHandlerFn);var onCloseHandlerFn=function(){log.debug([peerId,"RTCDataChannel",channelProp,"Datachannel has closed"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSED,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(dataChannel)),self._peerConnections[peerId]&&self._peerConnections[peerId].remoteDescription&&self._peerConnections[peerId].remoteDescription.sdp&&(-1===self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application")||self._peerConnections[peerId].remoteDescription.sdp.indexOf("m=application 0")>0)||channelType===self.DATA_CHANNEL_TYPE.MESSAGING&&setTimeout(function(){self._peerConnections[peerId]&&self._peerConnections[peerId].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[peerId].localDescription&&self._peerConnections[peerId].localDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&(log.debug([peerId,"RTCDataChannel",channelProp,"Reviving Datachannel connection"]),self._createDataChannel(peerId,channelName,bufferThreshold,!0))},100)};if("firefox"===AdapterJS.webrtcDetectedBrowser){var hasTriggeredClose=!1,timeBlockAfterClosing=0;dataChannel.onclose=function(){hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())};var onFFClosed=setInterval(function(){dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSED||hasTriggeredClose||5===timeBlockAfterClosing?(clearInterval(onFFClosed),hasTriggeredClose||(hasTriggeredClose=!0,onCloseHandlerFn())):dataChannel.readyState===self.DATA_CHANNEL_STATE.CLOSING&&timeBlockAfterClosing++},1e3)}else dataChannel.onclose=onCloseHandlerFn;channelType===self.DATA_CHANNEL_TYPE.MESSAGING?self._dataChannels[peerId].main={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}:self._dataChannels[peerId][channelName]={channelName:channelName,channelType:channelType,transferId:null,streamId:null,channel:dataChannel}},Skylink.prototype._getDataChannelBuffer=function(peerId,channelProp){if("object"==typeof peerId)return{bufferedAmountLow:"number"==typeof peerId.bufferedAmountLow?peerId.bufferedAmountLow:parseInt(peerId.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof peerId.bufferedAmountLowThreshold?peerId.bufferedAmountLowThreshold:parseInt(peerId.bufferedAmountLowThreshold,10)||0};if(!(this._dataChannels[peerId]&&this._dataChannels[peerId][channelProp]&&this._dataChannels[peerId][channelProp].channel))return{bufferedAmountLow:0,bufferedAmountLowThreshold:0};var channel=this._dataChannels[peerId][channelProp].channel;return{bufferedAmountLow:"number"==typeof channel.bufferedAmountLow?channel.bufferedAmountLow:parseInt(channel.bufferedAmountLow,10)||0,bufferedAmountLowThreshold:"number"==typeof channel.bufferedAmountLowThreshold?channel.bufferedAmountLowThreshold:parseInt(channel.bufferedAmountLowThreshold,10)||0}},Skylink.prototype._sendMessageToDataChannel=function(peerId,data,channelProp,doNotConvert){var self=this;if(channelProp&&channelProp!==peerId||(channelProp="main"),!("object"==typeof data&&data||data&&"string"==typeof data))return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping invalid data ->"],data);if(!self._peerConnections[peerId]||self._peerConnections[peerId].signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Peer connection does not exists or is closed ->"],data);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping for sending message as Datachannel connection does not exists ->"],data);var channelName=self._dataChannels[peerId][channelProp].channelName,channelType=self._dataChannels[peerId][channelProp].channelType,readyState=self._dataChannels[peerId][channelProp].channel.readyState,messageType="object"==typeof data&&data.type===self._DC_PROTOCOL_TYPE.MESSAGE?self.DATA_CHANNEL_MESSAGE_ERROR.MESSAGE:self.DATA_CHANNEL_MESSAGE_ERROR.TRANSFER;if(readyState!==self.DATA_CHANNEL_STATE.OPEN){var notOpenError='Failed sending message as Datachannel connection state is not opened. Current readyState is "'+readyState+'"';throw log.error([peerId,"RTCDataChannel",channelProp,notOpenError+" ->"],data),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,new Error(notOpenError),channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),new Error(notOpenError)}try{doNotConvert||"object"!=typeof data?(log.debug([peerId,"RTCDataChannel",channelProp,"Sending data with size ->"],data.size||data.length||data.byteLength),self._dataChannels[peerId][channelProp].channel.send(data)):(log.debug([peerId,"RTCDataChannel",channelProp,'Sending "'+data.type+'" protocol message ->'],data),self._dataChannels[peerId][channelProp].channel.send(JSON.stringify(data)))}catch(error){throw log.error([peerId,"RTCDataChannel",channelProp,"Failed sending "+(doNotConvert||"object"!=typeof data?"data":'"'+data.type+'" protocol message')+" ->"],error),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.SEND_MESSAGE_ERROR,peerId,error,channelName,channelType,messageType,self._getDataChannelBuffer(peerId,channelProp)),error}},Skylink.prototype._closeDataChannel=function(peerId,channelProp){var self=this;if(!self._dataChannels[peerId])return void log.warn([peerId,"RTCDataChannel",channelProp||null,"Aborting closing Datachannels as Peer connection does not have Datachannel sessions"]);var closeFn=function(rChannelProp){var channelName=self._dataChannels[peerId][rChannelProp].channelName,channelType=self._dataChannels[peerId][rChannelProp].channelType;self._dataChannels[peerId][rChannelProp].readyState!==self.DATA_CHANNEL_STATE.CLOSED&&(log.debug([peerId,"RTCDataChannel",channelProp,"Closing Datachannel"]),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.CLOSING,peerId,null,channelName,channelType,null,self._getDataChannelBuffer(peerId,rChannelProp)),self._dataChannels[peerId][rChannelProp].channel.close(),delete self._dataChannels[peerId][rChannelProp])};if(channelProp){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.");if(!self._enableSimultaneousTransfers)return emitErrorBeforeStreamingFn("Unable to start data streaming as this feature requires simultaneous data transfers to be enabled");for(var transferId="stream_"+(self._user&&self._user.sid?self._user.sid:"-")+"_"+(new Date).getTime(),peersInterop=[],peersNonInterop=[],sessions={},listenToPeerFn=function(peerId,channelProp){var hasStarted=!1;sessions[peerId]=channelProp,self.once("dataStreamState",function(){},function(state,evtTransferId,evtPeerId,evtSessionInfo){if(evtTransferId===transferId&&evtPeerId===peerId){evtSessionInfo.chunk;return delete clone(evtSessionInfo).chunk,state===self.DATA_STREAM_STATE.SENDING_STARTED?void(hasStarted=!0):hasStarted&&[self.DATA_STREAM_STATE.ERROR,self.DATA_STREAM_STATE.SENDING_STOPPED].indexOf(state)>-1?(channelProp===transferId&&self._closeDataChannel(peerId,transferId),self._dataStreams[transferId]&&self._dataStreams[transferId].sessions[peerId]&&(delete self._dataStreams[transferId].sessions[peerId],0===Object.keys(self._dataStreams[transferId].sessions).length&&delete self._dataStreams[transferId]),!0):void 0}})},i=0;i-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');if("MCU"===peerId)for(var mp=0;mp-1}),self._createDataChannel(peerId,transferId,"string"===sessionChunkType?self._CHUNK_DATAURL_SIZE:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE)};if(peersNonInterop.length>0)if(self._hasMCU)waitForChannelOpenFn("MCU",peersNonInterop);else for(var pni=0;pni0)if(self._hasMCU)startDataSessionFn("MCU","main",peersInterop);else for(var pi=0;piself._CHUNK_DATAURL_SIZE:updatedDataChunk.length>self._BINARY_FILE_SIZE)return void log.error("Failed streaming data chunk as data chunk exceeds maximum chunk limit.");var sessionInfo={chunk:updatedDataChunk,chunkSize:updatedDataChunk.size||updatedDataChunk.length||updatedDataChunk.byteLength,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){var onSendDataFn=function(buffer){self._sendMessageToDataChannel(peerId,buffer,channelProp,!0);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype.stopStreamingData=function(transferId){var self=this;if(!transferId||"string"!=typeof transferId)return void log.error("Failed streaming data chunk as stream session ID is not provided.");if(!(self._inRoom&&self._user&&self._user.sid))return void log.error("Failed streaming data chunk as User is not in the Room.");if(!self._dataStreams[transferId])return void log.error("Failed stopping data streaming session as it does not exists.");if(!self._dataStreams[transferId].isUpload)return void log.error("Failed stopping data streaming session as it is not sending.");if(self._hasMCU)return void log.error("Failed stopping data streaming session as MCU does not support this feature yet.");var sessionInfo={chunk:null,chunkSize:0,chunkType:"string"===self._dataStreams[transferId].sessionChunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,isPrivate:self._dataStreams[transferId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:self._user&&self._user.sid?self._user.sid:null},peersInterop=[],peersNonInterop=[],sendDataFn=function(peerId,channelProp,targetPeers){self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:transferId,size:0,originalSize:0,dataType:"fastBinaryStop",mimeType:null,chunkType:self._dataStreams[transferId].sessionChunkType,chunkSize:0,timeout:0,isPrivate:self._dataStreams[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp);var updatedSessionInfo=clone(sessionInfo);if(delete updatedSessionInfo.chunk,targetPeers)for(var i=0;i0&&sendDataFn(peerId,"main",peersInterop),peersNonInterop.length>0&&sendDataFn(peerId,transferId,peersNonInterop))},Skylink.prototype._startDataTransfer=function(data,timeout,targetPeerId,sendChunksAsBinary,callback,sessionType){var self=this,transferId=(self._user?self._user.sid:"")+"_"+(new Date).getTime(),transferErrors={},transferCompleted=[],chunks=[],listOfPeers=Object.keys(self._peerConnections),sessionChunkType="string",transferInfo={name:null,size:null,chunkSize:null,chunkType:null,dataType:null,mimeType:null,direction:self.DATA_TRANSFER_TYPE.UPLOAD,timeout:60,isPrivate:!1,percentage:0};"number"==typeof timeout?transferInfo.timeout=timeout:Array.isArray(timeout)?listOfPeers=timeout:timeout&&"string"==typeof timeout?listOfPeers=[timeout]:timeout&&"boolean"==typeof timeout?sessionChunkType="binary":"function"==typeof timeout&&(callback=timeout),Array.isArray(targetPeerId)?listOfPeers=targetPeerId:targetPeerId&&"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:targetPeerId&&"boolean"==typeof targetPeerId?sessionChunkType="binary":"function"==typeof targetPeerId&&(callback=targetPeerId),sendChunksAsBinary&&"boolean"==typeof sendChunksAsBinary?sessionChunkType="binary":"function"==typeof sendChunksAsBinary&&(callback=sendChunksAsBinary),listOfPeers.indexOf("MCU")>-1&&listOfPeers.splice(listOfPeers.indexOf("MCU"),1);var emitErrorBeforeDataTransferFn=function(error){if(log.error(error),"function"==typeof callback){var transferErrors={};if(0===listOfPeers.length)transferErrors.self=new Error(error);else for(var i=0;i0){var bsChunkSize="firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_CHUNK_FILE_SIZE:self._CHUNK_FILE_SIZE,bsChunks=self._chunkBlobData(new Blob(chunks),bsChunkSize);self._dataTransfers[transferId].enforceBSInfo={chunkSize:4*Math.ceil(bsChunkSize/3),chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,size:4*Math.ceil(transferInfo.originalSize/3),chunks:bsChunks}}}for(var completeFn=function(peerId,error){transferCompleted.indexOf(peerId)>-1||(log.debug([peerId,"RTCDataChannel",transferId,"Data transfer result. Is errors present? ->"],error),transferCompleted.push(peerId),error&&(transferErrors[peerId]=new Error(error)),listOfPeers.length===transferCompleted.length&&(log.log([null,"RTCDataChannel",transferId,"Data transfer request completed"]),"function"==typeof callback&&(Object.keys(transferErrors).length>0?callback({transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),transferErrors:transferErrors,listOfPeers:listOfPeers},null):callback(null,{transferId:transferId,transferInfo:self._getTransferInfo(transferId,peerId,!1,!0,!1),listOfPeers:listOfPeers}))))},i=0;i0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,"main",Object.keys(self._dataTransfers[transferId].peers.main)),Object.keys(self._dataTransfers[transferId].peers[transferId]).length>0&&self._startDataTransferToPeer(transferId,"MCU",completeFn,transferId,Object.keys(self._dataTransfers[transferId].peers[transferId])))},Skylink.prototype._startDataTransferToPeer=function(transferId,peerId,callback,channelProp,targetPeers){var self=this,peerConnectionStateCbFn=null,dataChannelStateCbFn=null,emitEventFn=function(cb){for(var peers=targetPeers||[peerId],i=0;i-1&&(log.warn([peerId,"RTCDataChannel",transferId,"Binary data chunks transfer is not yet supported with Peer connecting from Android, iOS and C++ SDK. Fallbacking to binary string data chunks transfer."]),size=self._dataTransfers[transferId].enforceBSInfo.size,chunkSize=self._dataTransfers[transferId].enforceBSInfo.chunkSize,chunkType="string"),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.WRQ,transferId:transferId,name:self._dataTransfers[transferId].name,size:size,originalSize:self._dataTransfers[transferId].originalSize,dataType:self._dataTransfers[transferId].sessionType,mimeType:self._dataTransfers[transferId].mimeType,chunkType:chunkType,chunkSize:chunkSize,timeout:self._dataTransfers[transferId].timeout,isPrivate:self._dataTransfers[transferId].isPrivate,sender:self._user.sid,agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,target:targetPeers||peerId},channelProp),emitEventFn(function(evtPeerId){self._trigger("incomingDataRequest",transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.USER_UPLOAD_REQUEST,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)})};if("MCU"!==peerId){var dataTransferStateCbFn=function(state,evtTransferId,evtPeerId,transferInfo,error){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&&-1===self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)))return void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel currently has an active "+self._dataStreams[streamId].sessionChunkType+" data streaming session.");var protocolVer=(self._peerInformations[peerId].agent||{}).DTProtocolVersion||"0.1.0",requireInterop=self._isLowerThanVersion(protocolVer,"0.1.2")||!self._enableSimultaneousTransfers;return self._isLowerThanVersion(protocolVer,"0.1.2")&&"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer do not support DATA_URL type of data transfers"):"MCU"!==peerId&&self._hasMCU?(channelProp=requireInterop?"main":transferId,peerConnectionStateCbFn=function(){returnErrorBeforeTransferFn("Data transfer terminated as Peer connection is not stable.")},self.once("peerConnectionState",peerConnectionStateCbFn,function(state,evtPeerId){return self._dataTransfers[transferId]?state!==self.PEER_CONNECTION_STATE.STABLE&&evtPeerId===peerId:void self.off("peerConnectionState",peerConnectionStateCbFn)}),requireInterop):(requireInterop||"main"===channelProp)&&self._dataChannels[peerId].main.transferId?void returnErrorBeforeTransferFn("Unable to start data transfer as Peer Datachannel has a data transfer in-progress."):(self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0},dataChannelStateCbFn=function(state,evtPeerId,error){self._dataTransfers[transferId].sessions[peerId].ackN>=self._dataTransfers[transferId].chunks.length-1||returnErrorBeforeTransferFn(error?error.message||error.toString():"Data transfer terminated as Peer Datachannel connection closed abruptly.")},self.once("dataChannelState",dataChannelStateCbFn,function(state,evtPeerId,error,channelName,channelType){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"===AdapterJS.webrtcDetectedBrowser?16384:65546:"firefox"===AdapterJS.webrtcDetectedBrowser?self._MOZ_BINARY_FILE_SIZE:self._BINARY_FILE_SIZE))))},Skylink.prototype._getTransferInfo=function(transferId,peerId,returnDataProp,hidePercentage,returnDataAtStart){if(!this._dataTransfers[transferId])return{};var transferInfo={name:this._dataTransfers[transferId].name,size:this._dataTransfers[transferId].size,dataType:this._dataTransfers[transferId].dataType||this.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:this._dataTransfers[transferId].mimeType||null,chunkSize:this._dataTransfers[transferId].chunkSize,chunkType:this._dataTransfers[transferId].chunkType,timeout:this._dataTransfers[transferId].timeout,isPrivate:this._dataTransfers[transferId].isPrivate,direction:this._dataTransfers[transferId].direction};if(this._dataTransfers[transferId].originalSize?transferInfo.size=this._dataTransfers[transferId].originalSize:this._dataTransfers[transferId].chunkType===this.DATA_TRANSFER_DATA_TYPE.BINARY_STRING&&(transferInfo.size=Math.ceil(3*transferInfo.size/4)),!hidePercentage){if(transferInfo.percentage=0,!this._dataTransfers[transferId].sessions[peerId])return returnDataProp&&(transferInfo.data=null),transferInfo;if(this._dataTransfers[transferId].direction===this.DATA_TRANSFER_TYPE.DOWNLOAD)this._dataTransfers[transferId].sessions[peerId].receivedSize===this._dataTransfers[transferId].sessions[peerId].size?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].receivedSize/this._dataTransfers[transferId].size*100).toFixed(2),10);else{var chunksLength=this._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?this._dataTransfers[transferId].enforceBSInfo.chunks.length:this._dataTransfers[transferId].chunks.length;this._dataTransfers[transferId].sessions[peerId].ackN===chunksLength?transferInfo.percentage=100:transferInfo.percentage=parseFloat((this._dataTransfers[transferId].sessions[peerId].ackN/chunksLength*100).toFixed(2),10)}returnDataProp&&("number"!=typeof returnDataAtStart?100===transferInfo.percentage?transferInfo.data=this._getTransferData(transferId):transferInfo.data=null:(transferInfo.percentage=returnDataAtStart,0===returnDataAtStart&&(transferInfo.data=this._getTransferData(transferId))))}return transferInfo},Skylink.prototype._getTransferData=function(transferId){if(!this._dataTransfers[transferId])return null;if(this._dataTransfers[transferId].dataType===this.DATA_TRANSFER_SESSION_TYPE.BLOB){var mimeType={name:this._dataTransfers[transferId].name};return this._dataTransfers[transferId].mimeType&&(mimeType.type=this._dataTransfers[transferId].mimeType),new Blob(this._dataTransfers[transferId].chunks,mimeType)}return this._dataTransfers[transferId].chunks.join("")},Skylink.prototype._handleDataTransferTimeoutForPeer=function(transferId,peerId,setPeerTO){var self=this;if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer does not exists for Peer. Ignoring timeout."]);log.debug([peerId,"RTCDataChannel",transferId,"Clearing data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer&&clearTimeout(self._dataTransfers[transferId].sessions[peerId].timer),self._dataTransfers[transferId].sessions[peerId].timer=null,setPeerTO&&(log.debug([peerId,"RTCDataChannel",transferId,"Setting data transfer timer for Peer."]),self._dataTransfers[transferId].sessions[peerId].timer=setTimeout(function(){if(!self._dataTransfers[transferId]||!self._dataTransfers[transferId].sessions[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Data transfer already ended for Peer. Ignoring expired timeout."]);if(!self._user||!self._user.sid)return void log.debug([peerId,"RTCDataChannel",transferId,"User is not in Room. Ignoring expired timeout."]);if(!self._dataChannels[peerId])return void log.debug([peerId,"RTCDataChannel",transferId,"Datachannel connection does not exists. Ignoring expired timeout."]);log.error([peerId,"RTCDataChannel",transferId,"Data transfer response has timed out."]);var emitEventFn=function(cb){if("MCU"===peerId){for(var broadcastedPeers=[self._dataTransfers[transferId].peers.main,self._dataTransfers[transferId].peers[transferId]],i=0;i"],rawData);if(!self._dataChannels[peerId]||!self._dataChannels[peerId][channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping data received from Peer as Datachannel connection is not present ->"],rawData);if("string"==typeof rawData)try{var protocolData=JSON.parse(rawData);if(isStreamChunk=!1,log.debug([peerId,"RTCDataChannel",channelProp,'Received protocol "'+protocolData.type+'" message ->'],protocolData),[self._DC_PROTOCOL_TYPE.ACK,self._DC_PROTOCOL_TYPE.ERROR,self._DC_PROTOCOL_TYPE.CANCEL].indexOf(protocolData.type)>-1&&!(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded protocol message as data transfer session is not present ->"],protocolData);switch(protocolData.type){case self._DC_PROTOCOL_TYPE.WRQ:if(transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId])return log.warn([peerId,"RTCDataChannel",channelProp,"Rejecting bidirectional data transfer request as it is currently not supported in the SDK ->"],protocolData),void self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,ackN:-1,sender:self._user.sid},channelProp);self._WRQProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ACK:self._ACKProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.ERROR:self._ERRORProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.CANCEL:self._CANCELProtocolHandler(peerId,protocolData,channelProp);break;case self._DC_PROTOCOL_TYPE.MESSAGE:self._MESSAGEProtocolHandler(peerId,protocolData,channelProp);break
-;default:log.warn([peerId,"RTCDataChannel",channelProp,'Discarded unknown "'+protocolData.type+'" message ->'],protocolData)}}catch(error){if(rawData.indexOf("{")>-1&&rawData.indexOf("}")>0)throw log.error([peerId,"RTCDataChannel",channelProp,"Failed parsing protocol step data error ->"],{data:rawData,error:error}),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(peerId,channelProp)),error;if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING;if(isStreamChunk||self._dataTransfers[transferId].dataType===self.DATA_TRANSFER_SESSION_TYPE.DATA_URL)log.debug([peerId,"RTCDataChannel",channelProp,"Received string data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.length||rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.STRING,rawData.length||rawData.size||0,channelProp);else{var removeSpaceData=rawData.replace(/\s|\r|\n/g,"");log.debug([peerId,"RTCDataChannel",channelProp,"Received binary string data chunk @"+self._dataTransfers[transferId].sessions[peerId].ackN+" with size ->"],removeSpaceData.length||removeSpaceData.size),self._DATAProtocolHandler(peerId,self._base64ToBlob(removeSpaceData),self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,removeSpaceData.length||removeSpaceData.size||0,channelProp)}}else{if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);if(rawData instanceof Blob)log.debug([peerId,"RTCDataChannel",channelProp,"Received blob data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.BLOB,rawData.size,channelProp);else{var byteArray=rawData,blob=null;if(rawData.constructor&&"Array"===rawData.constructor.name&&(byteArray=new Int8Array(rawData)),"IE"===AdapterJS.webrtcDetectedBrowser){if(window.BlobBuilder){var bb=new BlobBuilder;bb.append(rawData.constructor&&"ArrayBuffer"===rawData.constructor.name?byteArray:new Uint8Array(byteArray).buffer),blob=bb.getBlob()}}else blob=new Blob([byteArray]);log.debug([peerId,"RTCDataChannel",channelProp,"Received arraybuffer data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],blob.size),self._DATAProtocolHandler(peerId,blob,self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,blob.size,channelProp)}}},Skylink.prototype._WRQProtocolHandler=function(peerId,data,channelProp){var self=this,transferId="main"===channelProp?data.transferId||null:channelProp,senderPeerId=data.sender||peerId;if(["fastBinaryStart","fastBinaryStop"].indexOf(data.dataType)>-1)if("fastBinaryStart"===data.dataType){transferId||(transferId="stream_"+peerId+"_"+(new Date).getTime()),self._dataStreams[transferId]={chunkSize:0,chunkType:"string"===data.chunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:data.chunkType,isPrivate:!!data.isPrivate,isStringStream:"string"===data.chunkType,senderPeerId:senderPeerId,isUpload:!1},self._dataChannels[peerId][channelProp].streamId=transferId;self.once("dataChannelState",function(){},function(state,evtPeerId,channelName,channelType,error){if(!self._dataStreams[transferId])return!0;if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId&&channelType===self.DATA_CHANNEL_TYPE.DATA)&&[self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');return self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},updatedError),!0}}),self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STARTED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStarted",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1)}else transferId=self._dataChannels[peerId][channelProp].streamId,self._dataStreams[transferId]&&!self._dataStreams[transferId].isUpload&&(self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STOPPED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStopped",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1),self._dataChannels[peerId][channelProp].streamId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp),delete self._dataStreams[transferId]);else transferId||(transferId="transfer_"+peerId+"_"+(new Date).getTime()),self._dataTransfers[transferId]={name:data.name||transferId,size:data.size||0,chunkSize:data.chunkSize,originalSize:data.originalSize||0,timeout:data.timeout||60,isPrivate:!!data.isPrivate,senderPeerId:data.sender||peerId,dataType:self.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:data.mimeType||null,chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,direction:self.DATA_TRANSFER_TYPE.DOWNLOAD,chunks:[],sessions:{},sessionType:data.dataType||"blob",sessionChunkType:data.chunkType||"string"},"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?(self._dataTransfers[transferId].dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,self._dataTransfers[transferId].chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING):"blob"===self._dataTransfers[transferId].sessionType&&"binary"===self._dataTransfers[transferId].sessionChunkType&&(self._dataTransfers[transferId].chunkType=self._binaryChunkType),self._dataChannels[peerId][channelProp].transferId=transferId,self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0,receivedSize:0},self._trigger("incomingDataRequest",transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!1),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_REQUEST,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)},Skylink.prototype._ACKProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ACK event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};if(data.ackN>-1){if(0===data.ackN)emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_STARTED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,0),null)});else if(self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?data.ackN===self._dataTransfers[transferId].enforceBSInfo.chunks.length:data.ackN===self._dataTransfers[transferId].chunks.length)return self._dataTransfers[transferId].sessions[peerId].ackN=data.ackN,emitEventFn(function(evtPeerId){self._trigger("incomingData",self._getTransferData(transferId),transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,100),null)}),void(self._dataChannels[peerId][channelProp]&&(self._dataChannels[peerId][channelProp].transferId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp)));var uploadFn=function(chunk){self._sendMessageToDataChannel(peerId,chunk,channelProp,!0),data.ackN-1?self._blobToBase64(self._dataTransfers[transferId].enforceBSInfo.chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING?self._blobToBase64(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER?self._blobToArrayBuffer(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):uploadFn(self._dataTransfers[transferId].chunks[data.ackN])}else self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.REJECTED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as Peer has rejected data transfer request"),transferType:self.DATA_TRANSFER_TYPE.UPLOAD})},Skylink.prototype._MESSAGEProtocolHandler=function(peerId,data,channelProp){var senderPeerId=data.sender||peerId;log.log([senderPeerId,"RTCDataChannel",channelProp,"Received P2P message from peer:"],data),this._trigger("incomingMessage",{content:data.data,isPrivate:data.isPrivate,isDataChannel:!0,targetPeerId:this._user.sid,senderPeerId:senderPeerId},senderPeerId,this.getPeerInfo(senderPeerId),!1)},Skylink.prototype._ERRORProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ERROR event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,evtPeerId,self._getTransferInfo(transferId,peerID,!0,!1,!1),{message:new Error(data.content),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._CANCELProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of CANCEL event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(peerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.CANCEL,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error(data.content||"Peer has terminated data transfer."),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._DATAProtocolHandler=function(peerId,chunk,chunkType,chunkSize,channelProp){var self=this,transferId=channelProp,senderPeerId=peerId;if(self._dataChannels[peerId]&&self._dataChannels[peerId][channelProp]){var streamId=self._dataChannels[peerId][channelProp].streamId;if(streamId&&self._dataStreams[streamId]&&("string"==typeof chunk&&"string"===self._dataStreams[streamId].sessionChunkType||chunk instanceof Blob&&"binary"===self._dataStreams[streamId].sessionChunkType))return senderPeerId=self._dataStreams[streamId].senderPeerId||peerId,self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVED,streamId,senderPeerId,{chunk:chunk,chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},null),void self._trigger("incomingDataStream",chunk,transferId,senderPeerId,{chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},!1);if("main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._dataTransfers[transferId].senderPeerId&&(senderPeerId=self._dataTransfers[transferId].senderPeerId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1),self._dataTransfers[transferId].chunkType=chunkType,self._dataTransfers[transferId].sessions[peerId].receivedSize+=chunkSize,self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN]=chunk,self._dataTransfers[transferId].sessions[peerId].receivedSize>=self._dataTransfers[transferId].size)return log.log([peerId,"RTCDataChannel",channelProp,"Data transfer has been completed. Computed size ->"],self._dataTransfers[transferId].sessions[peerId].receivedSize),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN+1},channelProp),self._trigger("incomingData",self._getTransferData(transferId),transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),null),void self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null);self._dataTransfers[transferId].sessions[peerId].ackN+=1,self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN},channelProp),self._handleDataTransferTimeoutForPeer(transferId,peerId,!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOADING,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)}},Skylink.prototype.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._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,userInfo:self._getUserInfo(targetMid),target:targetMid,rid:self._room.id})}}},Skylink.prototype._addIceCandidateToQueue=function(targetMid,canId,candidate){var candidateType=candidate.candidate.split(" ")[7];log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Buffering ICE candidate."]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.BUFFERED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[],this._peerCandidatesQueue[targetMid].push([canId,candidate])},Skylink.prototype._addIceCandidateFromQueue=function(targetMid){this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[];for(var i=0;i"],error),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},error)};if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Adding ICE candidate."]),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESSING,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[targetMid].remoteDescription&&self._peerConnections[targetMid].remoteDescription.sdp&&self._peerConnections[targetMid].remoteDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),void self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed."));try{self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)}catch(error){onErrorCbFn(error)}},Skylink.prototype.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&&("firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion<53?useTURNSSLPort=!0:useTURNSSLProtocol=!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]=[]),-1===iceServersList[username][credential].indexOf(url)&&("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"===AdapterJS.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"===AdapterJS.webrtcDetectedBrowser&&pushIceServer("none","none","stun:stun.services.mozilla.com",0);var hasUrlsSupport="chrome"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>34||"firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>38||"opera"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion>31||["plugin","AppleWebKit"].indexOf(AdapterJS.webrtcDetectedType)>-1||["bowser","edge"].indexOf(AdapterJS.webrtcDetectedBrowser)>-1;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"===AdapterJS.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}))}},refreshSinglePeer=function(peerId,peerCallback){if(!self._peerConnections[peerId])return error="There is currently no existing peer connection made with the peer. Unable to restart connection",log.error([peerId,null,null,error]),void peerCallback(error);log.log([peerId,"PeerConnection",null,"Restarting peer connection"]),self._restartPeerConnection(peerId,doIceRestart,bwOptions,peerCallback)};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?refreshSinglePeer(peerId,refreshSinglePeerCallback(peerId)):(error="Peer connection with peer does not exists. Unable to restart",log.error([peerId,"PeerConnection",null,error]),refreshSinglePeerCallback(peerId)(error))}}},Skylink.prototype.getConnectionStatus=function(targetPeerId,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),listOfPeerStats={},listOfPeerErrors={};if(Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId&&targetPeerId?listOfPeers=[targetPeerId]:"function"==typeof targetPeerId&&(callback=targetPeerId,targetPeerId=void 0),0===listOfPeers.length)return listOfPeerErrors.self=new Error("There is currently no peer connections to retrieve connection status"),log.error([null,"RTCStatsReport",null,"Retrieving request failure ->"],listOfPeerErrors.self),void("function"==typeof callback&&callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null));"edge"===AdapterJS.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){-1===completedTaskCounter.indexOf(peerId)&&completedTaskCounter.push(peerId),completedTaskCounter.length===listOfPeers.length&&"function"==typeof callback&&(Object.keys(listOfPeerErrors).length>0?callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null):callback(null,{listOfPeers:listOfPeers,connectionStats:listOfPeerStats}))},statsFn=function(peerId){var retrieveFn=function(firstRetrieval,nextCb){return function(err,result){if(err)return log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],error),listOfPeerErrors[peerId]=error,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,error),checkCompletedFn(peerId),void(firstRetrieval&&delete self._peerStats[peerId]);firstRetrieval?nextCb():(listOfPeerStats[peerId]=result,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_SUCCESS,peerId,listOfPeerStats[peerId],null),checkCompletedFn(peerId))}};if(!self._peerStats[peerId])return self._peerStats[peerId]={},log.debug([peerId,"RTCStatsReport",null,"Retrieving first report to tabulate results"]),void self._retrieveStats(peerId,retrieveFn(!0,function(){self._retrieveStats(peerId,retrieveFn())}),!0);self._retrieveStats(peerId,retrieveFn())},i=0;i"],listOfPeerErrors[peerId]),self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,listOfPeerErrors[peerId]),checkCompletedFn(peerId))}},Skylink.prototype._retrieveStats=function(peerId,callback,beSilentOnLogs,isAutoBwStats){var self=this,pc=self._peerConnections[peerId],output={raw:{},connection:{},audio:{sending:{},receiving:{}},video:{sending:{},receiving:{}},selectedCandidate:{local:{},remote:{},consentResponses:{},consentRequests:{},responses:{},requests:{}},certificate:{}};if(!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));if(!pc)return callback(new Error("Peer connection is not initialised"));"edge"!==AdapterJS.webrtcDetectedBrowser&&"AppleWebKit"!==AdapterJS.webrtcDetectedType||log.warn("Current connection stats may not be complete as it is in beta"),output.connection.iceConnectionState=pc.iceConnectionState,output.connection.iceGatheringState=pc.iceGatheringState,output.connection.signalingState=pc.signalingState,output.connection.remoteDescription={type:pc.remoteDescription&&pc.remoteDescription.type||"",sdp:pc.remoteDescription&&pc.remoteDescription.sdp||""},output.connection.localDescription={type:pc.localDescription&&pc.localDescription.type||"",sdp:pc.localDescription&&pc.localDescription.sdp||""},output.connection.candidates={sending:self._getSDPICECandidates(peerId,pc.localDescription,beSilentOnLogs),receiving:self._getSDPICECandidates(peerId,pc.remoteDescription,beSilentOnLogs)},output.connection.dataChannels={},output.connection.constraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,output.connection.optional=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,output.connection.sdpConstraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null,output.audio.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),output.video.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),output.audio.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"audio",beSilentOnLogs),output.video.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"video",beSilentOnLogs),output.certificate.local=self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),output.certificate.remote=self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs);var inboundSSRCs=self._getSDPMediaSSRC(peerId,pc.remoteDescription,beSilentOnLogs);output.audio.receiving.ssrc=inboundSSRCs.audio,output.video.receiving.ssrc=inboundSSRCs.video;var outboundSSRCs=self._getSDPMediaSSRC(peerId,pc.localDescription,beSilentOnLogs);output.audio.sending.ssrc=outboundSSRCs.audio,output.video.sending.ssrc=outboundSSRCs.video,Object.keys(self._dataChannels[peerId]||{}).forEach(function(prop){var channel=self._dataChannels[peerId][prop];output.connection.dataChannels[channel.channel.label]={label:channel.channel.label,readyState:channel.channel.readyState,channelType:self.DATA_CHANNEL_TYPE["main"===prop?"MESSAGING":"DATA"],currentTransferId:channel.transferId||null,currentStreamId:channel.streamId||null}});var certificateFn=function(item,prop){if(0===prop.indexOf("RTCCertificate_"))item.fingerprint===output.certificate.local.fingerprint?(output.certificate.local.derBase64=item.base64Certificate,output.certificate.local.fingerprintAlgorithm=item.fingerprintAlgorithm):item.fingerprint===output.certificate.remote.fingerprint&&(output.certificate.remote.derBase64=item.base64Certificate,output.certificate.remote.fingerprintAlgorithm=item.fingerprintAlgorithm);else if(0===prop.indexOf("ssrc_")&&item.transportId){var pairItem=output.raw[item.transportId]||{};output.certificate.srtpCipher=pairItem.srtpCipher,output.certificate.dtlsCipher=pairItem.dtlsCipher;var localCertItem=output.raw[pairItem.localCertificateId||""]||{};output.certificate.local.fingerprint=localCertItem.googFingerprint,output.certificate.local.fingerprintAlgorithm=localCertItem.googFingerprintAlgorithm,output.certificate.local.derBase64=localCertItem.googDerBase64;var remoteCertItem=output.raw[pairItem.remoteCertificateId||""]||{};output.certificate.remote.fingerprint=remoteCertItem.googFingerprint,output.certificate.remote.fingerprintAlgorithm=remoteCertItem.googFingerprintAlgorithm,output.certificate.remote.derBase64=remoteCertItem.googDerBase64}},candidatePairFn=function(item,prop){if(0===prop.indexOf("RTCIceCandidatePair_")){if("succeeded"!==item.state||output.selectedCandidate.nominated||item.prioirty<(output.selectedCandidate.priority||0))return;for(var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],sending=pc.localDescription&&pc.localDescription.sdp&&pc.localDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],receiving=pc.remoteDescription&&pc.remoteDescription&&pc.remoteDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],computePrioirtyFn=function(controller,controlled){return Math.pow(2,32)*Math.min(controller,controlled)+2*Math.max(controller,controlled)+(controller>controlled?1:0)},computeCanTypeFn=function(type){return"relay"===type?"relayed":"host"===type?"local":"srflx"===type?"serverreflexive":type},s=0;s0?"sending":"receiving";item.codecImplementationName="unknown"===item.codecImplementationName?null:item.codecImplementationName,output[item.mediaType][direction].codec.implementation=item.codecImplementationName||null,item.googCodecName="unknown"===item.googCodecName?null:item.googCodecName,output[item.mediaType][direction].codec.name=item.googCodecName||output[item.mediaType][direction].codec.name}},audioStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPAudioStream")){if(output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.audio.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),"function"!=typeof pc.getReceivers)return}else if(0===prop.indexOf("RTCMediaStreamTrack_remote_audio_"))output.audio.receiving.audioOutputLevel=item.audioLevel;else if(0===prop.indexOf("RTCOutboundRTPAudioStream"))output.audio.sending.targetBitrate=item.targetBitrate||0,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"audio"===item.mediaType&&item.isRemote)output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"audio"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"audio"===item.mediaType)if(prop.indexOf("_recv")>0){output.audio.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.audio.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.audio.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.audio.receiving.totalBytes=bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.audio.receiving.totalPackets=packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.audio.receiving.totalPacketsLost=packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost")}else{output.audio.sending.rtt=parseInt(item.googRtt||"0",10),output.audio.sending.audioInputLevel=parseInt(item.audioInputLevel||"0",10),output.audio.sending.echoReturnLoss=parseInt(item.googEchoCancellationReturnLoss||"0",10),output.audio.sending.echoReturnLossEnhancement=parseInt(item.googEchoCancellationReturnLossEnhancement||"0",10);var bytesSent=parseInt(item.bytesSent||"0",10);output.audio.sending.totalBytes=bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.audio.sending.totalPackets=packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent")}else if(0===prop.indexOf("inbound_rtp_audio"))output.audio.receiving.jitter=item.jitter||0,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if(0===prop.indexOf("outbound_rtp_audio")){output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.audio.sending.rtt=rtcpItem.roundTripTime||0}}else{output.audio.sending.targetBitrate=item.targetBitrate,output.audio.sending.rtt=item.roundTripTime,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.audio.sending.audioInputLevel=trackItem.audioLevel,output.audio.sending.echoReturnLoss=trackItem.echoReturnLoss,output.audio.sending.echoReturnLossEnhancement=trackItem.echoReturnLossEnhancement}},videoStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPVideoStream"))output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.framesDecoded=item.framesDecoded,output.video.receiving.qpSum=item.qpSum,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.video.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if(0===prop.indexOf("RTCMediaStreamTrack_remote_video_"))output.video.receiving.frameHeight=item.frameHeight,output.video.receiving.frameWidth=item.frameWidth,output.video.receiving.framesCorrupted=item.framesCorrupted,output.video.receiving.framesPerSecond=item.framesPerSecond,output.video.receiving.framesDropped=item.framesDropped,output.video.receiving.totalFrames=item.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,item,"framesReceived");else if(0===prop.indexOf("RTCOutboundRTPVideoStream"))output.video.sending.qpSum=item.qpSum,output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"video"===item.mediaType&&item.isRemote){output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.receiving.framesCorrupted=trackItem.framesCorrupted,output.video.receiving.framesDropped=trackItem.framesDropped,output.video.receiving.framesDecoded=trackItem.framesDecoded,output.video.receiving.totalFrames=trackItem.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,trackItem,"framesReceived")}else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"video"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType)if(prop.indexOf("_recv")>0){output.video.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.video.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.video.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10),output.video.receiving.renderDelayMs=parseInt(item.googRenderDelayMs||"0",10),output.video.receiving.frameWidth=parseInt(item.googFrameWidthReceived||"0",10),output.video.receiving.frameHeight=parseInt(item.googFrameHeightReceived||"0",10),output.video.receiving.framesDecoded=parseInt(item.framesDecoded||"0",10),output.video.receiving.frameRateOutput=parseInt(item.googFrameRateOutput||"0",10),output.video.receiving.frameRateDecoded=parseInt(item.googFrameRateDecoded||"0",10),output.video.receiving.frameRateReceived=parseInt(item.googFrameRateReceived||"0",10),output.video.receiving.qpSum=parseInt(item.qpSum||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.video.receiving.totalBytes=bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.video.receiving.totalPackets=packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.video.receiving.totalPacketsLost=packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost");var nacksSent=parseInt(item.googNacksSent||"0",10);output.video.receiving.totalNacks=nacksSent,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"googNacksSent");var plisSent=parseInt(item.googPlisSent||"0",10);output.video.receiving.totalPlis=plisSent,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"googPlisSent");var firsSent=parseInt(item.googFirsSent||"0",10);output.video.receiving.totalFirs=firsSent,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"googFirsSent")}else{output.video.sending.rtt=parseInt(item.googRtt||"0",10),output.video.sending.frameWidth=parseInt(item.googFrameWidthSent||"0",10),output.video.sending.frameHeight=parseInt(item.googFrameHeightSent||"0",10),output.video.sending.framesEncoded=parseInt(item.framesEncoded||"0",10),output.video.sending.frameRateInput=parseInt(item.googFrameRateInput||"0",10),output.video.sending.frameRateEncoded=parseInt(item.googFrameRateEncoded||"0",10),output.video.sending.frameRateSent=parseInt(item.googFrameRateSent||"0",10),output.video.sending.cpuLimitedResolution="true"===item.googCpuLimitedResolution,output.video.sending.bandwidthLimitedResolution="true"===item.googBandwidthLimitedResolution;var bytesSent=parseInt(item.bytesSent||"0",10);output.video.sending.totalBytes=bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.video.sending.totalPackets=packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent");var nacksReceived=parseInt(item.googNacksReceived||"0",10);output.video.sending.totalNacks=nacksReceived,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"googNacksReceived");var plisReceived=parseInt(item.googPlisReceived||"0",10);output.video.sending.totalPlis=plisReceived,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"googPlisReceived");var firsReceived=parseInt(item.googFirsReceived||"0",10);output.video.sending.totalFirs=firsReceived,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"googFirsReceived")}else if(0===prop.indexOf("inbound_rtp_video"))output.video.receiving.jitter=item.jitter||0,output.video.receiving.framesDecoded=item.framesDecoded||0,output.video.receiving.frameRateMean=item.framerateMean||0,output.video.receiving.frameRateStdDev=item.framerateStdDev||0,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount");else if(0===prop.indexOf("outbound_rtp_video")){output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.frameRateMean=item.framerateMean||0,output.video.sending.frameRateStdDev=item.framerateStdDev||0,output.video.sending.framesDropped=item.droppedFrames||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.video.sending.rtt=rtcpItem.roundTripTime||0}}else{output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.roundTripTime=item.roundTripTime||0,
-output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.sending.frameHeight=trackItem.frameHeight,output.video.sending.frameWidth=trackItem.frameWidth,output.video.sending.framesPerSecond=trackItem.framesPerSecond,output.video.sending.totalFrames=trackItem.framesSent,output.video.sending.frames=self._parseConnectionStats(prevStats,trackItem,"framesSent")}},videoE2EStatsFn=function(item,prop){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType){var captureStartNtpTimeMs=parseInt(item.googCaptureStartNtpTimeMs||"0",10),remoteStream=pc.getRemoteStreams()[0];if(!(captureStartNtpTimeMs>0&&prop.indexOf("_recv")>0&&remoteStream&&document&&"function"==typeof document.getElementsByTagName))return;try{var elements=document.getElementsByTagName("plugin"===AdapterJS.webrtcDetectedType?"object":"video");"plugin"!==AdapterJS.webrtcDetectedType&&0===elements.length&&(elements=document.getElementsByTagName("audio"));for(var e=0;e0))break;for(var ec=0;ec"],error)}}},successCbFn=function(stats){"function"==typeof stats.forEach?stats.forEach(function(item,prop){output.raw[prop]=item}):output.raw=stats;var edgeTracksKind={remote:{},local:{}};"edge"===AdapterJS.webrtcDetectedBrowser&&(pc.remoteStream&&pc.remoteStream.getTracks().forEach(function(track){edgeTracksKind.remote[track.id]=track.kind}),pc.localStream&&pc.localStream.getTracks().forEach(function(track){edgeTracksKind.local[track.id]=track.kind})),Object.keys(output.raw).forEach(function(prop){if(0!==prop.indexOf("ssrc_")||output.raw[prop].mediaType){if("edge"===AdapterJS.webrtcDetectedBrowser&&!output.raw[prop].mediaType&&["inboundrtp","outboundrtp"].indexOf(output.raw[prop].type)>-1){var trackItem=output.raw[output.raw[prop].mediaTrackId]||{};output.raw[prop].mediaType=edgeTracksKind[output.raw[prop].isRemote?"remote":"local"][trackItem.trackIdentifier]||""}}else output.raw[prop].mediaType=output.raw[prop].audioInputLevel||output.raw[prop].audioOutputLevel?"audio":"video";certificateFn(output.raw[prop],prop),candidatePairFn(output.raw[prop],prop),codecsFn(output.raw[prop],prop),audioStatsFn(output.raw[prop],prop),videoStatsFn(output.raw[prop],prop),videoE2EStatsFn(output.raw[prop],prop),isAutoBwStats&&!self._peerBandwidth[peerId][prop]?self._peerBandwidth[peerId][prop]=output.raw[prop]:isAutoBwStats||self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=output.raw[prop])}),output.audio.sending.bytes=output.audio.sending.bytes||0,output.audio.sending.packets=output.audio.sending.packets||0,output.audio.sending.totalBytes=output.audio.sending.totalBytes||0,output.audio.sending.totalPackets=output.audio.sending.totalPackets||0,output.video.sending.bytes=output.video.sending.bytes||0,output.video.sending.packets=output.video.sending.packets||0,output.video.sending.totalBytes=output.video.sending.totalBytes||0,output.video.sending.totalPackets=output.video.sending.totalPackets||0,output.audio.receiving.bytes=output.audio.receiving.bytes||0,output.audio.receiving.packets=output.audio.receiving.packets||0,output.audio.receiving.totalBytes=output.audio.receiving.totalBytes||0,output.audio.receiving.totalPackets=output.audio.receiving.totalPackets||0,output.video.receiving.bytes=output.video.receiving.bytes||0,output.video.receiving.packets=output.video.receiving.packets||0,output.video.receiving.totalBytes=output.video.receiving.totalBytes||0,output.video.receiving.totalPackets=output.video.receiving.totalPackets||0,callback(null,output)},errorCbFn=function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)};if("function"!=typeof pc.getStats)return errorCbFn(new Error("getStats() API is not available."));"plugin"===AdapterJS.webrtcDetectedType?pc.getStats(null,successCbFn,errorCbFn):pc.getStats(null).then(successCbFn).catch(errorCbFn)},Skylink.prototype._addPeer=function(targetMid,cert,peerBrowser,receiveOnly,isSS){var self=this;return self._peerConnections[targetMid]?void log.error([targetMid,null,null,"Connection to peer has already been made"]):(self._peerConnStatus[targetMid]={connected:!1,init:!1},log.log([targetMid,null,null,"Starting the connection to peer. Options provided:"],{peerBrowser:peerBrowser,receiveOnly:receiveOnly,enableDataChannel:self._enableDataChannel}),log.info("Adding peer",isSS),self._peerConnections[targetMid]=self._createPeerConnection(targetMid,!!isSS,cert),self._peerConnections[targetMid]?(self._peerConnStatus[targetMid].init=!0,void(self._peerConnections[targetMid].hasScreen=!!isSS)):void log.error([targetMid,null,null,"Failed creating the connection to peer."]))},Skylink.prototype._restartPeerConnection=function(peerId,doIceRestart,bwOptions,callback){var self=this;if(!self._peerConnections[peerId])return void log.error([peerId,null,null,"Peer does not have an existing connection. Unable to restart"]);var pc=self._peerConnections[peerId],agent=(self.getPeerInfo(peerId)||{}).agent||{};if(self._isLowerThanVersion(agent.SMProtocolVersion||"","0.1.2")){var notSupportedError=new Error("Failed restarting with other agents connecting from other SDKs as re-negotiation is not supported by other SDKs");return log.warn([peerId,"RTCPeerConnection",null,"Ignoring restart request as agent's SDK does not support it"],notSupportedError),void("function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(notSupportedError)))}if(pc.signalingState===self.PEER_CONNECTION_STATE.STABLE&&self._peerConnections[peerId]){log.log([peerId,null,null,"Sending restart message to signaling server ->"],{iceRestart:doIceRestart,options:bwOptions}),self._peerCustomConfigs[peerId]=self._peerCustomConfigs[peerId]||{},self._peerCustomConfigs[peerId].bandwidth=self._peerCustomConfigs[peerId].bandwidth||{},self._peerCustomConfigs[peerId].googleXBandwidth=self._peerCustomConfigs[peerId].googleXBandwidth||{},bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._peerCustomConfigs[peerId].bandwidth.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._peerCustomConfigs[peerId].bandwidth.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._peerCustomConfigs[peerId].bandwidth.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._peerCustomConfigs[peerId].googleXBandwidth.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._peerCustomConfigs[peerId].googleXBandwidth.max=bwOptions.googleXBandwidth.max));var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===doIceRestart&&self._enableIceRestart&&self._peerInformations[peerId]&&self._peerInformations[peerId].config.enableIceRestart,isRestartResend:!1,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._peerEndOfCandidatesCounter[peerId]=self._peerEndOfCandidatesCounter[peerId]||{},self._peerEndOfCandidatesCounter[peerId].len=0,self._sendChannelMessage(restartMsg),self._trigger("peerRestart",peerId,self.getPeerInfo(peerId),!0,!0===doIceRestart),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart callback"]),callback(null))}else if(pc.signalingState===self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER){var hasLocalDescription=pc.localDescription&&pc.localDescription.sdp;if(hasLocalDescription)self._sendChannelMessage({type:pc.localDescription.type,sdp:pc.localDescription.sdp,mid:self._user.sid,target:peerId,rid:self._room.id,restart:!0});else{var noLocalDescriptionError="Failed re-sending localDescription as there is no localDescription set to connection. There could be a handshaking step error";log.error([peerId,"RTCPeerConnection",null,noLocalDescriptionError],{localDescription:pc.localDescription,remoteDescription:pc.remoteDescription}),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(noLocalDescriptionError)))}}else{var unableToRestartError="Failed restarting as peer connection state is "+pc.signalingState;log.warn([peerId,"RTCPeerConnection",null,unableToRestartError]),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(unableToRestartError)))}},Skylink.prototype._removePeer=function(peerId){if(!this._peerConnections[peerId]&&!this._peerInformations[peerId])return void log.debug([peerId,"RTCPeerConnection",null,"Dropping the hangup from Peer as not connected to Peer at all."]);var peerInfo=clone(this.getPeerInfo(peerId))||{userData:"",settings:{audio:!1,video:!1,data:!1},mediaStatus:{audioMuted:!0,videoMuted:!0},agent:{name:"unknown",version:0,os:"",pluginVersion:null},config:{enableDataChannel:!0,enableIceRestart:!1,enableIceTrickle:!0,priorityWeight:0,publishOnly:!1,receiveOnly:!0},parentId:null,room:clone(this._selectedRoom)};"MCU"!==peerId?this._trigger("peerLeft",peerId,peerInfo,!1):(this._hasMCU=!1,log.log([peerId,null,null,"MCU has stopped listening and left"]),this._trigger("serverPeerLeft",peerId,this.SERVER_PEER_TYPE.MCU)),this._peerConnections[peerId]&&(this._peerConnections[peerId].signalingState!==this.PEER_CONNECTION_STATE.CLOSED&&(this._peerConnections[peerId].close(),"AppleWebKit"===AdapterJS.webrtcDetectedType&&(this._peerConnections[peerId].signalingStateClosed||(this._peerConnections[peerId].signalingStateClosed=!0,this._trigger("peerConnectionState",this.PEER_CONNECTION_STATE.CLOSED,peerId)),this._peerConnections[peerId].iceConnectionStateClosed||(this._peerConnections[peerId].iceConnectionStateClosed=!0,this._trigger("iceConnectionState",this.ICE_CONNECTION_STATE.CLOSED,peerId)))),"MCU"!==peerId&&this._handleEndedStreams(peerId),delete this._peerConnections[peerId]),this._peerInformations[peerId]&&delete this._peerInformations[peerId],this._peerMessagesStamps[peerId]&&delete this._peerMessagesStamps[peerId],this._streamsSession[peerId]&&delete this._streamsSession[peerId],this._peerEndOfCandidatesCounter[peerId]&&delete this._peerEndOfCandidatesCounter[peerId],this._peerCandidatesQueue[peerId]&&delete this._peerCandidatesQueue[peerId],this._sdpSessions[peerId]&&delete this._sdpSessions[peerId],this._peerStats[peerId]&&delete this._peerStats[peerId],this._peerBandwidth[peerId]&&delete this._peerBandwidth[peerId],this._gatheredCandidates[peerId]&&delete this._gatheredCandidates[peerId],this._peerCustomConfigs[peerId]&&delete this._peerCustomConfigs[peerId],this._peerConnStatus[peerId]&&delete this._peerConnStatus[peerId],this._dataChannels[peerId]&&this._closeDataChannel(peerId),log.log([peerId,"RTCPeerConnection",null,"Successfully removed peer"])},Skylink.prototype._createPeerConnection=function(targetMid,isScreenSharing,cert){var pc,self=this;if(self._inRoom&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)){var constraints={iceServers:self._room.connection.peerConfig.iceServers,iceTransportPolicy:self._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(self._useEdgeWebRTC&&window.msRTCPeerConnection?window.msRTCPeerConnection:RTCPeerConnection)(constraints,optional)}catch(error){return log.error([targetMid,null,null,"Failed creating peer connection:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),null}pc.setOffer="",pc.setAnswer="",pc.hasStream=!1,pc.hasScreen=!!isScreenSharing,pc.hasMainChannel=!1,pc.firefoxStreamId="",pc.processingLocalSDP=!1,pc.processingRemoteSDP=!1,pc.gathered=!1,pc.gathering=!1,pc.localStream=null,pc.localStreamId=null,pc.remoteStream=null,pc.remoteStreamId=null,pc.iceConnectionStateClosed=!1,pc.signalingStateClosed=!1,self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}},self._streamsSession[targetMid]=self._streamsSession[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._sdpSessions[targetMid]={local:{},remote:{}},self._peerBandwidth[targetMid]={};var bandwidth=null;return pc.ondatachannel=function(event){var dc=event.channel||event;if(log.debug([targetMid,"RTCDataChannel",dc.label,"Received datachannel ->"],dc),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel){self.DATA_CHANNEL_TYPE.DATA,dc.label;pc.hasMainChannel||(self.DATA_CHANNEL_TYPE.MESSAGING,"main",pc.hasMainChannel=!0),self._createDataChannel(targetMid,dc)}else log.warn([targetMid,"RTCDataChannel",dc.label,"Not adding datachannel as enable datachannel is set to false"])},pc.onaddstream=function(evt){if(self._peerConnections[targetMid]){var stream=evt.stream||evt;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received empty remote stream ->"],stream);pc.remoteStream=stream,pc.remoteStreamId=pc.remoteStreamId||stream.id||stream.label;var peerSettings=clone(self.getPeerInfo(targetMid).settings);self._streamsSession[targetMid][pc.remoteStreamId]=peerSettings,0===stream.getAudioTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].audio=!1),0===stream.getVideoTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].video=!1),pc.hasStream=!0,pc.hasScreen=peerSettings.video&&"object"==typeof peerSettings.video&&peerSettings.video.screenshare,self._onRemoteStreamAdded(targetMid,stream,!!pc.hasScreen)}},pc.onicecandidate=function(event){self._onIceCandidate(targetMid,event.candidate||event)},pc.oniceconnectionstatechange=function(evt){var iceConnectionState=pc.iceConnectionState;if(log.debug([targetMid,"RTCIceConnectionState",null,"Ice connection state changed ->"],iceConnectionState),"edge"===AdapterJS.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),"AppleWebKit"===AdapterJS.webrtcDetectedType&&iceConnectionState===self.ICE_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.iceConnectionStateClosed||self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.CLOSED,targetMid)},10);if(self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._enableIceTrickle&&self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.TRICKLE_FAILED,targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].connected=[self.ICE_CONNECTION_STATE.COMPLETED,self.ICE_CONNECTION_STATE.CONNECTED].indexOf(iceConnectionState)>-1),!self._hasMCU&&[self.ICE_CONNECTION_STATE.CONNECTED,self.ICE_CONNECTION_STATE.COMPLETED].indexOf(iceConnectionState)>-1&&self._bandwidthAdjuster&&!bandwidth&&"edge"!==AdapterJS.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),"AppleWebKit"===AdapterJS.webrtcDetectedType&&pc.signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.signalingStateClosed||self._trigger("peerConnectionState",self.PEER_CONNECTION_STATE.CLOSED,targetMid)},10);self._trigger("peerConnectionState",pc.signalingState,targetMid)},pc.onicegatheringstatechange=function(){log.log([targetMid,"RTCIceGatheringState",null,"Ice gathering state changed ->"],pc.iceGatheringState),self._trigger("candidateGenerationState",pc.iceGatheringState,targetMid)},"firefox"===AdapterJS.webrtcDetectedBrowser&&(pc.removeStream=function(stream){for(var senders=pc.getSenders(),s=0;s"],restartMsg),self._sendChannelMessage(restartMsg)};bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=bwOptions.googleXBandwidth.max));for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers},null):callback(null,{listOfPeers:listOfPeers}))};self.once("peerJoined",peerJoinedFn,function(peerId,peerInfo,isSelf){return isSelf}),self.leaveRoom(!1,function(error,success){if(error){if("function"==typeof callback){for(var i=0;i=self._peerEndOfCandidatesCounter[targetMid].expectedLen&&(!self._peerCandidatesQueue[targetMid]||0===self._peerCandidatesQueue[targetMid].length)&&!self._peerEndOfCandidatesCounter[targetMid].hasSet){log.debug([targetMid,"RTCPeerConnection",null,"Signaling of end-of-candidates remote ICE gathering."]),self._peerEndOfCandidatesCounter[targetMid].hasSet=!0;try{if("edge"===AdapterJS.webrtcDetectedBrowser){for(var mLineCounter=-1,addedMids=[],sdpLines=self._peerConnections[targetMid].remoteDescription.sdp.split("\r\n"),rejected=!1,i=0;i"],error)}}},Skylink.prototype.setUserData=function(userData){var self=this,updatedUserData="";void 0!==userData&&null!==userData&&(updatedUserData=userData),this._userData=updatedUserData,self._inRoom?(log.log("Updated userData -> ",updatedUserData),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.UPDATE_USER,mid:self._user.sid,rid:self._room.id,userData:updatedUserData,stamp:(new Date).getTime()}),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0)):log.warn("User is not in the room. Broadcast of updated information will be dropped")},Skylink.prototype.getUserData=function(peerId){if(peerId&&this._peerInformations[peerId]){var userData=this._peerInformations[peerId].userData;return null!==userData&&void 0===userData||(userData=""),userData}return this._userData},Skylink.prototype.getPeerInfo=function(peerId){var peerInfo=null;return"string"==typeof peerId&&"object"==typeof this._peerInformations[peerId]?(peerInfo=clone(this._peerInformations[peerId]),peerInfo.room=clone(this._selectedRoom),peerInfo.settings.bandwidth=peerInfo.settings.bandwidth||{},peerInfo.settings.googleXBandwidth=peerInfo.settings.googleXBandwidth||{},"boolean"==typeof peerInfo.settings.video||peerInfo.settings.video&&"object"==typeof peerInfo.settings.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"==typeof peerInfo.settings.audio||peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.audioMuted&&(peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.videoMuted&&(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.maxBandwidth&&(peerInfo.settings.bandwidth=clone(peerInfo.settings.maxBandwidth),delete peerInfo.settings.maxBandwidth),peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&peerInfo.settings.video.customSettings&&"object"==typeof peerInfo.settings.video.customSettings&&(peerInfo.settings.video.customSettings.frameRate&&(peerInfo.settings.video.frameRate=clone(peerInfo.settings.video.customSettings.frameRate)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode)),peerInfo.settings.video.customSettings.width&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.width=clone(peerInfo.settings.video.customSettings.width)),peerInfo.settings.video.customSettings.height&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.height=clone(peerInfo.settings.video.customSettings.height)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode))),peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&(peerInfo.settings.audio.stereo=!0===peerInfo.settings.audio.stereo),null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),peerInfo.parentId=peerInfo.parentId||null,"MCU"===peerId?(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1):this._hasMCU&&(peerInfo.config.receiveOnly=!1,peerInfo.config.publishOnly=!0),this._sdpSettings.direction.audio.receive||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.direction.video.receive||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.data=!!(this._dataChannels[peerId]&&this._dataChannels[peerId].main&&this._dataChannels[peerId].main.channel&&this._dataChannels[peerId].main.channel.readyState===this.DATA_CHANNEL_STATE.OPEN),peerInfo.connected=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].connected,peerInfo.init=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].init,this._sdpSessions[peerId]&&this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&"object"==typeof this._sdpSessions[peerId].remote.connection&&(this._sdpSessions[peerId].remote.connection.audio&&this._sdpSessions[peerId].remote.connection.audio.indexOf("send")>-1||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSessions[peerId].remote.connection.video&&this._sdpSessions[peerId].remote.connection.video.indexOf("send")>-1||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSessions[peerId].remote.connection.data&&this._sdpSessions[peerId].remote.connection.data.indexOf("send")>-1||(peerInfo.settings.data=!1))):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,os:window.navigator.platform,
-pluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:this.SMProtocolVersion,DTProtocolVersion:this.DTProtocolVersion},room:clone(this._selectedRoom),config:{enableDataChannel:this._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;i-1||(customSettings.settings.audio=!1,customSettings.mediaStatus.audioMuted=!0),self._sdpSessions[usePeerId].local.connection.video&&self._sdpSessions[usePeerId].local.connection.video.indexOf("send")>-1||(customSettings.settings.video=!1,customSettings.mediaStatus.videoMuted=!0),self._sdpSessions[usePeerId].local.connection.data&&self._sdpSessions[usePeerId].local.connection.data.indexOf("send")>-1||(customSettings.settings.data=!1)),customSettings},Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo()),userCustomInfoForPeer=peerId?this._getPeerCustomSettings(peerId):null;return userCustomInfoForPeer&&"object"==typeof userCustomInfoForPeer&&(userInfo.settings=userCustomInfoForPeer.settings,userInfo.mediaStatus=userCustomInfoForPeer.mediaStatus),userInfo.settings.video&&"object"==typeof userInfo.settings.video&&(userInfo.settings.video.customSettings={},userInfo.settings.video.frameRate&&"object"==typeof userInfo.settings.video.frameRate&&(userInfo.settings.video.customSettings.frameRate=clone(userInfo.settings.video.frameRate),userInfo.settings.video.frameRate=-1),userInfo.settings.video.facingMode&&"object"==typeof userInfo.settings.video.facingMode&&(userInfo.settings.video.customSettings.facingMode=clone(userInfo.settings.video.facingMode),userInfo.settings.video.facingMode="-1"),userInfo.settings.video.resolution&&"object"==typeof userInfo.settings.video.resolution&&(userInfo.settings.video.resolution.width&&"object"==typeof userInfo.settings.video.resolution.width&&(userInfo.settings.video.customSettings.width=clone(userInfo.settings.video.width),userInfo.settings.video.resolution.width=-1),userInfo.settings.video.resolution.height&&"object"==typeof userInfo.settings.video.resolution.height&&(userInfo.settings.video.customSettings.height=clone(userInfo.settings.video.height),userInfo.settings.video.resolution.height=-1))),userInfo.settings.bandwidth&&(userInfo.settings.maxBandwidth=clone(userInfo.settings.bandwidth),delete userInfo.settings.bandwidth),this._getSDPCommonSupports(peerId).video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._getSDPCommonSupports(peerId).audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart){var self=this,pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of creating of offer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription","offer",'Dropping of creating of offer as signalingState is not "'+self.PEER_CONNECTION_STATE.STABLE+'" ->'],pc.signalingState);var offerConstraints={offerToReceiveAudio:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).video,offerToReceiveVideo:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).audio,iceRestart:!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,voiceActivityDetection:self._voiceActivityDetection};self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._dataChannels[targetMid]&&self._dataChannels[targetMid].main||(self._createDataChannel(targetMid),self._peerConnections[targetMid].hasMainChannel=!0)),log.debug([targetMid,null,null,"Creating offer with config:"],offerConstraints),pc.endOfCandidates=!1,self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=offerConstraints);var onSuccessCbFn=function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)};pc.createOffer(onSuccessCbFn,onErrorCbFn,"plugin"===AdapterJS.webrtcDetectedType?{mandatory:{OfferToReceiveAudio:offerConstraints.offerToReceiveAudio,OfferToReceiveVideo:offerConstraints.offerToReceiveVideo,iceRestart:offerConstraints.iceRestart,voiceActivityDetection:offerConstraints.voiceActivityDetection}}:offerConstraints)},Skylink.prototype._doAnswer=function(targetMid){var self=this;log.log([targetMid,null,null,"Creating answer with config:"],self._room.connection.sdpConstraints);var pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of creating of answer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription","answer",'Dropping of creating of answer as signalingState is not "'+self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER+'" ->'],pc.signalingState);var answerConstraints="edge"===AdapterJS.webrtcDetectedBrowser?{offerToReceiveVideo:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).video,offerToReceiveAudio:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).audio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints);var onSuccessCbFn=function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},onErrorCbFn=function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.createAnswer(onSuccessCbFn,onErrorCbFn,answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,_sessionDescription){var self=this,pc=self._peerConnections[targetMid];if(!_sessionDescription||!_sessionDescription.sdp)return void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],_sessionDescription);if(!pc)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as connection does not exists ->"],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(pc.processingLocalSDP)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as another is being processed ->"],_sessionDescription);pc.processingLocalSDP=!0;var sessionDescription={type:_sessionDescription.type,sdp:_sessionDescription.sdp};sessionDescription.sdp=self._removeSDPFirefoxH264Pref(targetMid,sessionDescription),sessionDescription.sdp=self._setSDPCodecParams(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPUnknownAptRtx(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPCodecs(targetMid,sessionDescription),sessionDescription.sdp=self._handleSDPConnectionSettings(targetMid,sessionDescription,"local"),sessionDescription.sdp=self._removeSDPREMBPackets(targetMid,sessionDescription),log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description updated ->"],sessionDescription.sdp);var onSuccessCbFn=function(){if(log.debug([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description has been set ->"],sessionDescription),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",sessionDescription.type,targetMid),sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER?pc.setAnswer="local":pc.setOffer="local",!self._enableIceTrickle&&!pc.gathered)return void log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description sending is halted to complete ICE gathering."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},onErrorCbFn=function(error){log.error([targetMid,"RTCSessionDescription",sessionDescription.type,"Local description failed setting ->"],error),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.setLocalDescription(new RTCSessionDescription(sessionDescription),onSuccessCbFn,onErrorCbFn)},Skylink.prototype.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:error instanceof Error?error:new Error(JSON.stringify(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);if("AppleWebKit"===AdapterJS.webrtcDetectedType){var checkStream=self._streams.screenshare&&self._streams.screenshare.stream?self._streams.screenshare.stream:self._streams.userMedia&&self._streams.userMedia.stream?self._streams.userMedia.stream:null;checkStream&&0!==checkStream.getTracks().length?0===checkStream.getAudioTracks().length?log.warn("Note that receiving audio streams may fail as safari 11 needs stream with audio and video tracks and not just with video tracks"):0===checkStream.getVideoTracks().length&&log.warn("Note that receiving video streams may fail as safari 11 needs stream with audio and video tracks and not just with audio tracks"):log.warn("Note that receiving audio and video streams may fail as safari 11 needs stream with audio and video tracks")}if("function"==typeof callback){var peerOnJoin=function(peerId,peerInfo,isSelf){self.off("systemAction",peerFailedJoin),self.off("channelClose",peerSocketFailedJoin),log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo})},peerFailedJoin=function(action,message){self.off("peerJoined",peerOnJoin),self.off("channelClose",peerSocketFailedJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room ->"],message),resolveAsErrorFn(new Error(message),self._selectedRoom,self._readyState)},peerSocketFailedJoin=function(){self.off("systemAction",peerFailedJoin),self.off("peerJoined",peerOnJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room due to abrupt disconnection."]),resolveAsErrorFn(new Error("Channel closed abruptly before session was established"),self._selectedRoom,self._readyState)};self.once("peerJoined",peerOnJoin,function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),self.once("systemAction",peerFailedJoin,function(action){return action===self.SYSTEM_ACTION.REJECT}),self.once("channelClose",peerSocketFailedJoin)}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.JOIN_ROOM,uid:self._user.uid,cid:self._key,rid:self._room.id,userCred:self._user.token,timeStamp:self._user.timeStamp,apiOwner:self._appKeyOwner,roomCred:self._room.token,start:self._room.startDateTime,len:self._room.duration,isPrivileged:!0===self._isPrivileged,autoIntroduce:!1!==self._autoIntroduce,key:self._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=!1===mediaOptions.audio&&!1===mediaOptions.video;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?!1===stopMediaOptions&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=!1!==stopMediaOptions.userMedia,stopScreenshare=!1!==stopMediaOptions.screenshare):"function"==typeof stopMediaOptions&&(callback=stopMediaOptions);for(var infoPeerId in self._peerInformations)self._peerInformations.hasOwnProperty(infoPeerId)&&self._peerInformations[infoPeerId]&&(peersThatLeft.push(infoPeerId),self._removePeer(infoPeerId));for(var connPeerId in self._peerConnections)self._peerConnections.hasOwnProperty(connPeerId)&&self._peerConnections[connPeerId]&&-1===peersThatLeft.indexOf(connPeerId)&&(peersThatLeft.push(connPeerId),self._removePeer(connPeerId));if(self._inRoom=!1,self._closeChannel(),isNotInRoom){var notInRoomError="Unable to leave room as user is not in any room";return log.error([null,"Room",previousRoom,notInRoomError]),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}self._stopStreams({userMedia:stopUserMedia,screenshare:stopScreenshare}),self._wait(function(){log.log([null,"Room",previousRoom,"User left the room"]),self._trigger("peerLeft",previousUserPeerId,self.getPeerInfo(),!0),"function"==typeof callback&&callback(null,{peerId:previousUserPeerId,previousRoom:previousRoom})},function(){return!self._channelOpen})},Skylink.prototype.lockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!0),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!0}),this._roomLocked=!0,this._trigger("roomLock",!0,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype.unlockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!1),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!1}),this._roomLocked=!1,this._trigger("roomLock",!1,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype._waitForOpenChannel=function(mediaOptions,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){var onChannelOpen=function(){self.off("socketError",onChannelError),setTimeout(function(){if(mediaOptions=mediaOptions||{},self._userData=mediaOptions.userData||self._userData||"",self._streamsBandwidthSettings={googleX:{},bAS:{}},self._publishOnly=!1,self._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},self._voiceActivityDetection="boolean"!=typeof mediaOptions.voiceActivityDetection||mediaOptions.voiceActivityDetection,self._peerConnectionConfig={bundlePolicy:self.BUNDLE_POLICY.BALANCED,rtcpMuxPolicy:self.RTCP_MUX_POLICY.REQUIRE,iceCandidatePoolSize:0,certificate:self.PEER_CERTIFICATE.AUTO},self._bandwidthAdjuster=null,mediaOptions.bandwidth&&("number"==typeof mediaOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=mediaOptions.bandwidth.audio),"number"==typeof mediaOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=mediaOptions.bandwidth.video),"number"==typeof mediaOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=mediaOptions.bandwidth.data)),mediaOptions.googleXBandwidth&&("number"==typeof mediaOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=mediaOptions.googleXBandwidth.min),"number"==typeof mediaOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=mediaOptions.googleXBandwidth.max)),mediaOptions.sdpSettings&&(mediaOptions.sdpSettings.direction&&(mediaOptions.sdpSettings.direction.audio&&(self._sdpSettings.direction.audio.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.receive||mediaOptions.sdpSettings.direction.audio.receive,self._sdpSettings.direction.audio.send="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.send||mediaOptions.sdpSettings.direction.audio.send),mediaOptions.sdpSettings.direction.video&&(self._sdpSettings.direction.video.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.video.receive||mediaOptions.sdpSettings.direction.video.receive,self._sdpSettings.direction.video.send="boolean"!=typeof mediaOptions.sdpSettings.direction.video.send||mediaOptions.sdpSettings.direction.video.send)),mediaOptions.sdpSettings.connection&&(self._sdpSettings.connection.audio="boolean"!=typeof mediaOptions.sdpSettings.connection.audio||mediaOptions.sdpSettings.connection.audio,self._sdpSettings.connection.video="boolean"!=typeof mediaOptions.sdpSettings.connection.video||mediaOptions.sdpSettings.connection.video,self._sdpSettings.connection.data="boolean"!=typeof mediaOptions.sdpSettings.connection.data||mediaOptions.sdpSettings.connection.data)),mediaOptions.publishOnly&&(self._sdpSettings.direction.audio.send=!0,self._sdpSettings.direction.audio.receive=!1,self._sdpSettings.direction.video.send=!0,self._sdpSettings.direction.video.receive=!1,self._publishOnly=!0,"object"==typeof mediaOptions.publishOnly&&mediaOptions.publishOnly.parentId&&"string"==typeof mediaOptions.publishOnly.parentId&&(self._parentId=mediaOptions.publishOnly.parentId)),mediaOptions.parentId&&(self._parentId=mediaOptions.parentId),mediaOptions.peerConnection&&"object"==typeof mediaOptions.peerConnection){if("string"==typeof mediaOptions.peerConnection.bundlePolicy)for(var bpProp in self.BUNDLE_POLICY)self.BUNDLE_POLICY.hasOwnProperty(bpProp)&&self.BUNDLE_POLICY[bpProp]===mediaOptions.peerConnection.bundlePolicy&&(self._peerConnectionConfig.bundlePolicy=mediaOptions.peerConnection.bundlePolicy);if("string"==typeof mediaOptions.peerConnection.rtcpMuxPolicy)for(var rmpProp in self.RTCP_MUX_POLICY)self.RTCP_MUX_POLICY.hasOwnProperty(rmpProp)&&self.RTCP_MUX_POLICY[rmpProp]===mediaOptions.peerConnection.rtcpMuxPolicy&&(self._peerConnectionConfig.rtcpMuxPolicy=mediaOptions.peerConnection.rtcpMuxPolicy);if("number"==typeof mediaOptions.peerConnection.iceCandidatePoolSize&&mediaOptions.peerConnection.iceCandidatePoolSize>0&&(self._peerConnectionConfig.iceCandidatePoolSize=mediaOptions.peerConnection.iceCandidatePoolSize),"string"==typeof mediaOptions.peerConnection.certificate)for(var pcProp in self.PEER_CERTIFICATE)self.PEER_CERTIFICATE.hasOwnProperty(pcProp)&&self.PEER_CERTIFICATE[pcProp]===mediaOptions.peerConnection.certificate&&(self._peerConnectionConfig.certificate=mediaOptions.peerConnection.certificate)}if(mediaOptions.autoBandwidthAdjustment&&(self._bandwidthAdjuster={interval:10,limitAtPercentage:100,useUploadBwOnly:!1},"object"==typeof mediaOptions.autoBandwidthAdjustment&&("number"==typeof mediaOptions.autoBandwidthAdjustment.interval&&mediaOptions.autoBandwidthAdjustment.interval>=10&&(self._bandwidthAdjuster.interval=mediaOptions.autoBandwidthAdjustment.interval),"number"==typeof mediaOptions.autoBandwidthAdjustment.limitAtPercentage&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage>=0&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage<=100&&(self._bandwidthAdjuster.limitAtPercentage=mediaOptions.autoBandwidthAdjustment.limitAtPercentage),
-"boolean"==typeof mediaOptions.autoBandwidthAdjustment.useUploadBwOnly&&(self._bandwidthAdjuster.useUploadBwOnly=mediaOptions.autoBandwidthAdjustment.useUploadBwOnly))),!0===mediaOptions.manualGetUserMedia){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){!0===mediaAccessRequiredFailure?self._onUserMediaError(new Error("Waiting for stream timeout"),!1,!1):callback(null,self._streams.userMedia.stream)},function(){return current50Block+=1,600===current50Block?(mediaAccessRequiredFailure=!0,!0):!(!self._streams.userMedia||!self._streams.userMedia.stream)||void 0},50)}if(mediaOptions.audio||mediaOptions.video)return void self.getUserMedia({useExactConstraints:!!mediaOptions.useExactConstraints,audio:mediaOptions.audio,video:mediaOptions.video},function(error,success){error?callback(error,null):callback(null,success)});callback(null,null)},1)},onChannelError=function(errorState,error){self.off("channelOpen",onChannelOpen),callback(error)};self._channelOpen?onChannelOpen():(self.once("channelOpen",onChannelOpen),self.once("socketError",onChannelError,function(errorState){return errorState===self.SOCKET_ERROR.RECONNECTION_ABORTED}),self._openChannel())},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.25",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,useEdgeWebRTC=!1,enableSimultaneousTransfers=!0;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,useEdgeWebRTC="boolean"==typeof options.useEdgeWebRTC?options.useEdgeWebRTC:useEdgeWebRTC,enableSimultaneousTransfers="boolean"==typeof options.enableSimultaneousTransfers?options.enableSimultaneousTransfers:enableSimultaneousTransfers,"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,"sprop-stereo":"boolean"==typeof options.codecParams.audio.opus["sprop-stereo"]?options.codecParams.audio.opus["sprop-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),!0===forceTURN&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===AdapterJS.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,self._useEdgeWebRTC=useEdgeWebRTC,self._enableSimultaneousTransfers=enableSimultaneousTransfers,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,useEdgeWebRTC:self._useEdgeWebRTC,enableSimultaneousTransfers:self._enableSimultaneousTransfers}),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,useEdgeWebRTC:self._useEdgeWebRTC,enableSimultaneousTransfers:self._enableSimultaneousTransfers})):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:error.content instanceof Error?error.content:new Error(JSON.stringify(error.content)),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:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion}),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}):(log.debug([null,"XMLHttpRequest",method,"Using XMLHttpRequest"],{agent:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.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;if("function"!=typeof(globals.AdapterJS||window.AdapterJS||{}).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 globals.io||window.io?window.XMLHttpRequest?self._path?void AdapterJS.webRTCReady(function(){if(self._enableIceRestart="firefox"!==AdapterJS.webrtcDetectedBrowser||AdapterJS.webrtcDetectedVersion>=48,self._binaryChunkType="firefox"===AdapterJS.webrtcDetectedBrowser?self.DATA_TRANSFER_DATA_TYPE.BLOB:self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&"plugin"===AdapterJS.webrtcDetectedType?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"plugin"===AdapterJS.webrtcDetectedType&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=-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,useEdgeWebRTC:self._useEdgeWebRTC,enableSimultaneousTransfers:self._enableSimultaneousTransfers};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_KEY="SkylinkJS",_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=_LOG_KEY;if("object"==typeof message){if(outputLog+=message[0]?" ["+message[0]+"] -":" -",outputLog+=message[1]?" <<"+message[1]+">>":"",message[2])if(outputLog+=" ","object"==typeof message[2])for(var i=0;i=logLevel)if(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace){void 0===console.trace&&logLevel[3];void 0!==debugObject?(console[_LOG_LEVELS[logLevel]](outputLog,debugObject),void 0!==console.trace&&console.trace("")):(console[_LOG_LEVELS[logLevel]](outputLog),void 0!==console.trace&&console.trace(""))}else void 0!==debugObject?console[_LOG_LEVELS[logLevel]](outputLog,debugObject):console[_LOG_LEVELS[logLevel]](outputLog)},log={debug:function(message,object){_logFn(4,message,object)},log:function(message,object){_logFn(3,message,object)},info:function(message,object){_logFn(2,message,object)},warn:function(message,object){_logFn(1,message,object)},error:function(message,object){_logFn(0,message,object)}};Skylink.prototype.setLogLevel=function(logLevel){for(var level in this.LOG_LEVEL)if(this.LOG_LEVEL[level]===logLevel)return _logLevel=logLevel,void log.log([null,"Log",level,"Log level exists. Level is set"]);log.error([null,"Log",level,"Log level does not exist. Level is not set"])},Skylink.prototype.setDebugMode=function(isDebugMode){isDebugMode&&"object"==typeof isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0===isDebugMode.trace,_enableDebugStack=!0===isDebugMode.storeLogs):!0===isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1)};Skylink.prototype.on=function(eventName,callback){"function"==typeof callback?(this._EVENTS[eventName]=this._EVENTS[eventName]||[],this._EVENTS[eventName].push(callback),log.log([null,"Event",eventName,"Event is subscribed"])):log.error([null,"Event",eventName,"Provided parameter is not a function"])},Skylink.prototype.once=function(eventName,callback,condition,fireAlways){"boolean"==typeof condition&&(fireAlways=condition,condition=null),fireAlways=void 0!==fireAlways&&fireAlways,condition="function"!=typeof condition?function(){return!0}:condition,"function"==typeof callback?(this._onceEvents[eventName]=this._onceEvents[eventName]||[],this._onceEvents[eventName].push([callback,condition,fireAlways]),log.log([null,"Event",eventName,"Event is subscribed on condition"])):log.error([null,"Event",eventName,"Provided callback is not a function"])},Skylink.prototype.off=function(eventName,callback){if(eventName&&"string"==typeof eventName){if(void 0===callback)return this._EVENTS[eventName]=[],this._onceEvents[eventName]=[],void log.log([null,"Event",eventName,"All events are unsubscribed"]);for(var arr=this._EVENTS[eventName]||[],once=this._onceEvents[eventName]||[],i=0;i"],message);self._user.sid&&!self._peerMessagesStamps[self._user.sid]&&(self._peerMessagesStamps[self._user.sid]={userData:0,audioMuted:0,videoMuted:0});var checkStampFn=function(statusMessage){return statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].userData:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].videoMuted:statusMessage.type!==self._SIG_MESSAGE_TYPE.MUTE_AUDIO||!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].audioMuted},setStampFn=function(statusMessage){statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?self._peerMessagesStamps[self._user.sid].userData=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?self._peerMessagesStamps[self._user.sid].videoMuted=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&(self._peerMessagesStamps[self._user.sid].audioMuted=statusMessage.stamp)},setQueueFn=function(){log.debug([null,"Socket",null,"Starting queue timeout"]),self._socketMessageTimeout=setTimeout(function(){if((new Date).getTime()-self._timestamp.socketMessage<=interval)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},interval-((new Date).getTime()-self._timestamp.socketMessage))},triggerEventFn=function(eventMessage){eventMessage.type===self._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE&&self._trigger("incomingMessage",{content:eventMessage.data,isPrivate:!1,targetPeerId:null,listOfPeers:Object.keys(self._peerInformations),isDataChannel:!1,senderPeerId:self._user.sid},self._user.sid,self.getPeerInfo(),!0)},sendGroupMessageFn=function(groupMessageList){if(self._socketMessageTimeout=null,!(self._channelOpen&&self._user&&self._user.sid&&self._socket))return void log.warn([message.target||"Server","Socket",null,"Dropping of group messages as Socket connection is not opened or is at incorrect step ->"],groupMessageList);for(var strGroupMessageList=[],stamps={userData:0,audioMuted:0,videoMuted:0},k=0;kself._peerMessagesStamps[self._user.sid].userData&&groupMessageList[k].stamp>stamps.userData?stamps.userData=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].audioMuted&&groupMessageList[k].stamp>stamps.audioMuted?stamps.audioMuted=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].videoMuted&&groupMessageList[k].stamp>stamps.videoMuted&&(stamps.videoMuted=groupMessageList[k].stamp));for(var i=0;i"],clone(groupMessageList[i])),groupMessageList.splice(i,1),i--):strGroupMessageList.push(JSON.stringify(groupMessageList[i]));if(strGroupMessageList.length>0){var groupMessage={type:self._SIG_MESSAGE_TYPE.GROUP,lists:strGroupMessageList,mid:self._user.sid,rid:self._room.id};log.log([message.target||"Server","Socket",groupMessage.type,"Sending queued grouped message (max: 16 per group) ->"],clone(groupMessage)),self._socket.send(JSON.stringify(groupMessage)),self._timestamp.socketMessage=(new Date).getTime();for(var j=0;j0&&(self._socketMessageQueue.length-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=interval)log.debug([message.target||"Server","Socket",message.type,"Queueing socket message to prevent message drop ->"],clone(message)),self._socketMessageQueue.push(message),self._socketMessageTimeout||setQueueFn();else{if(!checkStampFn(message))return void log.warn([message.target||"Server","Socket",message.type,"Dropping of outdated status message ->"],clone(message));self._socketMessageTimeout&&clearTimeout(self._socketMessageTimeout),log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),setStampFn(message),triggerEventFn(message),self._timestamp.socketMessage=(new Date).getTime()}else log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),message.type===self._SIG_MESSAGE_TYPE.BYE&&self._inRoom&&self._user&&self._user.sid&&message.mid===self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo()))},Skylink.prototype._createSocket=function(type){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:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._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:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._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:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "enter" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid)}self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0};var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),receiveOnly:self.getPeerInfo().config.receiveOnly,os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg),isNewPeer&&self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._restartHandler=function(message){var self=this,targetMid=message.mid,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "restart" received ->'],message),!self._peerInformations[targetMid])return void log.error([targetMid,"RTCPeerConnection",null,"Peer does not have an existing session. Ignoring restart process."]);if("MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId or publishOnly case ->'],message);if(self._hasMCU&&!self._mcuUseRenegoRestart)return log.warn([targetMid,"RTCPeerConnection",null,"Dropping restart request as MCU does not support re-negotiation. Restart workaround is to re-join Room for Peer."]),void self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!1);if(self._peerInformations[targetMid]=userInfo,self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid].len=0,self._peerPriorityWeight>message.weight){if(log.debug([targetMid,"RTCPeerConnection",null,"Re-negotiating new offer/answer."]),self._peerMessagesStamps[targetMid].hasRestart)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "restart" received.']);self._peerMessagesStamps[targetMid].hasRestart=!0,self._doOffer(targetMid,!0===message.doIceRestart,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start re-negotiation."]);var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===message.doIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,isRestartResend:!0,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._sendChannelMessage(restartMsg)}self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!0===message.doIceRestart)},Skylink.prototype._welcomeHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "welcome" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)}if(self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0,hasWelcome:!1},self._hasMCU||self._peerPriorityWeight>message.weight){if(self._peerMessagesStamps[targetMid].hasWelcome)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "welcome" received.']);log.debug([targetMid,"RTCPeerConnection",null,"Starting negotiation"]),self._peerMessagesStamps[targetMid].hasWelcome=!0,self._doOffer(targetMid,!1,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start negotiation."]);var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg)}};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._offerHandler=function(message){var self=this,targetMid=message.mid,pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for offer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}log.log([targetMid,null,message.type,"Received offer from peer. Session description:"],clone(message));var offer={type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],offer),offer.sdp=self._removeSDPFilteredCandidates(targetMid,offer),offer.sdp=self._setSDPCodec(targetMid,offer),offer.sdp=self._setSDPBitrate(targetMid,offer),offer.sdp=self._setSDPCodecParams(targetMid,offer),offer.sdp=self._removeSDPCodecs(targetMid,offer),offer.sdp=self._removeSDPREMBPackets(targetMid,offer),offer.sdp=self._handleSDPConnectionSettings(targetMid,offer,"remote"),offer.sdp=self._removeSDPUnknownAptRtx(targetMid,offer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "stable" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.resend});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,offer);var onSuccessCbFn=function(){log.debug([targetMid,"RTCSessionDescription",message.type,"Remote description set"]),pc.setOffer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.OFFER,targetMid),self._addIceCandidateFromQueue(targetMid),self._doAnswer(targetMid)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,offer:offer})};pc.setRemoteDescription(new RTCSessionDescription(offer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._candidateHandler=function(message){var targetMid=message.mid;if(!message.candidate&&!message.id)return void log.warn([targetMid,"RTCIceCandidate",null,"Received invalid ICE candidate message ->"],message);var canId="can-"+(new Date).getTime(),candidateType=message.candidate.split(" ")[7]||"",candidate=new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate,sdpMid:message.id});if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Received ICE candidate ->"],candidate),this._peerEndOfCandidatesCounter[targetMid]=this._peerEndOfCandidatesCounter[targetMid]||{},this._peerEndOfCandidatesCounter[targetMid].len=this._peerEndOfCandidatesCounter[targetMid].len||0,this._peerEndOfCandidatesCounter[targetMid].hasSet=!1,this._peerEndOfCandidatesCounter[targetMid].len++,this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.RECEIVED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!this._peerConnections[targetMid]||this._peerConnections[targetMid].signalingState===this.PEER_CONNECTION_STATE.CLOSED)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed.")),void this._signalingEndOfCandidates(targetMid);if(this._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};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],answer),answer.sdp=self._removeSDPFilteredCandidates(targetMid,answer),answer.sdp=self._setSDPCodec(targetMid,answer),answer.sdp=self._setSDPBitrate(targetMid,answer),answer.sdp=self._setSDPCodecParams(targetMid,answer),answer.sdp=self._removeSDPCodecs(targetMid,answer),answer.sdp=self._removeSDPREMBPackets(targetMid,answer),answer.sdp=self._handleSDPConnectionSettings(targetMid,answer,"remote"),answer.sdp=self._removeSDPUnknownAptRtx(targetMid,answer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "have-local-offer" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.restart});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,answer);var onSuccessCbFn=function(){log.debug([targetMid,null,message.type,"Remote description set"]),pc.setAnswer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ANSWER,targetMid),self._addIceCandidateFromQueue(targetMid),self._peerMessagesStamps[targetMid]&&(self._peerMessagesStamps[targetMid].hasRestart=!1),self._dataChannels[targetMid]&&(-1===pc.remoteDescription.sdp.indexOf("m=application")||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,answer:answer})};pc.setRemoteDescription(new RTCSessionDescription(answer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=(agentVer||"").split("."),partsB=(requiredVer||"").split("."),i=0;i0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for sendStream() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream);else{var notInRoomAgainError="Unable to send stream as user is not in the Room.";log.error(notInRoomAgainError,stream),"function"==typeof callback&&callback(new Error(notInRoomAgainError),null)}};if(!("object"==typeof options&&null!==options||AdapterJS&&AdapterJS.WebRTCPlugin&&AdapterJS.WebRTCPlugin.plugin&&["function","object"].indexOf(typeof options)>-1)){var invalidOptionsError="Provided stream settings is invalid";return log.error(invalidOptionsError,options),void("function"==typeof callback&&callback(new Error(invalidOptionsError),null))}if(!self._inRoom){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"===AdapterJS.webrtcDetectedBrowser){var edgeNotSupportError="Edge browser currently does not support renegotiation.";return log.error(edgeNotSupportError,options),void("function"==typeof callback&&callback(new Error(edgeNotSupportError),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t0&&(useMediaSource=enableAudioArr)}else enableAudio&&"object"==typeof enableAudio?enableAudioSettings={usedtx:"boolean"==typeof enableAudio.usedtx?enableAudio.usedtx:null,useinbandfec:"boolean"==typeof enableAudio.useinbandfec?enableAudio.useinbandfec:null,stereo:!0===enableAudio.stereo,echoCancellation:!1!==enableAudio.echoCancellation,deviceId:enableAudio.deviceId}:!0===enableAudio?enableAudioSettings=!0===enableAudio&&{usedtx:null,useinbandfec:null,stereo:!1,echoCancellation:!0,deviceId:null}:"function"==typeof enableAudio&&(callback=enableAudio,enableAudio=!1)
-;if(mediaSource&&"string"==typeof mediaSource)checkIfSourceExistsFn(mediaSource)&&(useMediaSource=[mediaSource]);else if(Array.isArray(mediaSource)){for(var mediaSourceArr=[],i=0;i0&&(useMediaSource=mediaSourceArr)}else"function"==typeof mediaSource&&(callback=mediaSource);useMediaSource.indexOf("audio")>-1&&-1===useMediaSource.indexOf("tab")&&(useMediaSource.splice(useMediaSource.indexOf("audio"),1),0===useMediaSource.length&&(useMediaSource=[self.MEDIA_SOURCE.SCREEN])),self._throttle(function(runFn){if(runFn){var settings={settings:{audio:enableAudioSettings,video:{screenshare:!0,exactConstraints:!1}},getUserMediaSettings:{audio:!1,video:{mediaSource:useMediaSource}}},mediaAccessSuccessFn=function(stream){self.off("mediaAccessError",mediaAccessErrorFn),self._inRoom?(self._trigger("incomingStream",self._user.sid,stream,!0,self.getPeerInfo(),!0,stream.id||stream.label),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0),Object.keys(self._peerConnections).length>0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for shareScreen() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream)):"function"==typeof callback&&callback(null,stream)},mediaAccessErrorFn=function(error){self.off("mediaAccessSuccess",mediaAccessSuccessFn),"function"==typeof callback&&callback(error,null)};self.once("mediaAccessSuccess",mediaAccessSuccessFn,function(stream,isScreensharing){return isScreensharing}),self.once("mediaAccessError",mediaAccessErrorFn,function(error,isScreensharing){return isScreensharing});var getUserMediaAudioSettings=!!enableAudioSettings&&{echoCancellation:enableAudioSettings.echoCancellation};try{var hasDefaultAudioTrack=!1;enableAudioSettings&&("firefox"===AdapterJS.webrtcDetectedBrowser?(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio=getUserMediaAudioSettings):useMediaSource.indexOf("audio")>-1&&useMediaSource.indexOf("tab")>-1&&(hasDefaultAudioTrack=!0,settings.getUserMediaSettings.audio={}));var onSuccessCbFn=function(stream){if(hasDefaultAudioTrack||!enableAudioSettings)return void self._onStreamAccessSuccess(stream,settings,!0,!1);settings.getUserMediaSettings.audio=getUserMediaAudioSettings;var onAudioSuccessCbFn=function(audioStream){try{audioStream.addTrack(stream.getVideoTracks()[0]),self.once("mediaAccessSuccess",function(){self._streams.screenshare.streamClone=stream},function(stream,isScreensharing){return isScreensharing}),self._onStreamAccessSuccess(audioStream,settings,!0,!1)}catch(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)}},onAudioErrorCbFn=function(error){log.error("Failed retrieving audio stream for screensharing stream",error),self._onStreamAccessSuccess(stream,settings,!0,!1)};navigator.getUserMedia({audio:getUserMediaAudioSettings},onAudioSuccessCbFn,onAudioErrorCbFn)},onErrorCbFn=function(error){self._onStreamAccessError(error,settings,!0,!1)};navigator.getUserMedia(settings.getUserMediaSettings,onSuccessCbFn,onErrorCbFn)}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"!==AdapterJS.webrtcDetectedBrowser&&("boolean"==typeof options.audio.echoCancellation&&(settings.settings.audio.echoCancellation=options.audio.echoCancellation,settings.getUserMediaSettings.audio.echoCancellation=options.audio.echoCancellation),Array.isArray(options.audio.optional)&&(settings.settings.audio.optional=clone(options.audio.optional),settings.getUserMediaSettings.audio.optional=clone(options.audio.optional)),options.audio.deviceId&&"string"==typeof options.audio.deviceId&&"firefox"!==AdapterJS.webrtcDetectedBrowser&&(settings.settings.audio.deviceId=options.audio.deviceId,settings.getUserMediaSettings.audio.deviceId=options.useExactConstraints?{exact:options.audio.deviceId}:{ideal:options.audio.deviceId}))),"edge"===AdapterJS.webrtcDetectedBrowser&&(settings.getUserMediaSettings.audio=!0)),options.video&&(settings.settings.video={resolution:clone(this.VIDEO_RESOLUTION.VGA),screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video={},"object"==typeof options.video?("boolean"==typeof options.video.mute&&(settings.mutedSettings.shouldVideoMuted=options.video.mute),Array.isArray(options.video.optional)&&(settings.settings.video.optional=clone(options.video.optional),settings.getUserMediaSettings.video.optional=clone(options.video.optional)),options.video.deviceId&&"string"==typeof options.video.deviceId&&"firefox"!==AdapterJS.webrtcDetectedBrowser&&(settings.settings.video.deviceId=options.video.deviceId,settings.getUserMediaSettings.video.deviceId=options.useExactConstraints?{exact:options.video.deviceId}:{ideal:options.video.deviceId}),options.video.resolution&&"object"==typeof options.video.resolution&&((options.video.resolution.width&&"object"==typeof options.video.resolution.width||"number"==typeof options.video.resolution.width)&&(settings.settings.video.resolution.width=options.video.resolution.width),(options.video.resolution.height&&"object"==typeof options.video.resolution.height||"number"==typeof options.video.resolution.height)&&(settings.settings.video.resolution.height=options.video.resolution.height)),settings.getUserMediaSettings.video.width="object"==typeof settings.settings.video.resolution.width?settings.settings.video.resolution.width:options.useExactConstraints?{exact:settings.settings.video.resolution.width}:{max:settings.settings.video.resolution.width},settings.getUserMediaSettings.video.height="object"==typeof settings.settings.video.resolution.height?settings.settings.video.resolution.height:options.useExactConstraints?{exact:settings.settings.video.resolution.height}:{max:settings.settings.video.resolution.height},(options.video.frameRate&&"object"==typeof options.video.frameRate||"number"==typeof options.video.frameRate&&"plugin"!==AdapterJS.webrtcDetectedType)&&(settings.settings.video.frameRate=options.video.frameRate,settings.getUserMediaSettings.video.frameRate="object"==typeof settings.settings.video.frameRate?settings.settings.video.frameRate:options.useExactConstraints?{exact:settings.settings.video.frameRate}:{max:settings.settings.video.frameRate}),options.video.facingMode&&["string","object"].indexOf(typeof options.video.facingMode)>-1&&"plugin"===AdapterJS.webrtcDetectedType&&(settings.settings.video.facingMode=options.video.facingMode,settings.getUserMediaSettings.video.facingMode="object"==typeof settings.settings.video.facingMode?settings.settings.video.facingMode:options.useExactConstraints?{exact:settings.settings.video.facingMode}:{max:settings.settings.video.facingMode})):settings.getUserMediaSettings.video={width:options.useExactConstraints?{exact:settings.settings.video.resolution.width}:{max:settings.settings.video.resolution.width},height:options.useExactConstraints?{exact:settings.settings.video.resolution.height}:{max:settings.settings.video.resolution.height}},"edge"===AdapterJS.webrtcDetectedBrowser&&(settings.settings.video={screenshare:!1,exactConstraints:!!options.useExactConstraints},settings.getUserMediaSettings.video=!0)),settings},Skylink.prototype._onStreamAccessSuccess=function(stream,settings,isScreenSharing,isAudioFallback){var self=this,streamId=stream.id||stream.label,streamHasEnded=!1;if(log.log([null,"MediaStream",streamId,"Has access to stream ->"],stream),!isScreenSharing&&self._streams.userMedia?self._stopStreams({userMedia:!0,screenshare:!1}):isScreenSharing&&self._streams.screenshare&&self._stopStreams({userMedia:!1,screenshare:!0}),self._streamsStoppedCbs[streamId]=function(){log.log([null,"MediaStream",streamId,"Stream has ended"]),streamHasEnded=!0,self._trigger("mediaAccessStopped",!!isScreenSharing,!!isAudioFallback,streamId),self._inRoom&&(log.debug([null,"MediaStream",streamId,"Sending Stream ended status to Peers"]),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.STREAM,mid:self._user.sid,rid:self._room.id,cid:self._key,streamId:streamId,settings:settings.settings,status:"ended"}),self._trigger("streamEnded",self._user.sid,self.getPeerInfo(),!0,!!isScreenSharing,streamId),isScreenSharing&&self._streams.screenshare&&self._streams.screenshare.stream&&(self._streams.screenshare.stream.id||self._streams.screenshare.stream.label)===streamId?self._streams.screenshare=null:!isScreenSharing&&self._streams.userMedia&&self._streams.userMedia.stream&&(self._streams.userMedia.stream.id||self._streams.userMedia.stream.label)===streamId&&(self._streams.userMedia=null))},["chrome","opera"].indexOf(AdapterJS.webrtcDetectedBrowser)>-1?(stream.oninactive=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},isScreenSharing&&stream.getVideoTracks().length>0&&(stream.getVideoTracks()[0].onended=function(){setTimeout(function(){!streamHasEnded&&self._inRoom&&self.stopScreen()},350)})):"firefox"===AdapterJS.webrtcDetectedBrowser?stream.endedInterval=setInterval(function(){void 0===stream.recordedTime&&(stream.recordedTime=0),stream.recordedTime===stream.currentTime?(clearInterval(stream.endedInterval),self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])):stream.recordedTime=stream.currentTime},1e3):stream.onended=function(){self._streamsStoppedCbs[streamId]&&(self._streamsStoppedCbs[streamId](),delete self._streamsStoppedCbs[streamId])},settings.settings.audio&&0===stream.getAudioTracks().length||settings.settings.video&&0===stream.getVideoTracks().length){var tracksNotSameError="Expected audio tracks length with "+(settings.settings.audio?"1":"0")+" and video tracks length with "+(settings.settings.video?"1":"0")+" but received audio tracks length with "+stream.getAudioTracks().length+" and video tracks length with "+stream.getVideoTracks().length;log.warn([null,"MediaStream",streamId,tracksNotSameError]);var requireAudio=!!settings.settings.audio,requireVideo=!!settings.settings.video;settings.settings.audio&&0===stream.getAudioTracks().length&&(settings.settings.audio=!1),settings.settings.video&&0===stream.getVideoTracks().length&&(settings.settings.video=!1),self._trigger("mediaAccessFallback",{error:new Error(tracksNotSameError),diff:{video:{expected:requireVideo?1:0,received:stream.getVideoTracks().length},audio:{expected:requireAudio?1:0,received:stream.getAudioTracks().length}}},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKED,!!isScreenSharing,!!isAudioFallback,streamId)}self._streams[isScreenSharing?"screenshare":"userMedia"]={stream:stream,settings:settings.settings,constraints:settings.getUserMediaSettings},self._muteStreams(),self._trigger("mediaAccessSuccess",stream,!!isScreenSharing,!!isAudioFallback,streamId)},Skylink.prototype._onStreamAccessError=function(error,settings,isScreenSharing){var self=this;if(!isScreenSharing&&settings.settings.audio&&settings.settings.video&&self._audioFallback){log.debug("Fallbacking to retrieve audio only Stream"),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.FALLBACKING,!1,!0);var onAudioSuccessCbFn=function(stream){self._onStreamAccessSuccess(stream,settings,!1,!0)},onAudioErrorCbFn=function(error){log.error("Failed fallbacking to retrieve audio only Stream ->",error),self._trigger("mediaAccessError",error,!1,!0),self._trigger("mediaAccessFallback",{error:error,diff:null},self.MEDIA_ACCESS_FALLBACK_STATE.ERROR,!1,!0)};return void navigator.getUserMedia({audio:!0},onAudioSuccessCbFn,onAudioErrorCbFn)}log.error("Failed retrieving "+(isScreenSharing?"screensharing":"camera")+" Stream ->",error),self._trigger("mediaAccessError",error,!!isScreenSharing,!1)},Skylink.prototype._onRemoteStreamAdded=function(targetMid,stream,isScreenSharing){var self=this,streamId=self._peerConnections[targetMid]&&self._peerConnections[targetMid].remoteStreamId||stream.id||stream.label;if(!self._peerInformations[targetMid])return void log.warn([targetMid,"MediaStream",streamId,"Received remote stream when peer is not connected. Ignoring stream ->"],stream);log.log([targetMid,"MediaStream",streamId,"Received remote stream ->"],stream),isScreenSharing&&log.log([targetMid,"MediaStream",streamId,"Peer is having a screensharing session with user"]),self._trigger("incomingStream",targetMid,stream,!1,self.getPeerInfo(targetMid),isScreenSharing,streamId),self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1)},Skylink.prototype._addLocalMediaStreams=function(peerId){var self=this;try{log.log([peerId,null,null,"Adding local stream"]);var pc=self._peerConnections[peerId];if(pc){var offerToReceiveAudio=!(!self._sdpSettings.connection.audio&&"MCU"!==peerId)&&self._getSDPCommonSupports(peerId,pc.remoteDescription).video,offerToReceiveVideo=!(!self._sdpSettings.connection.video&&"MCU"!==peerId)&&self._getSDPCommonSupports(peerId,pc.remoteDescription).audio;if(pc.signalingState!==self.PEER_CONNECTION_STATE.CLOSED){var updateStreamFn=function(updatedStream){if(!updatedStream||(!pc.localStreamId||updatedStream.id!==pc.localStreamId)){if("edge"!==AdapterJS.webrtcDetectedBrowser||self._useEdgeWebRTC&&window.msRTCPeerConnection?pc.getLocalStreams().forEach(function(stream){pc.removeStream(stream)}):pc.getSenders().forEach(function(sender){pc.removeTrack(sender)}),!offerToReceiveAudio&&!offerToReceiveVideo)return;updatedStream&&("edge"!==AdapterJS.webrtcDetectedBrowser||self._useEdgeWebRTC&&window.msRTCPeerConnection?pc.addStream(updatedStream):updatedStream.getTracks().forEach(function(track){"audio"===track.kind&&!offerToReceiveAudio||"video"===track.kind&&!offerToReceiveVideo||pc.addTrack(track,updatedStream)}),pc.localStreamId=updatedStream.id||updatedStream.label,pc.localStream=updatedStream)}};self._streams.screenshare&&self._streams.screenshare.stream?(log.debug([peerId,"MediaStream",null,"Sending screen"],self._streams.screenshare.stream),updateStreamFn(self._streams.screenshare.stream)):self._streams.userMedia&&self._streams.userMedia.stream?(log.debug([peerId,"MediaStream",null,"Sending stream"],self._streams.userMedia.stream),updateStreamFn(self._streams.userMedia.stream)):(log.warn([peerId,"MediaStream",null,"No media to send. Will be only receiving"]),updateStreamFn(null))}else log.warn([peerId,"MediaStream",null,"Not adding any stream as signalingState is closed"])}else log.warn([peerId,"MediaStream",self._mediaStream,"Not adding stream as peerconnection object does not exists"])}catch(error){(error.message||"").indexOf("already added")>-1?log.warn([peerId,null,null,"Not re-adding stream as LocalMediaStream is already added"],error):log.error([peerId,null,null,"Failed adding local stream"],error)}},Skylink.prototype._handleEndedStreams=function(peerId,checkStreamId){var self=this;self._streamsSession[peerId]=self._streamsSession[peerId]||{};var renderEndedFn=function(streamId){if(self._streamsSession[peerId][streamId]){var peerInfo=clone(self.getPeerInfo(peerId));peerInfo.settings.audio=clone(self._streamsSession[peerId][streamId].audio),peerInfo.settings.video=clone(self._streamsSession[peerId][streamId].video);var hasScreenshare=peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&!!peerInfo.settings.video.screenshare;self._streamsSession[peerId][streamId]=!1,self._trigger("streamEnded",peerId,peerInfo,!1,hasScreenshare,streamId)}};if(checkStreamId)renderEndedFn(checkStreamId);else if(self._peerConnections[peerId])for(var streamId in self._streamsSession[peerId])self._streamsSession[peerId].hasOwnProperty(streamId)&&self._streamsSession[peerId][streamId]&&renderEndedFn(streamId)},Skylink.prototype._setSDPCodecParams=function(targetMid,sessionDescription){var self=this,parseFn=function(type,codecName,samplingRate,settings){var mLine=sessionDescription.sdp.match(new RegExp("m="+type+" .*\r\n","gi"));if(Array.isArray(mLine)&&mLine.length>0){var codecsList=sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codecName+"/"+(samplingRate?samplingRate+("audio"===type?"[/]*.*":".*"):".*")+"\r\n","gi"));if(Array.isArray(codecsList)&&codecsList.length>0)for(var i=0;i0){for(var fmtpParts=(fmtpLine[0].split("a=fmtp:"+payload+" ")[1]||"").replace(/ /g,"").replace(/\r\n/g,"").split(";"),j=0;j0){if(0===sdpLines[i].indexOf("m="))break;0===sdpLines[i].indexOf("c=")?cLineIndex=i:0!==sdpLines[i].indexOf("b=AS:")&&0!==sdpLines[i].indexOf("b:TIAS:")||(sdpLines.splice(i,1),i--)}return"number"==typeof bw&&bw>0?-1===cLineIndex?void log.error([targetMid,"RTCSessionDesription",sessionDescription.type,'Failed setting "'+type+'" bandwidth as c-line is missing.']):(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Limiting maximum sending "'+type+'" bandwidth ->'],bw),void sdpLines.splice(cLineIndex+1,0,"firefox"===window.webrtcDetectedBrowser?"b=TIAS:"+(1e3*bw*(window.webrtcDetectedVersion>52&&window.webrtcDetectedVersion<55?1e3:1)).toFixed(0):"b=AS:"+bw)):void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not limiting "'+type+'" bandwidth'])},bASAudioBw=this._streamsBandwidthSettings.bAS.audio,bASVideoBw=this._streamsBandwidthSettings.bAS.video,bASDataBw=this._streamsBandwidthSettings.bAS.data,googleXMinBw=this._streamsBandwidthSettings.googleX.min,googleXMaxBw=this._streamsBandwidthSettings.googleX.max;if(this._peerCustomConfigs[targetMid]&&(this._peerCustomConfigs[targetMid].bandwidth&&"object"==typeof this._peerCustomConfigs[targetMid].bandwidth&&("number"==typeof this._peerCustomConfigs[targetMid].bandwidth.audio&&(bASAudioBw=this._peerCustomConfigs[targetMid].bandwidth.audio),"number"==typeof this._peerCustomConfigs[targetMid].bandwidth.video&&(bASVideoBw=this._peerCustomConfigs[targetMid].bandwidth.video),"number"==typeof this._peerCustomConfigs[targetMid].bandwidth.data&&(bASDataBw=this._peerCustomConfigs[targetMid].bandwidth.data)),this._peerCustomConfigs[targetMid].googleXBandwidth&&"object"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth&&("number"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth.min&&(googleXMinBw=this._peerCustomConfigs[targetMid].googleXBandwidth.min),"number"==typeof this._peerCustomConfigs[targetMid].googleXBandwidth.max&&(googleXMaxBw=this._peerCustomConfigs[targetMid].googleXBandwidth.max))),parseFn("audio",bASAudioBw),parseFn("video",bASVideoBw),parseFn("data",bASDataBw),"number"==typeof googleXMinBw||"number"==typeof googleXMaxBw){for(var codec=null,codecRtpMapLineIndex=-1,codecFmtpLineIndex=-1,j=0;j-1){var xGoogleParams="";"number"==typeof googleXMinBw&&(xGoogleParams+="x-google-min-bitrate="+googleXMinBw+";"),"number"==typeof googleXMaxBw&&(xGoogleParams+="x-google-max-bitrate="+googleXMaxBw+";"),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Limiting x-google-bitrate ->"],xGoogleParams),codecFmtpLineIndex>-1?sdpLines[codecFmtpLineIndex]+=(sdpLines[codecFmtpLineIndex].split(" ")[1]?";":"")+xGoogleParams:sdpLines.splice(codecRtpMapLineIndex+1,0,"a=fmtp:"+codec+" "+xGoogleParams)}}return sdpLines.join("\r\n")},Skylink.prototype._setSDPCodec=function(targetMid,sessionDescription,overrideSettings){var self=this,parseFn=function(type,codecSettings){var codec="object"==typeof codecSettings?codecSettings.codec:codecSettings,samplingRate="object"==typeof codecSettings?codecSettings.samplingRate:null,channels="object"==typeof codecSettings?codecSettings.channels:null;if(codec===self["audio"===type?"AUDIO_CODEC":"VIDEO_CODEC"].AUTO)return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not preferring any codec for "'+type+'" streaming. Using browser selection.']);var mLine=sessionDescription.sdp.match(new RegExp("m="+type+" .*\r\n","gi"));if(!(Array.isArray(mLine)&&mLine.length>0))return void log.error([targetMid,"RTCSessionDesription",sessionDescription.type,'Not preferring any codec for "'+type+'" streaming as m= line is not found.']);var setLineFn=function(codecsList,isSROk,isChnlsOk){if(Array.isArray(codecsList)&&codecsList.length>0){isSROk||(samplingRate=null),isChnlsOk||(channels=null),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,'Preferring "'+codec+'" (samplingRate: '+(samplingRate||"n/a")+", channels: "+(channels||"n/a")+') for "'+type+'" streaming.']);var line=mLine[0],lineParts=line.replace("\r\n","").split(" ");line=lineParts[0]+" "+lineParts[1]+" "+lineParts[2]+" ",lineParts.splice(0,3);for(var i=0;i0?(lineParts.splice(j,1),j--):sessionDescription.sdp.match(new RegExp("a=rtpmap:"+lineParts[j]+" "+codec+"/.*\r\n","gi"))&&(line+=lineParts[j]+" ",lineParts.splice(j,1),j--);return line+=lineParts.join(" ")+"\r\n",sessionDescription.sdp=sessionDescription.sdp.replace(mLine[0],line),!0}};if(samplingRate){if("audio"===type&&channels&&setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/"+samplingRate+(1===channels?"[/1]*":"/"+channels)+"\r\n","gi")),!0,!0))return;if(setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/"+samplingRate+"[/]*.*\r\n","gi")),!0))return}"audio"===type&&channels&&setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/.*/"+channels+"\r\n","gi")),!1,!0)||setLineFn(sessionDescription.sdp.match(new RegExp("a=rtpmap:.* "+codec+"/.*\r\n","gi")))};return parseFn("audio",overrideSettings?overrideSettings.audio:self._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._removeSDPUnknownAptRtx=function(targetMid,sessionDescription){for(var mediaLines=(sessionDescription.sdp.split("\r\n"),sessionDescription.sdp.split("m=")),formatRtx=function(str){return(str.match(/a=rtpmap:.*\ rtx\/.*\r\n/gi)||[]).forEach(function(line){var payload=(line.split("a=rtpmap:")[1]||"").split(" ")[0]||"",fmtpLine=(str.match(new RegExp("a=fmtp:"+payload+" .*\r\n","gi"))||[])[0];if(!fmtpLine)return void(str=str.replace(new RegExp(line,"g"),""));var codecPayload=(fmtpLine.split(" apt=")[1]||"").replace(/\r\n/gi,"");str.match(new RegExp("a=rtpmap:"+codecPayload+" .*\r\n","gi"))||(str=str.replace(new RegExp(line,"g"),""),str=str.replace(new RegExp(fmtpLine,"g"),""))}),str},formatFmtpRtcpFb=function(str){return(str.match(/a=(fmtp|rtcp-fb):.*\ rtx\/.*\r\n/gi)||[]).forEach(function(line){var payload=(line.split("a="+(line.indexOf("rtcp")>0?"rtcp-fb":"fmtp"))[1]||"").split(" ")[0]||""
-;str.match(new RegExp("a=rtpmap:"+payload+" .*\r\n","gi"))||(str=str.replace(new RegExp(line,"g"),""))}),str},m=0;m0))return void log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,'Not removing "'+codec+'" as it does not exists.']);for(var i=0;i'],payload),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=fmtp:"+payload+"\\ .*\\r\\n","g"),""),sessionDescription.sdp=sessionDescription.sdp.replace(new RegExp("a=rtpmap:\\d+ rtx\\/\\d+\\r\\na=fmtp:\\d+ apt="+payload+"\\r\\n","g"),"");for(var sdpLines=sessionDescription.sdp.split("\r\n"),j=0;j=3&&parts.splice(parts.indexOf(payload),1),sdpLines[j]=parts.join(" ");break}sessionDescription.sdp=sdpLines.join("\r\n")}};return this._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){var codecInfo={name:null,implementation:null,clockRate:null,channels:null,payloadType:null,params:null};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index&&0===mediaItem.indexOf(type+" ")){var codecs=(mediaItem.split("\r\n")[0]||"").split(" ");codecs.splice(0,3);for(var i=0;i-1)){codecInfo.name=parts[0],codecInfo.clockRate=parseInt(parts[1],10)||0,codecInfo.channels=parseInt(parts[2]||"1",10)||1,codecInfo.payloadType=parseInt(codecs[i],10),codecInfo.params="";(mediaItem.match(new RegExp("a=fmtp:"+codecs[i]+".*\r\n","gi"))||[]).forEach(function(paramItem){codecInfo.params+=paramItem.replace(new RegExp("a=fmtp:"+codecs[i],"gi"),"").replace(/\ /g,"").replace(/\r\n/g,"")});break}}}}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,'Parsing session description "'+type+'" codecs ->'],codecInfo),codecInfo):codecInfo},Skylink.prototype._removeSDPFilteredCandidates=function(targetMid,sessionDescription){return"MCU"===targetMid&&sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER&&"firefox"===window.webrtcDetectedBrowser&&(sessionDescription.sdp=sessionDescription.sdp.replace(/ generation 0/g,""),sessionDescription.sdp=sessionDescription.sdp.replace(/ udp /g," UDP ")),this._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);if(self._currentCodecSupport={audio:{},video:{}},"AppleWebKit"===AdapterJS.webrtcDetectedType)return self._currentCodecSupport.audio={opus:["48000/2"]},self._currentCodecSupport.video={h264:["48000"]},callback(null);try{if("edge"===window.webrtcDetectedBrowser){for(var codecs=RTCRtpSender.getCapabilities().codecs,i=0;i-1&&codecs[i].name){var codec=codecs[i].name.toLowerCase();self._currentCodecSupport[codecs[i].kind][codec]=codecs[i].clockRate+(codecs[i].numChannels>1?"/"+codecs[i].numChannels:"")}callback(null)}else{var pc=new RTCPeerConnection(null),offerConstraints="plugin"!==AdapterJS.webrtcDetectedType?{offerToReceiveAudio:!0,offerToReceiveVideo:!0}:{mandatory:{OfferToReceiveVideo:!0,OfferToReceiveAudio:!0}};try{var channel=pc.createDataChannel("test");self._binaryChunkType=channel.binaryType||self._binaryChunkType,self._binaryChunkType=self._binaryChunkType.toLowerCase().indexOf("array")>-1?self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER:self._binaryChunkType;for(var prop in self.DATA_TRANSFER_DATA_TYPE)if(self.DATA_TRANSFER_DATA_TYPE.hasOwnProperty(prop)&&self._binaryChunkType.toLowerCase()===self.DATA_TRANSFER_DATA_TYPE[prop].toLowerCase()){self._binaryChunkType=self.DATA_TRANSFER_DATA_TYPE[prop];break}}catch(e){}pc.createOffer(function(offer){self._currentCodecSupport=self._getSDPCodecsSupport(null,offer),callback(null)},function(error){callback(error)},offerConstraints)}}catch(error){callback(error)}},Skylink.prototype._handleSDPConnectionSettings=function(targetMid,sessionDescription,direction){var self=this;if(!self._sdpSessions[targetMid])return sessionDescription.sdp;var sessionDescriptionStr=sessionDescription.sdp;"remote"!==direction||self.getPeerInfo(targetMid).config.enableIceTrickle||(sessionDescriptionStr=sessionDescriptionStr.replace(/a=end-of-candidates\r\n/g,""));var sdpLines=sessionDescriptionStr.split("\r\n"),peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"",mediaType=(self._peerInformations[targetMid],""),bundleLineIndex=-1,bundleLineMids=[],mLineIndex=-1,settings=clone(self._sdpSettings);if("MCU"===targetMid&&(settings.connection.audio=!0,settings.connection.video=!0,settings.connection.data=!0),self._hasMCU){var peerStreamSettings=clone(self.getPeerInfo(targetMid)).settings||{};settings.direction.audio.receive="MCU"!==targetMid&&!!peerStreamSettings.audio,settings.direction.audio.send="MCU"===targetMid,settings.direction.video.receive="MCU"!==targetMid&&!!peerStreamSettings.video,settings.direction.video.send="MCU"===targetMid}if("remote"===direction){var offerCodecs=self._getSDPCommonSupports(targetMid,sessionDescription);offerCodecs.audio||(settings.connection.audio=!1),offerCodecs.video||(settings.connection.video=!1)}self._sdpSessions[targetMid][direction].mLines=[],self._sdpSessions[targetMid][direction].bundleLine="",self._sdpSessions[targetMid][direction].connection={audio:null,video:null,data:null};for(var i=0;i"],sdpLines[i]),self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE&&bundleLineIndex>-1&&0===mLineIndex&&("remote"===direction?sessionDescription.type===this.HANDSHAKE_PROGRESS.OFFER:sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER)){log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Not removing rejected m="+mediaType+" line ->"],sdpLines[i]),settings.connection[mediaType]=!0,["audio","video"].indexOf(mediaType)>-1&&(settings.direction[mediaType].send=!1,settings.direction[mediaType].receive=!1);continue}if("edge"===window.webrtcDetectedBrowser){sdpLines.splice(i,1),i--;continue}if("remote"===direction||sessionDescription.type===this.HANDSHAKE_PROGRESS.ANSWER){var parts=sdpLines[i].split(" ");parts[1]=0,sdpLines[i]=parts.join(" ");continue}}if("remote"!==direction||0!==sdpLines[i].indexOf("a=candidate:")||self.getPeerInfo(targetMid).config.enableIceTrickle||sdpLines[i+1]&&(0===sdpLines[i+1].indexOf("a=candidate:")||0===sdpLines[i+1].indexOf("a=end-of-candidates"))||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]),sdpLines.splice(i+1,0,"a=end-of-candidates"),i++),mediaType)if(settings.connection[mediaType]){if(0===sdpLines[i].indexOf("a=mid:"))bundleLineMids.push(sdpLines[i].split("a=mid:")[1]||"");else if(mediaType&&["a=sendrecv","a=sendonly","a=recvonly"].indexOf(sdpLines[i])>-1){if(-1===["audio","video"].indexOf(mediaType)){self._sdpSessions[targetMid][direction].connection.data=sdpLines[i];continue}if("local"===direction)settings.direction[mediaType].send&&!settings.direction[mediaType].receive?sdpLines[i]=sdpLines[i].indexOf("send")>-1?"a=sendonly":"a=inactive":!settings.direction[mediaType].send&&settings.direction[mediaType].receive?sdpLines[i]=sdpLines[i].indexOf("recv")>-1?"a=recvonly":"a=inactive":settings.direction[mediaType].send||settings.direction[mediaType].receive||(sdpLines[i]="a=inactive"),self._hasMCU||"firefox"===window.webrtcDetectedBrowser||"firefox"!==peerAgent||sessionDescription.type!==self.HANDSHAKE_PROGRESS.OFFER||"a=recvonly"!==sdpLines[i]||(log.warn([targetMid,"RTCSessionDesription",sessionDescription.type,"Overriding any original settings to receive only to send and receive to resolve chrome BUNDLE errors."]),sdpLines[i]="a=sendrecv",settings.direction[mediaType].send=!0,settings.direction[mediaType].receive=!0);else if(sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER){var localOfferRes=self._sdpSessions[targetMid].local.connection[mediaType];"a=sendonly"===localOfferRes?sdpLines[i]=-1===["a=inactive","a=recvonly"].indexOf(sdpLines[i])?"a=sendonly"===sdpLines[i]?"a=inactive":"a=recvonly":sdpLines[i]:"a=recvonly"===localOfferRes?sdpLines[i]=-1===["a=inactive","a=sendonly"].indexOf(sdpLines[i])?"a=recvonly"===sdpLines[i]?"a=inactive":"a=sendonly":sdpLines[i]:"a=inactive"===localOfferRes&&(sdpLines[i]="a=inactive")}self._sdpSessions[targetMid][direction].connection[mediaType]=sdpLines[i]}}else sdpLines.splice(i,1),i--;(sdpLines[i]||"").replace(/\n|\r|\s|\ /gi,"")||(sdpLines.splice(i,1),i--)}return bundleLineIndex>-1&&(self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.MAX_BUNDLE?sdpLines[bundleLineIndex]="a=group:BUNDLE "+bundleLineMids.join(" "):self._peerConnectionConfig.bundlePolicy===self.BUNDLE_POLICY.NONE&&sdpLines.splice(bundleLineIndex,1)),"edge"!==window.webrtcDetectedBrowser&&(sdpLines[sdpLines.length-1].replace(/\n|\r|\s/gi,"")?sdpLines.push(""):sdpLines[sdpLines.length-1]=""),log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Handling connection lines and direction ->"],settings),sdpLines.join("\r\n")},Skylink.prototype._getSDPFingerprint=function(targetMid,sessionDescription,beSilentOnLogs){var fingerprint={fingerprint:null,fingerprintAlgorithm:null,derBase64:null};if(!sessionDescription||!sessionDescription.sdp)return fingerprint;for(var sdpLines=sessionDescription.sdp.split("\r\n"),i=0;i"],fingerprint),fingerprint},Skylink.prototype._renderSDPOutput=function(targetMid,sessionDescription){var self=this,localStream=null,localStreamId=null;if(sessionDescription&&sessionDescription.sdp){if(!self._peerConnections[targetMid])return sessionDescription.sdp;self._peerConnections[targetMid].localStream&&(localStream=self._peerConnections[targetMid].localStream,localStreamId=self._peerConnections[targetMid].localStreamId||self._peerConnections[targetMid].localStream.id);var sdpLines=(self._enableIceTrickle?sessionDescription.sdp:sessionDescription.sdp.replace(/a=end-of-candidates\r\n/g,"")).split("\r\n");self._peerInformations[targetMid];if(localStream)for(var mediaType="",i=0;i0?ssrcParts=sdpLines[i].split(" msid:"):sdpLines[i].indexOf(" mslabel:")>0&&(ssrcParts=sdpLines[i].split(" mslabel:")),ssrcParts){var ssrcMsidParts=(ssrcParts[1]||"").split(" ");ssrcMsidParts[0]=localStreamId,ssrcParts[1]=ssrcMsidParts.join(" "),sdpLines[i].indexOf(" msid:")>0?sdpLines[i]=ssrcParts.join(" msid:"):sdpLines[i].indexOf(" mslabel:")>0&&(sdpLines[i]=ssrcParts.join(" mslabel:"))}}if(!self._enableIceTrickle){log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending end-of-candidates signal for non-trickle ICE connection."]);for(var e=0;e"],compareB.join(" ")),sdpLines.splice(j,0,compareB.join(" ")),j++,mLineIndex++)}for(;this._sdpSessions[targetMid].remote.mLines[mLineIndex+1];){mLineIndex++;var appendIndex=sdpLines.length;sdpLines[appendIndex-1].replace(/\s/gi,"")||(appendIndex-=1);var parts=(this._sdpSessions[targetMid].remote.mLines[mLineIndex]||"").split(" ");parts[1]=0,log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Appending later rejected m= line ->"],parts.join(" ")),sdpLines.splice(appendIndex,0,parts.join(" "))}}return"edge"!==window.webrtcDetectedBrowser||sessionDescription.type!==this.HANDSHAKE_PROGRESS.OFFER||sdpLines[sdpLines.length-1].replace(/\s/gi,"")||(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Removing last empty space for Edge browsers"]),sdpLines.splice(sdpLines.length-1,1)),log.info([targetMid,"RTCSessionDescription",sessionDescription.type,"Formatted output ->"],sdpLines.join("\r\n")),sdpLines.join("\r\n")}},Skylink.prototype._parseSDPMediaStreamIDs=function(targetMid,sessionDescription){if(this._peerConnections[targetMid]){if(!sessionDescription||!sessionDescription.sdp)return void(this._peerConnections[targetMid].remoteStreamId=null);for(var sdpLines=sessionDescription.sdp.split("\r\n"),currentStreamId=null,i=0;i0){currentStreamId=(sdpLines[i].split(" msid:")[1]||"").split(" ")[0];break}}currentStreamId?currentStreamId!==this._peerConnections[targetMid].remoteStreamId?(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"New remote stream is sent ->"],currentStreamId),this._peerConnections[targetMid].remoteStreamId=currentStreamId):log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"Same remote stream is sent ->"],currentStreamId):(log.info([targetMid,"RTCSessionDesription",sessionDescription.type,"No remote stream is sent."]),this._peerConnections[targetMid].remoteStreamId=null)}},Skylink.prototype._getSDPICECandidates=function(targetMid,sessionDescription,beSilentOnLogs){var candidates={host:[],srflx:[],relay:[]};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index){var sdpMid=((mediaItem.match(/a=mid:.*\r\n/gi)||[])[0]||"").replace(/a=mid:/gi,"").replace(/\r\n/,""),sdpMLineIndex=index-1;(mediaItem.match(/a=candidate:.*\r\n/gi)||[]).forEach(function(item){var canType=(item.split(" ")[7]||"host").replace(/\r\n/g,"");candidates[canType]=candidates[canType]||[],candidates[canType].push(new RTCIceCandidate({sdpMid:sdpMid,sdpMLineIndex:sdpMLineIndex,candidate:(item.split("a=")[1]||"").replace(/\r\n/g,"")}))})}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,"Parsing session description ICE candidates ->"],candidates),candidates):candidates},Skylink.prototype._getSDPMediaSSRC=function(targetMid,sessionDescription,beSilentOnLogs){var ssrcs={audio:0,video:0};return sessionDescription&&sessionDescription.sdp?(sessionDescription.sdp.split("m=").forEach(function(mediaItem,index){if(0!==index){var mediaType=mediaItem.split(" ")[0]||"",ssrcLine=(mediaItem.match(/a=ssrc:.*\r\n/)||[])[0];"number"==typeof ssrcs[mediaType]&&ssrcLine&&(ssrcs[mediaType]=parseInt((ssrcLine.split("a=ssrc:")[1]||"").split(" ")[0],10)||0)}}),beSilentOnLogs||log.debug([targetMid,"RTCSessionDesription",sessionDescription.type,"Parsing session description media SSRCs ->"],ssrcs),ssrcs):ssrcs},Skylink.prototype._getSDPCodecsSupport=function(targetMid,sessionDescription){var codecs={audio:{},video:{}};if(!sessionDescription||!sessionDescription.sdp)return codecs;for(var sdpLines=sessionDescription.sdp.split("\r\n"),mediaType="",i=0;i-1)continue;codecs[mediaType][codec]=codecs[mediaType][codec]||[],-1===codecs[mediaType][codec].indexOf(info)&&codecs[mediaType][codec].push(info)}}else if(mediaType=(sdpLines[i].split("m=")[1]||"").split(" ")[0],-1===["audio","video"].indexOf(mediaType))break;return log.info([targetMid||null,"RTCSessionDescription",sessionDescription.type,"Parsed codecs support ->"],codecs),codecs},Skylink.prototype._getSDPCommonSupports=function(targetMid,sessionDescription){var self=this,offer={audio:!1,video:!1};if(!targetMid||!sessionDescription||!sessionDescription.sdp){if(offer.video=!(!self._currentCodecSupport.video.h264&&!self._currentCodecSupport.video.vp8),offer.audio=!!self._currentCodecSupport.audio.opus,targetMid){var peerAgent=((self._peerInformations[targetMid]||{}).agent||{}).name||"";AdapterJS.webrtcDetectedBrowser===peerAgent&&(offer.video=Object.keys(self._currentCodecSupport.video).length>0,offer.audio=Object.keys(self._currentCodecSupport.audio).length>0)}return offer}var remoteCodecs=self._getSDPCodecsSupport(targetMid,sessionDescription),localCodecs=self._currentCodecSupport;for(var ac in localCodecs.audio)if(localCodecs.audio.hasOwnProperty(ac)&&localCodecs.audio[ac]&&remoteCodecs.audio[ac]){offer.audio=!0;break}for(var vc in localCodecs.video)if(localCodecs.video.hasOwnProperty(vc)&&localCodecs.video[vc]&&remoteCodecs.video[vc]){offer.video=!0;break}return offer},"undefined"!=typeof exports?module.exports={Skylink:Skylink,SkylinkLogs:SkylinkLogs}:globals?(globals.Skylink=Skylink,globals.SkylinkLogs=SkylinkLogs):window&&(window.Skylink=Skylink,window.SkylinkLogs=SkylinkLogs)}(this);
\ No newline at end of file
+;default:log.warn([peerId,"RTCDataChannel",channelProp,'Discarded unknown "'+protocolData.type+'" message ->'],protocolData)}}catch(error){if(rawData.indexOf("{")>-1&&rawData.indexOf("}")>0)throw log.error([peerId,"RTCDataChannel",channelProp,"Failed parsing protocol step data error ->"],{data:rawData,error:error}),self._trigger("dataChannelState",self.DATA_CHANNEL_STATE.ERROR,peerId,error,channelName,channelType,null,self._getDataChannelBuffer(peerId,channelProp)),error;if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING;if(isStreamChunk||self._dataTransfers[transferId].dataType===self.DATA_TRANSFER_SESSION_TYPE.DATA_URL)log.debug([peerId,"RTCDataChannel",channelProp,"Received string data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.length||rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.STRING,rawData.length||rawData.size||0,channelProp);else{var removeSpaceData=rawData.replace(/\s|\r|\n/g,"");log.debug([peerId,"RTCDataChannel",channelProp,"Received binary string data chunk @"+self._dataTransfers[transferId].sessions[peerId].ackN+" with size ->"],removeSpaceData.length||removeSpaceData.size),self._DATAProtocolHandler(peerId,self._base64ToBlob(removeSpaceData),self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,removeSpaceData.length||removeSpaceData.size||0,channelProp)}}else{if(!(isStreamChunk||transferId&&self._dataTransfers[transferId]&&self._dataTransfers[transferId].sessions[peerId]))return void log.warn([peerId,"RTCDataChannel",channelProp,"Discarded data chunk without session ->"],rawData);if(!isStreamChunk&&transferId&&self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN])return void log.warn([peerId,"RTCDataChannel",transferId,"Dropping data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" as it has already been added ->"],rawData);if(rawData instanceof Blob)log.debug([peerId,"RTCDataChannel",channelProp,"Received blob data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],rawData.size),self._DATAProtocolHandler(peerId,rawData,self.DATA_TRANSFER_DATA_TYPE.BLOB,rawData.size,channelProp);else{var byteArray=rawData,blob=null;if(rawData.constructor&&"Array"===rawData.constructor.name&&(byteArray=new Int8Array(rawData)),"IE"===AdapterJS.webrtcDetectedBrowser){if(window.BlobBuilder){var bb=new BlobBuilder;bb.append(rawData.constructor&&"ArrayBuffer"===rawData.constructor.name?byteArray:new Uint8Array(byteArray).buffer),blob=bb.getBlob()}}else blob=new Blob([byteArray]);log.debug([peerId,"RTCDataChannel",channelProp,"Received arraybuffer data chunk "+(isStreamChunk?"":"@"+self._dataTransfers[transferId].sessions[peerId].ackN)+" with size ->"],blob.size),self._DATAProtocolHandler(peerId,blob,self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,blob.size,channelProp)}}},Skylink.prototype._WRQProtocolHandler=function(peerId,data,channelProp){var self=this,transferId="main"===channelProp?data.transferId||null:channelProp,senderPeerId=data.sender||peerId;if(["fastBinaryStart","fastBinaryStop"].indexOf(data.dataType)>-1)if("fastBinaryStart"===data.dataType){transferId||(transferId="stream_"+peerId+"_"+(new Date).getTime()),self._dataStreams[transferId]={chunkSize:0,chunkType:"string"===data.chunkType?self.DATA_TRANSFER_DATA_TYPE.STRING:self._binaryChunkType,sessionChunkType:data.chunkType,isPrivate:!!data.isPrivate,isStringStream:"string"===data.chunkType,senderPeerId:senderPeerId,isUpload:!1},self._dataChannels[peerId][channelProp].streamId=transferId;self.once("dataChannelState",function(){},function(state,evtPeerId,channelName,channelType,error){if(!self._dataStreams[transferId])return!0;if(evtPeerId===peerId&&("main"===channelProp?channelType===self.DATA_CHANNEL_TYPE.MESSAGING:channelName===transferId&&channelType===self.DATA_CHANNEL_TYPE.DATA)&&[self.DATA_CHANNEL_STATE.ERROR,self.DATA_CHANNEL_STATE.CLOSED].indexOf(state)>-1){var updatedError=new Error(error&&error.message?error.message:'Failed data transfer as datachannel state is "'+state+'".');return self._trigger("dataStreamState",self.DATA_STREAM_STATE.ERROR,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},updatedError),!0}}),self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STARTED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStarted",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1)}else transferId=self._dataChannels[peerId][channelProp].streamId,self._dataStreams[transferId]&&!self._dataStreams[transferId].isUpload&&(self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVING_STOPPED,transferId,senderPeerId,{chunk:null,chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},null),self._trigger("incomingDataStreamStopped",transferId,senderPeerId,{chunkSize:0,chunkType:self._dataStreams[transferId].chunkType,isPrivate:self._dataStreams[transferId].isPrivate,isStringStream:"string"===self._dataStreams[transferId].sessionChunkType,senderPeerId:senderPeerId},!1),self._dataChannels[peerId][channelProp].streamId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp),delete self._dataStreams[transferId]);else transferId||(transferId="transfer_"+peerId+"_"+(new Date).getTime()),self._dataTransfers[transferId]={name:data.name||transferId,size:data.size||0,chunkSize:data.chunkSize,originalSize:data.originalSize||0,timeout:data.timeout||60,isPrivate:!!data.isPrivate,senderPeerId:data.sender||peerId,dataType:self.DATA_TRANSFER_SESSION_TYPE.BLOB,mimeType:data.mimeType||null,chunkType:self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING,direction:self.DATA_TRANSFER_TYPE.DOWNLOAD,chunks:[],sessions:{},sessionType:data.dataType||"blob",sessionChunkType:data.chunkType||"string"},"data"===self._dataTransfers[transferId].sessionType&&"string"===self._dataTransfers[transferId].sessionChunkType?(self._dataTransfers[transferId].dataType=self.DATA_TRANSFER_SESSION_TYPE.DATA_URL,self._dataTransfers[transferId].chunkType=self.DATA_TRANSFER_DATA_TYPE.STRING):"blob"===self._dataTransfers[transferId].sessionType&&"binary"===self._dataTransfers[transferId].sessionChunkType&&(self._dataTransfers[transferId].chunkType=self._binaryChunkType),self._dataChannels[peerId][channelProp].transferId=transferId,self._dataTransfers[transferId].sessions[peerId]={timer:null,ackN:0,receivedSize:0},self._trigger("incomingDataRequest",transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!1),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_REQUEST,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)},Skylink.prototype._ACKProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ACK event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};if(data.ackN>-1){if(0===data.ackN)emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_STARTED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,0),null)});else if(self._dataTransfers[transferId].enforceBSPeers.indexOf(peerId)>-1?data.ackN===self._dataTransfers[transferId].enforceBSInfo.chunks.length:data.ackN===self._dataTransfers[transferId].chunks.length)return self._dataTransfers[transferId].sessions[peerId].ackN=data.ackN,emitEventFn(function(evtPeerId){self._trigger("incomingData",self._getTransferData(transferId),transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.UPLOAD_COMPLETED,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,100),null)}),void(self._dataChannels[peerId][channelProp]&&(self._dataChannels[peerId][channelProp].transferId=null,"main"!==channelProp&&self._closeDataChannel(peerId,channelProp)));var uploadFn=function(chunk){self._sendMessageToDataChannel(peerId,chunk,channelProp,!0),data.ackN-1?self._blobToBase64(self._dataTransfers[transferId].enforceBSInfo.chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.BINARY_STRING?self._blobToBase64(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):self._dataTransfers[transferId].chunkType===self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER?self._blobToArrayBuffer(self._dataTransfers[transferId].chunks[data.ackN],uploadFn):uploadFn(self._dataTransfers[transferId].chunks[data.ackN])}else self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.REJECTED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error("Data transfer terminated as Peer has rejected data transfer request"),transferType:self.DATA_TRANSFER_TYPE.UPLOAD})},Skylink.prototype._MESSAGEProtocolHandler=function(peerId,data,channelProp){var senderPeerId=data.sender||peerId;log.log([senderPeerId,"RTCDataChannel",channelProp,"Received P2P message from peer:"],data),this._trigger("incomingMessage",{content:data.data,isPrivate:data.isPrivate,isDataChannel:!0,targetPeerId:this._user.sid,senderPeerId:senderPeerId},senderPeerId,this.getPeerInfo(senderPeerId),!1)},Skylink.prototype._ERRORProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp,senderPeerId=data.sender||peerId;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of ERROR event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(senderPeerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received an error from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.ERROR,transferId,evtPeerId,self._getTransferInfo(transferId,peerID,!0,!1,!1),{message:new Error(data.content),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._CANCELProtocolHandler=function(peerId,data,channelProp){var self=this,transferId=channelProp;"main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1);var emitEventFn=function(cb){if("MCU"===peerId){if(!self._dataTransfers[transferId].peers[channelProp])return void log.warn([peerId,"RTCDataChannel",channelProp,"Dropping triggering of CANCEL event as Peers list does not exists"]);for(var evtPeerId in self._dataTransfers[transferId].peers[channelProp])self._dataTransfers[transferId].peers[channelProp].hasOwnProperty(evtPeerId)&&self._dataTransfers[transferId].peers[channelProp][evtPeerId]&&cb(evtPeerId)}else cb(peerId)};log.error([peerId,"RTCDataChannel",channelProp,"Received data transfer termination from peer ->"],data),emitEventFn(function(evtPeerId){self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.CANCEL,transferId,evtPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),{message:new Error(data.content||"Peer has terminated data transfer."),transferType:self._dataTransfers[transferId].direction})})},Skylink.prototype._DATAProtocolHandler=function(peerId,chunk,chunkType,chunkSize,channelProp){var self=this,transferId=channelProp,senderPeerId=peerId;if(self._dataChannels[peerId]&&self._dataChannels[peerId][channelProp]){var streamId=self._dataChannels[peerId][channelProp].streamId;if(streamId&&self._dataStreams[streamId]&&("string"==typeof chunk&&"string"===self._dataStreams[streamId].sessionChunkType||chunk instanceof Blob&&"binary"===self._dataStreams[streamId].sessionChunkType))return senderPeerId=self._dataStreams[streamId].senderPeerId||peerId,self._trigger("dataStreamState",self.DATA_STREAM_STATE.RECEIVED,streamId,senderPeerId,{chunk:chunk,chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},null),void self._trigger("incomingDataStream",chunk,transferId,senderPeerId,{chunkSize:chunkSize,chunkType:chunkType,isPrivate:self._dataStreams[streamId].sessionChunkType.isPrivate,isStringStream:"string"===self._dataStreams[streamId].sessionChunkType,senderPeerId:senderPeerId},!1);if("main"===channelProp&&(transferId=self._dataChannels[peerId].main.transferId),self._dataTransfers[transferId].senderPeerId&&(senderPeerId=self._dataTransfers[transferId].senderPeerId),self._handleDataTransferTimeoutForPeer(transferId,peerId,!1),self._dataTransfers[transferId].chunkType=chunkType,self._dataTransfers[transferId].sessions[peerId].receivedSize+=chunkSize,self._dataTransfers[transferId].chunks[self._dataTransfers[transferId].sessions[peerId].ackN]=chunk,self._dataTransfers[transferId].sessions[peerId].receivedSize>=self._dataTransfers[transferId].size)return log.log([peerId,"RTCDataChannel",channelProp,"Data transfer has been completed. Computed size ->"],self._dataTransfers[transferId].sessions[peerId].receivedSize),self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN+1},channelProp),self._trigger("incomingData",self._getTransferData(transferId),transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!1,!1,!1),null),void self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOAD_COMPLETED,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null);self._dataTransfers[transferId].sessions[peerId].ackN+=1,self._sendMessageToDataChannel(peerId,{type:self._DC_PROTOCOL_TYPE.ACK,sender:self._user.sid,ackN:self._dataTransfers[transferId].sessions[peerId].ackN},channelProp),self._handleDataTransferTimeoutForPeer(transferId,peerId,!0),self._trigger("dataTransferState",self.DATA_TRANSFER_STATE.DOWNLOADING,transferId,senderPeerId,self._getTransferInfo(transferId,peerId,!0,!1,!1),null)}},Skylink.prototype.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._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,userInfo:self._getUserInfo(targetMid),target:targetMid,rid:self._room.id})}}},Skylink.prototype._addIceCandidateToQueue=function(targetMid,canId,candidate){var candidateType=candidate.candidate.split(" ")[7];log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Buffering ICE candidate."]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.BUFFERED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[],this._peerCandidatesQueue[targetMid].push([canId,candidate])},Skylink.prototype._addIceCandidateFromQueue=function(targetMid){this._peerCandidatesQueue[targetMid]=this._peerCandidatesQueue[targetMid]||[];for(var i=0;i"],error),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},error)};if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Adding ICE candidate."]),self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.PROCESSING,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!(self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&self._peerConnections[targetMid].remoteDescription&&self._peerConnections[targetMid].remoteDescription.sdp&&self._peerConnections[targetMid].remoteDescription.sdp.indexOf("\r\na=mid:"+candidate.sdpMid+"\r\n")>-1))return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),void self._trigger("candidateProcessingState",self.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed."));try{self._peerConnections[targetMid].addIceCandidate(candidate,onSuccessCbFn,onErrorCbFn)}catch(error){onErrorCbFn(error)}},Skylink.prototype.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(passedIceServers){var self=this,iceServerName=null,iceServerProtocol="stun",iceServerPorts={udp:[3478,19302,19303,19304],tcp:[80,443],both:[19305,19306,19307,19308]},iceServers=[{urls:[]},{urls:[]}];return passedIceServers.forEach(function(server){if(0===server.url.indexOf("stun:"))server.url.indexOf("temasys")>0?iceServerName=(server.url.split(":")[1]||"").split("?")[0]||null:iceServers[0].urls.push(server.url);else if(0===server.url.indexOf("turn:")&&server.url.indexOf("@")>0&&server.credential&&!iceServers[1].username&&!iceServers[1].credential){var parts=server.url.split(":"),urlParts=(parts[1]||"").split("@");iceServerName=(urlParts[1]||"").split("?")[0],iceServers[1].username=urlParts[0],iceServers[1].credential=server.credential,iceServerProtocol="turn"}}),self._iceServer?iceServers=[{urls:self._iceServer.urls,username:iceServers[1].username,credential:iceServers[1].credential}]:(iceServerName=iceServerName||"turn.temasys.io","edge"===AdapterJS.webrtcDetectedBrowser?(iceServerPorts.udp=[3478],iceServerPorts.tcp=[],iceServerPorts.both=[],iceServerProtocol="turn"):self._forceTURNSSL?"firefox"===AdapterJS.webrtcDetectedBrowser&&AdapterJS.webrtcDetectedVersion<53?(iceServerPorts.udp=[],iceServerPorts.tcp=[443],iceServerPorts.both=[],iceServerProtocol="turn"):(iceServerPorts.udp=[],iceServerProtocol="turns"):"firefox"===AdapterJS.webrtcDetectedBrowser&&(iceServerPorts.udp=[3478],iceServerPorts.tcp=[443,80]),self._TURNTransport!==self.TURN_TRANSPORT.UDP||self._forceTURNSSL?self._TURNTransport===self.TURN_TRANSPORT.TCP?(iceServerPorts.tcp=iceServerPorts.tcp.concat(iceServerPorts.both),iceServerPorts.udp=[],iceServerPorts.both=[]):self._TURNTransport===self.TURN_TRANSPORT.NONE&&(iceServerPorts.tcp=[],iceServerPorts.udp=[]):(iceServerPorts.udp=iceServerPorts.udp.concat(iceServerPorts.both),iceServerPorts.tcp=[],iceServerPorts.both=[]),"stun"===iceServerProtocol&&(iceServerPorts.tcp=[]),iceServerPorts.tcp.forEach(function(tcpPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+tcpPort+"?transport=tcp")}),iceServerPorts.udp.forEach(function(udpPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+udpPort+"?transport=udp")}),iceServerPorts.both.forEach(function(bothPort){iceServers[1].urls.push(iceServerProtocol+":"+iceServerName+":"+bothPort)})),self._usePublicSTUN||iceServers.splice(0,1),log.log("Output iceServers configuration:",iceServers),{iceServers:iceServers}},Skylink.prototype.PEER_CONNECTION_STATE={STABLE:"stable",HAVE_LOCAL_OFFER:"have-local-offer",HAVE_REMOTE_OFFER:"have-remote-offer",CLOSED:"closed"},Skylink.prototype.GET_CONNECTION_STATUS_STATE={RETRIEVING:0,RETRIEVE_SUCCESS:1,RETRIEVE_ERROR:-1},Skylink.prototype.SERVER_PEER_TYPE={MCU:"mcu"},Skylink.prototype.BUNDLE_POLICY={MAX_COMPAT:"max-compat",BALANCED:"balanced",MAX_BUNDLE:"max-bundle",NONE:"none"},Skylink.prototype.RTCP_MUX_POLICY={REQUIRE:"require",NEGOTIATE:"negotiate"},Skylink.prototype.PEER_CERTIFICATE={RSA:"RSA",ECDSA:"ECDSA",AUTO:"AUTO"},Skylink.prototype.refreshConnection=function(targetPeerId,iceRestart,options,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),doIceRestart=!1,bwOptions={};Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId?listOfPeers=[targetPeerId]:"boolean"==typeof targetPeerId?doIceRestart=targetPeerId:targetPeerId&&"object"==typeof targetPeerId?bwOptions=targetPeerId:"function"==typeof targetPeerId&&(callback=targetPeerId),"boolean"==typeof iceRestart?doIceRestart=iceRestart:iceRestart&&"object"==typeof iceRestart?bwOptions=iceRestart:"function"==typeof iceRestart&&(callback=iceRestart),options&&"object"==typeof options?bwOptions=options:"function"==typeof options&&(callback=options);var emitErrorForPeersFn=function(error){if(log.error(error),"function"==typeof callback){var listOfPeerErrors={};if(0===listOfPeers.length)listOfPeerErrors.self=new Error(error);else for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings},null):callback(null,{listOfPeers:listOfPeers,refreshSettings:listOfPeersSettings}))}},refreshSinglePeer=function(peerId,peerCallback){if(!self._peerConnections[peerId])return error="There is currently no existing peer connection made with the peer. Unable to restart connection",log.error([peerId,null,null,error]),void peerCallback(error);log.log([peerId,"PeerConnection",null,"Restarting peer connection"]),self._restartPeerConnection(peerId,doIceRestart,bwOptions,peerCallback)};if(self._hasMCU)self._restartMCUConnection(callback,doIceRestart,bwOptions);else{var i;for(i=0;i-1?refreshSinglePeer(peerId,refreshSinglePeerCallback(peerId)):(error="Peer connection with peer does not exists. Unable to restart",log.error([peerId,"PeerConnection",null,error]),refreshSinglePeerCallback(peerId)(error))}}},Skylink.prototype.getConnectionStatus=function(targetPeerId,callback){var self=this,listOfPeers=Object.keys(self._peerConnections),listOfPeerStats={},listOfPeerErrors={};if(Array.isArray(targetPeerId)?listOfPeers=targetPeerId:"string"==typeof targetPeerId&&targetPeerId?listOfPeers=[targetPeerId]:"function"==typeof targetPeerId&&(callback=targetPeerId,targetPeerId=void 0),0===listOfPeers.length)return listOfPeerErrors.self=new Error("There is currently no peer connections to retrieve connection status"),log.error([null,"RTCStatsReport",null,"Retrieving request failure ->"],listOfPeerErrors.self),void("function"==typeof callback&&callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null));"edge"===AdapterJS.webrtcDetectedBrowser&&log.warn("Edge browser does not have well support for stats.");for(var completedTaskCounter=[],checkCompletedFn=function(peerId){-1===completedTaskCounter.indexOf(peerId)&&completedTaskCounter.push(peerId),
+completedTaskCounter.length===listOfPeers.length&&"function"==typeof callback&&(Object.keys(listOfPeerErrors).length>0?callback({listOfPeers:listOfPeers,retrievalErrors:listOfPeerErrors,connectionStats:listOfPeerStats},null):callback(null,{listOfPeers:listOfPeers,connectionStats:listOfPeerStats}))},statsFn=function(peerId){var retrieveFn=function(firstRetrieval,nextCb){return function(err,result){if(err)return log.error([peerId,"RTCStatsReport",null,"Retrieval failure ->"],error),listOfPeerErrors[peerId]=error,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,error),checkCompletedFn(peerId),void(firstRetrieval&&delete self._peerStats[peerId]);firstRetrieval?nextCb():(listOfPeerStats[peerId]=result,self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_SUCCESS,peerId,listOfPeerStats[peerId],null),checkCompletedFn(peerId))}};if(!self._peerStats[peerId])return self._peerStats[peerId]={},log.debug([peerId,"RTCStatsReport",null,"Retrieving first report to tabulate results"]),void self._retrieveStats(peerId,retrieveFn(!0,function(){self._retrieveStats(peerId,retrieveFn())}),!0);self._retrieveStats(peerId,retrieveFn())},i=0;i"],listOfPeerErrors[peerId]),self._trigger("getConnectionStatusStateChange",self.GET_CONNECTION_STATUS_STATE.RETRIEVE_ERROR,peerId,null,listOfPeerErrors[peerId]),checkCompletedFn(peerId))}},Skylink.prototype._retrieveStats=function(peerId,callback,beSilentOnLogs,isAutoBwStats){var self=this,pc=self._peerConnections[peerId],output={raw:{},connection:{},audio:{sending:{},receiving:{}},video:{sending:{},receiving:{}},selectedCandidate:{local:{},remote:{},consentResponses:{},consentRequests:{},responses:{},requests:{}},certificate:{}};if(!self._peerStats[peerId]&&!isAutoBwStats)return callback(new Error("No stats initiated yet."));if(!pc)return callback(new Error("Peer connection is not initialised"));"edge"!==AdapterJS.webrtcDetectedBrowser&&"AppleWebKit"!==AdapterJS.webrtcDetectedType||log.warn("Current connection stats may not be complete as it is in beta"),output.connection.iceConnectionState=pc.iceConnectionState,output.connection.iceGatheringState=pc.iceGatheringState,output.connection.signalingState=pc.signalingState,output.connection.remoteDescription={type:pc.remoteDescription&&pc.remoteDescription.type||"",sdp:pc.remoteDescription&&pc.remoteDescription.sdp||""},output.connection.localDescription={type:pc.localDescription&&pc.localDescription.type||"",sdp:pc.localDescription&&pc.localDescription.sdp||""},output.connection.candidates={sending:self._getSDPICECandidates(peerId,pc.localDescription,beSilentOnLogs),receiving:self._getSDPICECandidates(peerId,pc.remoteDescription,beSilentOnLogs)},output.connection.dataChannels={},output.connection.constraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].constraints:null,output.connection.optional=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].optional:null,output.connection.sdpConstraints=self._peerConnStatus[peerId]?self._peerConnStatus[peerId].sdpConstraints:null,output.audio.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"audio",beSilentOnLogs),output.video.sending.codec=self._getSDPSelectedCodec(peerId,pc.remoteDescription,"video",beSilentOnLogs),output.audio.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"audio",beSilentOnLogs),output.video.receiving.codec=self._getSDPSelectedCodec(peerId,pc.localDescription,"video",beSilentOnLogs),output.certificate.local=self._getSDPFingerprint(peerId,pc.localDescription,beSilentOnLogs),output.certificate.remote=self._getSDPFingerprint(peerId,pc.remoteDescription,beSilentOnLogs);var inboundSSRCs=self._getSDPMediaSSRC(peerId,pc.remoteDescription,beSilentOnLogs);output.audio.receiving.ssrc=inboundSSRCs.audio,output.video.receiving.ssrc=inboundSSRCs.video;var outboundSSRCs=self._getSDPMediaSSRC(peerId,pc.localDescription,beSilentOnLogs);output.audio.sending.ssrc=outboundSSRCs.audio,output.video.sending.ssrc=outboundSSRCs.video,Object.keys(self._dataChannels[peerId]||{}).forEach(function(prop){var channel=self._dataChannels[peerId][prop];output.connection.dataChannels[channel.channel.label]={label:channel.channel.label,readyState:channel.channel.readyState,channelType:self.DATA_CHANNEL_TYPE["main"===prop?"MESSAGING":"DATA"],currentTransferId:channel.transferId||null,currentStreamId:channel.streamId||null}});var certificateFn=function(item,prop){if(0===prop.indexOf("RTCCertificate_"))item.fingerprint===output.certificate.local.fingerprint?(output.certificate.local.derBase64=item.base64Certificate,output.certificate.local.fingerprintAlgorithm=item.fingerprintAlgorithm):item.fingerprint===output.certificate.remote.fingerprint&&(output.certificate.remote.derBase64=item.base64Certificate,output.certificate.remote.fingerprintAlgorithm=item.fingerprintAlgorithm);else if(0===prop.indexOf("ssrc_")&&item.transportId){var pairItem=output.raw[item.transportId]||{};output.certificate.srtpCipher=pairItem.srtpCipher,output.certificate.dtlsCipher=pairItem.dtlsCipher;var localCertItem=output.raw[pairItem.localCertificateId||""]||{};output.certificate.local.fingerprint=localCertItem.googFingerprint,output.certificate.local.fingerprintAlgorithm=localCertItem.googFingerprintAlgorithm,output.certificate.local.derBase64=localCertItem.googDerBase64;var remoteCertItem=output.raw[pairItem.remoteCertificateId||""]||{};output.certificate.remote.fingerprint=remoteCertItem.googFingerprint,output.certificate.remote.fingerprintAlgorithm=remoteCertItem.googFingerprintAlgorithm,output.certificate.remote.derBase64=remoteCertItem.googDerBase64}},candidatePairFn=function(item,prop){if(0===prop.indexOf("RTCIceCandidatePair_")){if("succeeded"!==item.state||output.selectedCandidate.nominated||item.prioirty<(output.selectedCandidate.priority||0))return;for(var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop],sending=pc.localDescription&&pc.localDescription.sdp&&pc.localDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],receiving=pc.remoteDescription&&pc.remoteDescription&&pc.remoteDescription.sdp.match(/a=candidate:.*\r\n/gi)||[],computePrioirtyFn=function(controller,controlled){return Math.pow(2,32)*Math.min(controller,controlled)+2*Math.max(controller,controlled)+(controller>controlled?1:0)},computeCanTypeFn=function(type){return"relay"===type?"relayed":"host"===type?"local":"srflx"===type?"serverreflexive":type},s=0;s0?"sending":"receiving";item.codecImplementationName="unknown"===item.codecImplementationName?null:item.codecImplementationName,output[item.mediaType][direction].codec.implementation=item.codecImplementationName||null,item.googCodecName="unknown"===item.googCodecName?null:item.googCodecName,output[item.mediaType][direction].codec.name=item.googCodecName||output[item.mediaType][direction].codec.name}},audioStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPAudioStream")){if(output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.audio.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),"function"!=typeof pc.getReceivers)return}else if(0===prop.indexOf("RTCMediaStreamTrack_remote_audio_"))output.audio.receiving.audioOutputLevel=item.audioLevel;else if(0===prop.indexOf("RTCOutboundRTPAudioStream"))output.audio.sending.targetBitrate=item.targetBitrate||0,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"audio"===item.mediaType&&item.isRemote)output.audio.receiving.fractionLost=item.fractionLost,output.audio.receiving.jitter=item.jitter,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"audio"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"audio"===item.mediaType)if(prop.indexOf("_recv")>0){output.audio.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.audio.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.audio.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.audio.receiving.totalBytes=bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.audio.receiving.totalPackets=packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.audio.receiving.totalPacketsLost=packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost")}else{output.audio.sending.rtt=parseInt(item.googRtt||"0",10),output.audio.sending.audioInputLevel=parseInt(item.audioInputLevel||"0",10),output.audio.sending.echoReturnLoss=parseInt(item.googEchoCancellationReturnLoss||"0",10),output.audio.sending.echoReturnLossEnhancement=parseInt(item.googEchoCancellationReturnLossEnhancement||"0",10);var bytesSent=parseInt(item.bytesSent||"0",10);output.audio.sending.totalBytes=bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.audio.sending.totalPackets=packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent")}else if(0===prop.indexOf("inbound_rtp_audio"))output.audio.receiving.jitter=item.jitter||0,output.audio.receiving.totalBytes=item.bytesReceived,output.audio.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.audio.receiving.totalPackets=item.packetsReceived,output.audio.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.audio.receiving.totalPacketsLost=item.packetsLost,output.audio.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.audio.receiving.totalNacks=item.nackCount,output.audio.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount");else if(0===prop.indexOf("outbound_rtp_audio")){output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.audio.sending.rtt=rtcpItem.roundTripTime||0}}else{output.audio.sending.targetBitrate=item.targetBitrate,output.audio.sending.rtt=item.roundTripTime,output.audio.sending.totalBytes=item.bytesSent,output.audio.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.audio.sending.totalPackets=item.packetsSent,output.audio.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.audio.sending.totalNacks=item.nackCount,output.audio.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.audio.sending.audioInputLevel=trackItem.audioLevel,output.audio.sending.echoReturnLoss=trackItem.echoReturnLoss,output.audio.sending.echoReturnLossEnhancement=trackItem.echoReturnLossEnhancement}},videoStatsFn=function(item,prop){var prevStats=isAutoBwStats?self._peerBandwidth[peerId][prop]:self._peerStats[peerId][prop];if(0===prop.indexOf("RTCInboundRTPVideoStream"))output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.framesDecoded=item.framesDecoded,output.video.receiving.qpSum=item.qpSum,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsDiscarded=item.packetsDiscarded,output.video.receiving.packetsDiscarded=self._parseConnectionStats(prevStats,item,"packetsDiscarded"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if(0===prop.indexOf("RTCMediaStreamTrack_remote_video_"))output.video.receiving.frameHeight=item.frameHeight,output.video.receiving.frameWidth=item.frameWidth,output.video.receiving.framesCorrupted=item.framesCorrupted,output.video.receiving.framesPerSecond=item.framesPerSecond,output.video.receiving.framesDropped=item.framesDropped,output.video.receiving.totalFrames=item.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,item,"framesReceived");else if(0===prop.indexOf("RTCOutboundRTPVideoStream"))output.video.sending.qpSum=item.qpSum,output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");else if("edge"===AdapterJS.webrtcDetectedBrowser&&"inboundrtp"===item.type&&"video"===item.mediaType&&item.isRemote){output.video.receiving.fractionLost=item.fractionLost,output.video.receiving.jitter=item.jitter,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.receiving.totalSlis=item.sliCount,output.video.receiving.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.receiving.framesCorrupted=trackItem.framesCorrupted,output.video.receiving.framesDropped=trackItem.framesDropped,output.video.receiving.framesDecoded=trackItem.framesDecoded,output.video.receiving.totalFrames=trackItem.framesReceived,output.video.receiving.frames=self._parseConnectionStats(prevStats,trackItem,"framesReceived")}else if("edge"!==AdapterJS.webrtcDetectedBrowser||"outboundrtp"!==item.type||"video"!==item.mediaType||item.isRemote){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType)if(prop.indexOf("_recv")>0){output.video.receiving.jitter=parseInt(item.googJitterReceived||"0",10),output.video.receiving.jitterBufferMs=parseInt(item.googJitterBufferMs||"0",10),output.video.receiving.currentDelayMs=parseInt(item.googCurrentDelayMs||"0",10),output.video.receiving.renderDelayMs=parseInt(item.googRenderDelayMs||"0",10),output.video.receiving.frameWidth=parseInt(item.googFrameWidthReceived||"0",10),output.video.receiving.frameHeight=parseInt(item.googFrameHeightReceived||"0",10),output.video.receiving.framesDecoded=parseInt(item.framesDecoded||"0",10),output.video.receiving.frameRateOutput=parseInt(item.googFrameRateOutput||"0",10),output.video.receiving.frameRateDecoded=parseInt(item.googFrameRateDecoded||"0",10),output.video.receiving.frameRateReceived=parseInt(item.googFrameRateReceived||"0",10),output.video.receiving.qpSum=parseInt(item.qpSum||"0",10);var bytesReceived=parseInt(item.bytesReceived||"0",10);output.video.receiving.totalBytes=bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived");var packetsReceived=parseInt(item.packetsReceived||"0",10);output.video.receiving.totalPackets=packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived");var packetsLost=parseInt(item.packetsLost||"0",10);output.video.receiving.totalPacketsLost=packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost");var nacksSent=parseInt(item.googNacksSent||"0",10);output.video.receiving.totalNacks=nacksSent,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"googNacksSent");var plisSent=parseInt(item.googPlisSent||"0",10);output.video.receiving.totalPlis=plisSent,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"googPlisSent");var firsSent=parseInt(item.googFirsSent||"0",10);output.video.receiving.totalFirs=firsSent,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"googFirsSent")}else{output.video.sending.rtt=parseInt(item.googRtt||"0",10),output.video.sending.frameWidth=parseInt(item.googFrameWidthSent||"0",10),output.video.sending.frameHeight=parseInt(item.googFrameHeightSent||"0",10),output.video.sending.framesEncoded=parseInt(item.framesEncoded||"0",10),output.video.sending.frameRateInput=parseInt(item.googFrameRateInput||"0",10),output.video.sending.frameRateEncoded=parseInt(item.googFrameRateEncoded||"0",10),output.video.sending.frameRateSent=parseInt(item.googFrameRateSent||"0",10),output.video.sending.cpuLimitedResolution="true"===item.googCpuLimitedResolution,output.video.sending.bandwidthLimitedResolution="true"===item.googBandwidthLimitedResolution;var bytesSent=parseInt(item.bytesSent||"0",10);output.video.sending.totalBytes=bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent");var packetsSent=parseInt(item.packetsSent||"0",10);output.video.sending.totalPackets=packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent");var nacksReceived=parseInt(item.googNacksReceived||"0",10);output.video.sending.totalNacks=nacksReceived,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"googNacksReceived");var plisReceived=parseInt(item.googPlisReceived||"0",10);output.video.sending.totalPlis=plisReceived,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"googPlisReceived");var firsReceived=parseInt(item.googFirsReceived||"0",10);output.video.sending.totalFirs=firsReceived,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"googFirsReceived")}else if(0===prop.indexOf("inbound_rtp_video"))output.video.receiving.jitter=item.jitter||0,output.video.receiving.framesDecoded=item.framesDecoded||0,output.video.receiving.frameRateMean=item.framerateMean||0,output.video.receiving.frameRateStdDev=item.framerateStdDev||0,output.video.receiving.totalBytes=item.bytesReceived,output.video.receiving.bytes=self._parseConnectionStats(prevStats,item,"bytesReceived"),output.video.receiving.totalPackets=item.packetsReceived,output.video.receiving.packets=self._parseConnectionStats(prevStats,item,"packetsReceived"),output.video.receiving.totalPacketsLost=item.packetsLost,output.video.receiving.packetsLost=self._parseConnectionStats(prevStats,item,"packetsLost"),output.video.receiving.totalNacks=item.nackCount,output.video.receiving.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.receiving.totalPlis=item.pliCount,output.video.receiving.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.receiving.totalFirs=item.firCount,output.video.receiving.firs=self._parseConnectionStats(prevStats,item,"firCount");else if(0===prop.indexOf("outbound_rtp_video")){output.video.sending.framesEncoded=item.framesEncoded||0,output.video.sending.frameRateMean=item.framerateMean||0,output.video.sending.frameRateStdDev=item.framerateStdDev||0,output.video.sending.framesDropped=item.droppedFrames||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount");var rtcpItem=output.raw[prop.replace(/_rtp_/g,"_rtcp_")]||{};output.video.sending.rtt=rtcpItem.roundTripTime||0}}else{output.video.sending.targetBitrate=item.targetBitrate||0,output.video.sending.roundTripTime=item.roundTripTime||0,output.video.sending.totalBytes=item.bytesSent,output.video.sending.bytes=self._parseConnectionStats(prevStats,item,"bytesSent"),output.video.sending.totalPackets=item.packetsSent,output.video.sending.packets=self._parseConnectionStats(prevStats,item,"packetsSent"),output.video.sending.totalNacks=item.nackCount,output.video.sending.nacks=self._parseConnectionStats(prevStats,item,"nackCount"),output.video.sending.totalFirs=item.firCount,output.video.sending.firs=self._parseConnectionStats(prevStats,item,"firCount"),output.video.sending.totalPlis=item.pliCount,output.video.sending.plis=self._parseConnectionStats(prevStats,item,"pliCount"),output.video.sending.totalSlis=item.sliCount,output.video.sending.slis=self._parseConnectionStats(prevStats,item,"sliCount");var trackItem=output.raw[item.mediaTrackId||""]||{};output.video.sending.frameHeight=trackItem.frameHeight,output.video.sending.frameWidth=trackItem.frameWidth,output.video.sending.framesPerSecond=trackItem.framesPerSecond,output.video.sending.totalFrames=trackItem.framesSent,output.video.sending.frames=self._parseConnectionStats(prevStats,trackItem,"framesSent")}},videoE2EStatsFn=function(item,prop){if(0===prop.indexOf("ssrc_")&&"video"===item.mediaType){var captureStartNtpTimeMs=parseInt(item.googCaptureStartNtpTimeMs||"0",10),remoteStream=pc.getRemoteStreams()[0];if(!(captureStartNtpTimeMs>0&&prop.indexOf("_recv")>0&&remoteStream&&document&&"function"==typeof document.getElementsByTagName))return;try{var elements=document.getElementsByTagName("plugin"===AdapterJS.webrtcDetectedType?"object":"video");"plugin"!==AdapterJS.webrtcDetectedType&&0===elements.length&&(elements=document.getElementsByTagName("audio"));for(var e=0;e0))break;for(var ec=0;ec"],error)}}},successCbFn=function(stats){"function"==typeof stats.forEach?stats.forEach(function(item,prop){output.raw[prop]=item}):output.raw=stats;var edgeTracksKind={remote:{},local:{}};"edge"===AdapterJS.webrtcDetectedBrowser&&(pc.remoteStream&&pc.remoteStream.getTracks().forEach(function(track){edgeTracksKind.remote[track.id]=track.kind}),pc.localStream&&pc.localStream.getTracks().forEach(function(track){edgeTracksKind.local[track.id]=track.kind})),Object.keys(output.raw).forEach(function(prop){if(0!==prop.indexOf("ssrc_")||output.raw[prop].mediaType){if("edge"===AdapterJS.webrtcDetectedBrowser&&!output.raw[prop].mediaType&&["inboundrtp","outboundrtp"].indexOf(output.raw[prop].type)>-1){var trackItem=output.raw[output.raw[prop].mediaTrackId]||{};output.raw[prop].mediaType=edgeTracksKind[output.raw[prop].isRemote?"remote":"local"][trackItem.trackIdentifier]||""}}else output.raw[prop].mediaType=output.raw[prop].audioInputLevel||output.raw[prop].audioOutputLevel?"audio":"video";certificateFn(output.raw[prop],prop),candidatePairFn(output.raw[prop],prop),codecsFn(output.raw[prop],prop),audioStatsFn(output.raw[prop],prop),videoStatsFn(output.raw[prop],prop),videoE2EStatsFn(output.raw[prop],prop),isAutoBwStats&&!self._peerBandwidth[peerId][prop]?self._peerBandwidth[peerId][prop]=output.raw[prop]:isAutoBwStats||self._peerStats[peerId][prop]||(self._peerStats[peerId][prop]=output.raw[prop])}),output.audio.sending.bytes=output.audio.sending.bytes||0,output.audio.sending.packets=output.audio.sending.packets||0,output.audio.sending.totalBytes=output.audio.sending.totalBytes||0,output.audio.sending.totalPackets=output.audio.sending.totalPackets||0,output.video.sending.bytes=output.video.sending.bytes||0,output.video.sending.packets=output.video.sending.packets||0,output.video.sending.totalBytes=output.video.sending.totalBytes||0,output.video.sending.totalPackets=output.video.sending.totalPackets||0,output.audio.receiving.bytes=output.audio.receiving.bytes||0,output.audio.receiving.packets=output.audio.receiving.packets||0,output.audio.receiving.totalBytes=output.audio.receiving.totalBytes||0,output.audio.receiving.totalPackets=output.audio.receiving.totalPackets||0,output.video.receiving.bytes=output.video.receiving.bytes||0,output.video.receiving.packets=output.video.receiving.packets||0,output.video.receiving.totalBytes=output.video.receiving.totalBytes||0,output.video.receiving.totalPackets=output.video.receiving.totalPackets||0,callback(null,output)},errorCbFn=function(error){beSilentOnLogs||log.error([peerId,"RTCStatsReport",null,"Failed retrieving stats ->"],error),callback(error,null)};if("function"!=typeof pc.getStats)return errorCbFn(new Error("getStats() API is not available."));"plugin"===AdapterJS.webrtcDetectedType?pc.getStats(null,successCbFn,errorCbFn):pc.getStats(null).then(successCbFn).catch(errorCbFn)},Skylink.prototype._addPeer=function(targetMid,cert,peerBrowser,receiveOnly,isSS){var self=this;return self._peerConnections[targetMid]?void log.error([targetMid,null,null,"Connection to peer has already been made"]):(self._peerConnStatus[targetMid]={connected:!1,init:!1},log.log([targetMid,null,null,"Starting the connection to peer. Options provided:"],{peerBrowser:peerBrowser,receiveOnly:receiveOnly,enableDataChannel:self._enableDataChannel}),log.info("Adding peer",isSS),self._peerConnections[targetMid]=self._createPeerConnection(targetMid,!!isSS,cert),self._peerConnections[targetMid]?(self._peerConnStatus[targetMid].init=!0,void(self._peerConnections[targetMid].hasScreen=!!isSS)):void log.error([targetMid,null,null,"Failed creating the connection to peer."]))},Skylink.prototype._restartPeerConnection=function(peerId,doIceRestart,bwOptions,callback){var self=this;if(!self._peerConnections[peerId])return void log.error([peerId,null,null,"Peer does not have an existing connection. Unable to restart"]);var pc=self._peerConnections[peerId],agent=(self.getPeerInfo(peerId)||{}).agent||{};if(self._isLowerThanVersion(agent.SMProtocolVersion||"","0.1.2")){var notSupportedError=new Error("Failed restarting with other agents connecting from other SDKs as re-negotiation is not supported by other SDKs");return log.warn([peerId,"RTCPeerConnection",null,"Ignoring restart request as agent's SDK does not support it"],notSupportedError),void("function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(notSupportedError)))}if(pc.signalingState===self.PEER_CONNECTION_STATE.STABLE&&self._peerConnections[peerId]){log.log([peerId,null,null,"Sending restart message to signaling server ->"],{iceRestart:doIceRestart,options:bwOptions}),self._peerCustomConfigs[peerId]=self._peerCustomConfigs[peerId]||{},self._peerCustomConfigs[peerId].bandwidth=self._peerCustomConfigs[peerId].bandwidth||{},self._peerCustomConfigs[peerId].googleXBandwidth=self._peerCustomConfigs[peerId].googleXBandwidth||{},bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._peerCustomConfigs[peerId].bandwidth.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._peerCustomConfigs[peerId].bandwidth.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._peerCustomConfigs[peerId].bandwidth.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._peerCustomConfigs[peerId].googleXBandwidth.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._peerCustomConfigs[peerId].googleXBandwidth.max=bwOptions.googleXBandwidth.max));var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(peerId),target:peerId,weight:self._peerPriorityWeight,receiveOnly:self.getPeerInfo().config.receiveOnly,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===doIceRestart&&self._enableIceRestart&&self._peerInformations[peerId]&&self._peerInformations[peerId].config.enableIceRestart,isRestartResend:!1,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._peerEndOfCandidatesCounter[peerId]=self._peerEndOfCandidatesCounter[peerId]||{},self._peerEndOfCandidatesCounter[peerId].len=0,self._sendChannelMessage(restartMsg),self._trigger("peerRestart",peerId,self.getPeerInfo(peerId),!0,!0===doIceRestart),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart callback"]),callback(null))}else if(pc.signalingState===self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER){var hasLocalDescription=pc.localDescription&&pc.localDescription.sdp;if(hasLocalDescription)self._sendChannelMessage({type:pc.localDescription.type,sdp:pc.localDescription.sdp,mid:self._user.sid,target:peerId,rid:self._room.id,restart:!0});else{var noLocalDescriptionError="Failed re-sending localDescription as there is no localDescription set to connection. There could be a handshaking step error";log.error([peerId,"RTCPeerConnection",null,noLocalDescriptionError],{localDescription:pc.localDescription,remoteDescription:pc.remoteDescription}),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(noLocalDescriptionError)))}}else{var unableToRestartError="Failed restarting as peer connection state is "+pc.signalingState;log.warn([peerId,"RTCPeerConnection",null,unableToRestartError]),"function"==typeof callback&&(log.debug([peerId,"RTCPeerConnection",null,"Firing restart failure callback"]),callback(new Error(unableToRestartError)))}},Skylink.prototype._removePeer=function(peerId){if(!this._peerConnections[peerId]&&!this._peerInformations[peerId])return void log.debug([peerId,"RTCPeerConnection",null,"Dropping the hangup from Peer as not connected to Peer at all."]);var peerInfo=clone(this.getPeerInfo(peerId))||{userData:"",settings:{audio:!1,video:!1,data:!1},mediaStatus:{audioMuted:!0,videoMuted:!0},agent:{name:"unknown",version:0,os:"",pluginVersion:null},config:{enableDataChannel:!0,enableIceRestart:!1,enableIceTrickle:!0,priorityWeight:0,publishOnly:!1,receiveOnly:!0},parentId:null,room:clone(this._selectedRoom)};"MCU"!==peerId?this._trigger("peerLeft",peerId,peerInfo,!1):(this._hasMCU=!1,log.log([peerId,null,null,"MCU has stopped listening and left"]),this._trigger("serverPeerLeft",peerId,this.SERVER_PEER_TYPE.MCU)),this._peerConnections[peerId]&&(this._peerConnections[peerId].signalingState!==this.PEER_CONNECTION_STATE.CLOSED&&(this._peerConnections[peerId].close(),"AppleWebKit"===AdapterJS.webrtcDetectedType&&(this._peerConnections[peerId].signalingStateClosed||(this._peerConnections[peerId].signalingStateClosed=!0,this._trigger("peerConnectionState",this.PEER_CONNECTION_STATE.CLOSED,peerId)),this._peerConnections[peerId].iceConnectionStateClosed||(this._peerConnections[peerId].iceConnectionStateClosed=!0,this._trigger("iceConnectionState",this.ICE_CONNECTION_STATE.CLOSED,peerId)))),"MCU"!==peerId&&this._handleEndedStreams(peerId),delete this._peerConnections[peerId]),this._peerInformations[peerId]&&delete this._peerInformations[peerId],this._peerMessagesStamps[peerId]&&delete this._peerMessagesStamps[peerId],this._streamsSession[peerId]&&delete this._streamsSession[peerId],this._peerEndOfCandidatesCounter[peerId]&&delete this._peerEndOfCandidatesCounter[peerId],this._peerCandidatesQueue[peerId]&&delete this._peerCandidatesQueue[peerId],this._sdpSessions[peerId]&&delete this._sdpSessions[peerId],this._peerStats[peerId]&&delete this._peerStats[peerId],this._peerBandwidth[peerId]&&delete this._peerBandwidth[peerId],this._gatheredCandidates[peerId]&&delete this._gatheredCandidates[peerId],this._peerCustomConfigs[peerId]&&delete this._peerCustomConfigs[peerId],this._peerConnStatus[peerId]&&delete this._peerConnStatus[peerId],this._dataChannels[peerId]&&this._closeDataChannel(peerId),log.log([peerId,"RTCPeerConnection",null,"Successfully removed peer"])},Skylink.prototype._createPeerConnection=function(targetMid,isScreenSharing,cert){var pc,self=this;if(self._inRoom&&self._room&&self._room.connection&&self._room.connection.peerConfig&&Array.isArray(self._room.connection.peerConfig.iceServers)){var constraints={iceServers:self._room.connection.peerConfig.iceServers,iceTransportPolicy:self._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(self._useEdgeWebRTC&&window.msRTCPeerConnection?window.msRTCPeerConnection:RTCPeerConnection)(constraints,optional)}catch(error){return log.error([targetMid,null,null,"Failed creating peer connection:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),null}pc.setOffer="",pc.setAnswer="",pc.hasStream=!1,pc.hasScreen=!!isScreenSharing,pc.hasMainChannel=!1,pc.firefoxStreamId="",pc.processingLocalSDP=!1,pc.processingRemoteSDP=!1,pc.gathered=!1,pc.gathering=!1,pc.localStream=null,pc.localStreamId=null,pc.remoteStream=null,pc.remoteStreamId=null,pc.iceConnectionStateClosed=!1,pc.signalingStateClosed=!1,self._gatheredCandidates[targetMid]={sending:{host:[],srflx:[],relay:[]},receiving:{host:[],srflx:[],relay:[]}},self._streamsSession[targetMid]=self._streamsSession[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._sdpSessions[targetMid]={local:{},remote:{}},self._peerBandwidth[targetMid]={};var bandwidth=null;return pc.ondatachannel=function(event){var dc=event.channel||event;if(log.debug([targetMid,"RTCDataChannel",dc.label,"Received datachannel ->"],dc),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel){self.DATA_CHANNEL_TYPE.DATA,dc.label;pc.hasMainChannel||(self.DATA_CHANNEL_TYPE.MESSAGING,"main",pc.hasMainChannel=!0),self._createDataChannel(targetMid,dc)}else log.warn([targetMid,"RTCDataChannel",dc.label,"Not adding datachannel as enable datachannel is set to false"])},pc.onaddstream=function(evt){if(self._peerConnections[targetMid]){var stream=evt.stream||evt;if("MCU"===targetMid)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received remote stream from MCU ->"],stream);if(!self._sdpSettings.direction.audio.receive&&!self._sdpSettings.direction.video.receive)return void log.warn([targetMid,"MediaStream",pc.remoteStreamId,"Ignoring received empty remote stream ->"],stream);pc.remoteStream=stream,pc.remoteStreamId=pc.remoteStreamId||stream.id||stream.label;var peerSettings=clone(self.getPeerInfo(targetMid).settings);self._streamsSession[targetMid][pc.remoteStreamId]=peerSettings,0===stream.getAudioTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].audio=!1),0===stream.getVideoTracks().length&&(self._streamsSession[targetMid][pc.remoteStreamId].video=!1),pc.hasStream=!0,pc.hasScreen=peerSettings.video&&"object"==typeof peerSettings.video&&peerSettings.video.screenshare,self._onRemoteStreamAdded(targetMid,stream,!!pc.hasScreen)}},pc.onicecandidate=function(event){self._onIceCandidate(targetMid,event.candidate||event)},pc.oniceconnectionstatechange=function(evt){var iceConnectionState=pc.iceConnectionState;if(log.debug([targetMid,"RTCIceConnectionState",null,"Ice connection state changed ->"],iceConnectionState),"edge"===AdapterJS.webrtcDetectedBrowser&&("connecting"===iceConnectionState?iceConnectionState=self.ICE_CONNECTION_STATE.CHECKING:"new"===iceConnectionState&&(iceConnectionState=self.ICE_CONNECTION_STATE.FAILED)),"AppleWebKit"===AdapterJS.webrtcDetectedType&&iceConnectionState===self.ICE_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.iceConnectionStateClosed||self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.CLOSED,targetMid)},10);if(self._trigger("iceConnectionState",iceConnectionState,targetMid),iceConnectionState===self.ICE_CONNECTION_STATE.FAILED&&self._enableIceTrickle&&self._trigger("iceConnectionState",self.ICE_CONNECTION_STATE.TRICKLE_FAILED,targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].connected=[self.ICE_CONNECTION_STATE.COMPLETED,self.ICE_CONNECTION_STATE.CONNECTED].indexOf(iceConnectionState)>-1),!self._hasMCU&&[self.ICE_CONNECTION_STATE.CONNECTED,self.ICE_CONNECTION_STATE.COMPLETED].indexOf(iceConnectionState)>-1&&self._bandwidthAdjuster&&!bandwidth&&"edge"!==AdapterJS.webrtcDetectedBrowser&&"edge"!==(((self._peerInformations[targetMid]||{}).agent||{}).name||"edge")){var currentBlock=0,formatTotalFn=function(arr){for(var total=0,i=0;i"],pc.signalingState),"AppleWebKit"===AdapterJS.webrtcDetectedType&&pc.signalingState===self.PEER_CONNECTION_STATE.CLOSED)return void setTimeout(function(){pc.signalingStateClosed||self._trigger("peerConnectionState",self.PEER_CONNECTION_STATE.CLOSED,targetMid)},10);self._trigger("peerConnectionState",pc.signalingState,targetMid)},pc.onicegatheringstatechange=function(){log.log([targetMid,"RTCIceGatheringState",null,"Ice gathering state changed ->"],pc.iceGatheringState),self._trigger("candidateGenerationState",pc.iceGatheringState,targetMid)},"firefox"===AdapterJS.webrtcDetectedBrowser&&(pc.removeStream=function(stream){for(var senders=pc.getSenders(),s=0;s"],restartMsg),self._sendChannelMessage(restartMsg)};bwOptions.bandwidth&&"object"==typeof bwOptions.bandwidth&&("number"==typeof bwOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=bwOptions.bandwidth.audio),"number"==typeof bwOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=bwOptions.bandwidth.video),"number"==typeof bwOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=bwOptions.bandwidth.data)),bwOptions.googleXBandwidth&&"object"==typeof bwOptions.googleXBandwidth&&("number"==typeof bwOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=bwOptions.googleXBandwidth.min),"number"==typeof bwOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=bwOptions.googleXBandwidth.max));for(var i=0;i0?callback({refreshErrors:listOfPeerRestartErrors,listOfPeers:listOfPeers},null):callback(null,{listOfPeers:listOfPeers}))};self.once("peerJoined",peerJoinedFn,function(peerId,peerInfo,isSelf){return isSelf}),self.leaveRoom(!1,function(error,success){if(error){if("function"==typeof callback){for(var i=0;i=self._peerEndOfCandidatesCounter[targetMid].expectedLen&&(!self._peerCandidatesQueue[targetMid]||0===self._peerCandidatesQueue[targetMid].length)&&!self._peerEndOfCandidatesCounter[targetMid].hasSet){log.debug([targetMid,"RTCPeerConnection",null,"Signaling of end-of-candidates remote ICE gathering."]),self._peerEndOfCandidatesCounter[targetMid].hasSet=!0;try{if("edge"===AdapterJS.webrtcDetectedBrowser){for(var mLineCounter=-1,addedMids=[],sdpLines=self._peerConnections[targetMid].remoteDescription.sdp.split("\r\n"),rejected=!1,i=0;i"],error)}}},Skylink.prototype.setUserData=function(userData){var self=this,updatedUserData="";void 0!==userData&&null!==userData&&(updatedUserData=userData),this._userData=updatedUserData,self._inRoom?(log.log("Updated userData -> ",updatedUserData),self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.UPDATE_USER,mid:self._user.sid,rid:self._room.id,userData:updatedUserData,stamp:(new Date).getTime()}),self._trigger("peerUpdated",self._user.sid,self.getPeerInfo(),!0)):log.warn("User is not in the room. Broadcast of updated information will be dropped")},Skylink.prototype.getUserData=function(peerId){if(peerId&&this._peerInformations[peerId]){var userData=this._peerInformations[peerId].userData;return null!==userData&&void 0===userData||(userData=""),userData}return this._userData},Skylink.prototype.getPeerInfo=function(peerId){var peerInfo=null;return"string"==typeof peerId&&"object"==typeof this._peerInformations[peerId]?(peerInfo=clone(this._peerInformations[peerId]),peerInfo.room=clone(this._selectedRoom),peerInfo.settings.bandwidth=peerInfo.settings.bandwidth||{},peerInfo.settings.googleXBandwidth=peerInfo.settings.googleXBandwidth||{},"boolean"==typeof peerInfo.settings.video||peerInfo.settings.video&&"object"==typeof peerInfo.settings.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"==typeof peerInfo.settings.audio||peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.audioMuted&&(peerInfo.mediaStatus.audioMuted=!0),"boolean"!=typeof peerInfo.mediaStatus.videoMuted&&(peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.maxBandwidth&&(peerInfo.settings.bandwidth=clone(peerInfo.settings.maxBandwidth),delete peerInfo.settings.maxBandwidth),peerInfo.settings.video&&"object"==typeof peerInfo.settings.video&&peerInfo.settings.video.customSettings&&"object"==typeof peerInfo.settings.video.customSettings&&(peerInfo.settings.video.customSettings.frameRate&&(peerInfo.settings.video.frameRate=clone(peerInfo.settings.video.customSettings.frameRate)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode)),peerInfo.settings.video.customSettings.width&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.width=clone(peerInfo.settings.video.customSettings.width)),peerInfo.settings.video.customSettings.height&&(peerInfo.settings.video.resolution=peerInfo.settings.video.resolution||{},peerInfo.settings.video.resolution.height=clone(peerInfo.settings.video.customSettings.height)),peerInfo.settings.video.customSettings.facingMode&&(peerInfo.settings.video.facingMode=clone(peerInfo.settings.video.customSettings.facingMode))),peerInfo.settings.audio&&"object"==typeof peerInfo.settings.audio&&(peerInfo.settings.audio.stereo=!0===peerInfo.settings.audio.stereo),null!==peerInfo.userData&&void 0!==peerInfo.userData||(peerInfo.userData=""),peerInfo.parentId=peerInfo.parentId||null,"MCU"===peerId?(peerInfo.config.receiveOnly=!0,peerInfo.config.publishOnly=!1):this._hasMCU&&(peerInfo.config.receiveOnly=!1,peerInfo.config.publishOnly=!0),this._sdpSettings.direction.audio.receive||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.direction.video.receive||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSettings.connection.audio||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSettings.connection.video||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),peerInfo.settings.data=!!(this._dataChannels[peerId]&&this._dataChannels[peerId].main&&this._dataChannels[peerId].main.channel&&this._dataChannels[peerId].main.channel.readyState===this.DATA_CHANNEL_STATE.OPEN),peerInfo.connected=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].connected,peerInfo.init=this._peerConnStatus[peerId]&&!!this._peerConnStatus[peerId].init,this._sdpSessions[peerId]&&this._sdpSessions[peerId].remote&&this._sdpSessions[peerId].remote.connection&&"object"==typeof this._sdpSessions[peerId].remote.connection&&(this._sdpSessions[peerId].remote.connection.audio&&this._sdpSessions[peerId].remote.connection.audio.indexOf("send")>-1||(peerInfo.settings.audio=!1,peerInfo.mediaStatus.audioMuted=!0),this._sdpSessions[peerId].remote.connection.video&&this._sdpSessions[peerId].remote.connection.video.indexOf("send")>-1||(peerInfo.settings.video=!1,peerInfo.mediaStatus.videoMuted=!0),this._sdpSessions[peerId].remote.connection.data&&this._sdpSessions[peerId].remote.connection.data.indexOf("send")>-1||(peerInfo.settings.data=!1))):(peerInfo={userData:clone(this._userData),settings:{audio:!1,video:!1},mediaStatus:clone(this._streamsMutedSettings),agent:{name:AdapterJS.webrtcDetectedBrowser,version:AdapterJS.webrtcDetectedVersion,os:window.navigator.platform,pluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:this.SMProtocolVersion,DTProtocolVersion:this.DTProtocolVersion},room:clone(this._selectedRoom),config:{enableDataChannel:this._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;i-1||(customSettings.settings.audio=!1,customSettings.mediaStatus.audioMuted=!0),self._sdpSessions[usePeerId].local.connection.video&&self._sdpSessions[usePeerId].local.connection.video.indexOf("send")>-1||(customSettings.settings.video=!1,customSettings.mediaStatus.videoMuted=!0),self._sdpSessions[usePeerId].local.connection.data&&self._sdpSessions[usePeerId].local.connection.data.indexOf("send")>-1||(customSettings.settings.data=!1)),customSettings},Skylink.prototype._getUserInfo=function(peerId){var userInfo=clone(this.getPeerInfo()),userCustomInfoForPeer=peerId?this._getPeerCustomSettings(peerId):null;return userCustomInfoForPeer&&"object"==typeof userCustomInfoForPeer&&(userInfo.settings=userCustomInfoForPeer.settings,userInfo.mediaStatus=userCustomInfoForPeer.mediaStatus),userInfo.settings.video&&"object"==typeof userInfo.settings.video&&(userInfo.settings.video.customSettings={},userInfo.settings.video.frameRate&&"object"==typeof userInfo.settings.video.frameRate&&(userInfo.settings.video.customSettings.frameRate=clone(userInfo.settings.video.frameRate),userInfo.settings.video.frameRate=-1),userInfo.settings.video.facingMode&&"object"==typeof userInfo.settings.video.facingMode&&(userInfo.settings.video.customSettings.facingMode=clone(userInfo.settings.video.facingMode),userInfo.settings.video.facingMode="-1"),userInfo.settings.video.resolution&&"object"==typeof userInfo.settings.video.resolution&&(userInfo.settings.video.resolution.width&&"object"==typeof userInfo.settings.video.resolution.width&&(userInfo.settings.video.customSettings.width=clone(userInfo.settings.video.width),userInfo.settings.video.resolution.width=-1),userInfo.settings.video.resolution.height&&"object"==typeof userInfo.settings.video.resolution.height&&(userInfo.settings.video.customSettings.height=clone(userInfo.settings.video.height),userInfo.settings.video.resolution.height=-1))),userInfo.settings.bandwidth&&(userInfo.settings.maxBandwidth=clone(userInfo.settings.bandwidth),delete userInfo.settings.bandwidth),this._getSDPCommonSupports(peerId).video||(userInfo.settings.video=!1,userInfo.mediaStatus.videoMuted=!0),this._getSDPCommonSupports(peerId).audio||(userInfo.settings.audio=!1,userInfo.mediaStatus.audioMuted=!0),delete userInfo.agent,delete userInfo.room,delete userInfo.config,delete userInfo.parentId,delete userInfo.settings.data,userInfo},Skylink.prototype.HANDSHAKE_PROGRESS={ENTER:"enter",WELCOME:"welcome",OFFER:"offer",ANSWER:"answer",ERROR:"error"},Skylink.prototype._doOffer=function(targetMid,iceRestart){var self=this,pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of creating of offer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription","offer",'Dropping of creating of offer as signalingState is not "'+self.PEER_CONNECTION_STATE.STABLE+'" ->'],pc.signalingState);var offerConstraints={offerToReceiveAudio:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).video,offerToReceiveVideo:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid).audio,iceRestart:!!((self._peerInformations[targetMid]||{}).config||{}).enableIceRestart&&iceRestart&&self._enableIceRestart,voiceActivityDetection:self._voiceActivityDetection};self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._enableDataChannel&&self._peerInformations[targetMid]&&self._peerInformations[targetMid].config.enableDataChannel&&(self._dataChannels[targetMid]&&self._dataChannels[targetMid].main||(self._createDataChannel(targetMid),self._peerConnections[targetMid].hasMainChannel=!0)),log.debug([targetMid,null,null,"Creating offer with config:"],offerConstraints),pc.endOfCandidates=!1,self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=offerConstraints);var onSuccessCbFn=function(offer){log.debug([targetMid,null,null,"Created offer"],offer),self._setLocalAndSendMessage(targetMid,offer)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),log.error([targetMid,null,null,"Failed creating an offer:"],error)};pc.createOffer(onSuccessCbFn,onErrorCbFn,"plugin"===AdapterJS.webrtcDetectedType?{mandatory:{OfferToReceiveAudio:offerConstraints.offerToReceiveAudio,OfferToReceiveVideo:offerConstraints.offerToReceiveVideo,iceRestart:offerConstraints.iceRestart,voiceActivityDetection:offerConstraints.voiceActivityDetection}}:offerConstraints)},Skylink.prototype._doAnswer=function(targetMid){var self=this;log.log([targetMid,null,null,"Creating answer with config:"],self._room.connection.sdpConstraints);var pc=self._peerConnections[targetMid];if(!pc)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of creating of answer as connection does not exists"]);if(pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription","answer",'Dropping of creating of answer as signalingState is not "'+self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER+'" ->'],pc.signalingState);var answerConstraints="edge"===AdapterJS.webrtcDetectedBrowser?{offerToReceiveVideo:!(!self._sdpSettings.connection.audio&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).video,offerToReceiveAudio:!(!self._sdpSettings.connection.video&&"MCU"!==targetMid)&&self._getSDPCommonSupports(targetMid,pc.remoteDescription).audio,voiceActivityDetection:self._voiceActivityDetection}:void 0;self._hasMCU&&"MCU"!==targetMid||self._addLocalMediaStreams(targetMid),self._peerConnStatus[targetMid]&&(self._peerConnStatus[targetMid].sdpConstraints=answerConstraints);var onSuccessCbFn=function(answer){log.debug([targetMid,null,null,"Created answer"],answer),self._setLocalAndSendMessage(targetMid,answer)},onErrorCbFn=function(error){log.error([targetMid,null,null,"Failed creating an answer:"],error),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.createAnswer(onSuccessCbFn,onErrorCbFn,answerConstraints)},Skylink.prototype._setLocalAndSendMessage=function(targetMid,_sessionDescription){var self=this,pc=self._peerConnections[targetMid];if(!_sessionDescription||!_sessionDescription.sdp)return void log.warn([targetMid,"RTCSessionDescription",null,"Local session description is undefined ->"],_sessionDescription);if(!pc)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as connection does not exists ->"],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.OFFER&&pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(_sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER&&pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_REMOTE_OFFER)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,'Local session description will not be set as signaling state is "'+pc.signalingState+'" ->'],_sessionDescription);if(pc.processingLocalSDP)return void log.warn([targetMid,"RTCSessionDescription",_sessionDescription.type,"Local session description will not be set as another is being processed ->"],_sessionDescription);pc.processingLocalSDP=!0;var sessionDescription={type:_sessionDescription.type,sdp:_sessionDescription.sdp};sessionDescription.sdp=self._removeSDPFirefoxH264Pref(targetMid,sessionDescription),sessionDescription.sdp=self._setSDPCodecParams(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPUnknownAptRtx(targetMid,sessionDescription),sessionDescription.sdp=self._removeSDPCodecs(targetMid,sessionDescription),sessionDescription.sdp=self._handleSDPConnectionSettings(targetMid,sessionDescription,"local"),sessionDescription.sdp=self._removeSDPREMBPackets(targetMid,sessionDescription),log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description updated ->"],sessionDescription.sdp);var onSuccessCbFn=function(){if(log.debug([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description has been set ->"],sessionDescription),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",sessionDescription.type,targetMid),sessionDescription.type===self.HANDSHAKE_PROGRESS.ANSWER?pc.setAnswer="local":pc.setOffer="local",!self._enableIceTrickle&&!pc.gathered)return void log.log([targetMid,"RTCSessionDescription",sessionDescription.type,"Local session description sending is halted to complete ICE gathering."]);self._sendChannelMessage({type:sessionDescription.type,sdp:self._renderSDPOutput(targetMid,sessionDescription),mid:self._user.sid,target:targetMid,rid:self._room.id,userInfo:self._getUserInfo(targetMid)})},onErrorCbFn=function(error){log.error([targetMid,"RTCSessionDescription",sessionDescription.type,"Local description failed setting ->"],error),pc.processingLocalSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error)};pc.setLocalDescription(new RTCSessionDescription(sessionDescription),onSuccessCbFn,onErrorCbFn)},Skylink.prototype.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={},timestamp=(new Date).getTime()+Math.floor(1e4*Math.random());self._joinRoomManager.timestamp=timestamp,room&&"string"==typeof room?selectedRoom=room:room&&"object"==typeof room?mediaOptions=room:"function"==typeof room&&(callback=room),options&&"object"==typeof options?mediaOptions=options:"function"==typeof options&&(callback=options);var resolveAsErrorFn=function(error,tryRoom,readyState){log.error(error),"function"==typeof callback&&callback({room:tryRoom,errorCode:readyState||null,error:error instanceof Error?error:new Error(JSON.stringify(error))})},joinRoomFn=function(){if(self._joinRoomManager.timestamp!==timestamp)return void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom);self._initSelectedRoom(selectedRoom,function(initError,initSuccess){return initError?void resolveAsErrorFn(initError.error,self._selectedRoom,self._readyState):self._joinRoomManager.timestamp!==timestamp?void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom):void self._waitForOpenChannel(mediaOptions||{},timestamp,function(error,success){if(error)return void resolveAsErrorFn(error,self._selectedRoom,self._readyState);if(self._joinRoomManager.timestamp!==timestamp)return void resolveAsErrorFn("joinRoom() process did not complete",selectedRoom);if("AppleWebKit"===AdapterJS.webrtcDetectedType){var checkStream=self._streams.screenshare&&self._streams.screenshare.stream?self._streams.screenshare.stream:self._streams.userMedia&&self._streams.userMedia.stream?self._streams.userMedia.stream:null;checkStream&&0!==checkStream.getTracks().length?0===checkStream.getAudioTracks().length?log.warn("Note that receiving audio streams may fail as safari 11 needs stream with audio and video tracks and not just with video tracks"):0===checkStream.getVideoTracks().length&&log.warn("Note that receiving video streams may fail as safari 11 needs stream with audio and video tracks and not just with audio tracks"):log.warn("Note that receiving audio and video streams may fail as safari 11 needs stream with audio and video tracks")}if("function"==typeof callback){var peerOnJoin=function(peerId,peerInfo,isSelf){self.off("systemAction",peerFailedJoin),self.off("channelClose",peerSocketFailedJoin),log.info([null,"Room",selectedRoom,"Connected to Room ->"],peerInfo),callback(null,{room:self._selectedRoom,peerId:peerId,peerInfo:peerInfo})},peerFailedJoin=function(action,message){self.off("peerJoined",peerOnJoin),self.off("channelClose",peerSocketFailedJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room ->"],message),resolveAsErrorFn(new Error(message),self._selectedRoom,self._readyState)},peerSocketFailedJoin=function(){self.off("systemAction",peerFailedJoin),self.off("peerJoined",peerOnJoin),log.error([null,"Room",selectedRoom,"Failed connecting to Room due to abrupt disconnection."]),resolveAsErrorFn(new Error("Channel closed abruptly before session was established"),self._selectedRoom,self._readyState)};self.once("peerJoined",peerOnJoin,function(peerId,peerInfo,isSelf){return peerInfo.room===selectedRoom&&isSelf}),self.once("systemAction",peerFailedJoin,function(action){return action===self.SYSTEM_ACTION.REJECT}),self.once("channelClose",peerSocketFailedJoin)}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.JOIN_ROOM,uid:self._user.uid,cid:self._key,rid:self._room.id,userCred:self._user.token,timeStamp:self._user.timeStamp,apiOwner:self._appKeyOwner,roomCred:self._room.token,start:self._room.startDateTime,len:self._room.duration,isPrivileged:!0===self._isPrivileged,autoIntroduce:!1!==self._autoIntroduce,key:self._appKey})})})};if(null===room||["number","boolean"].indexOf(typeof room)>-1)return void resolveAsErrorFn("Invalid room name is provided",room);if(null===options||["number","boolean"].indexOf(typeof options)>-1)return void resolveAsErrorFn("Invalid mediaOptions is provided",selectedRoom);self._joinRoomManager.socketsFn.forEach(function(fnItem){fnItem(timestamp)}),self._joinRoomManager.socketsFn=[];var stopStream=!1===mediaOptions.audio&&!1===mediaOptions.video;self._inRoom?self.leaveRoom({userMedia:stopStream},function(lRError,lRSuccess){log.debug([null,"Room",previousRoom,"Leave Room callback result ->"],[lRError,lRSuccess]),joinRoomFn()}):(stopStream&&self.stopStream(),joinRoomFn())},Skylink.prototype.leaveRoom=function(stopMediaOptions,callback){var self=this,stopUserMedia=!0,stopScreenshare=!0,previousRoom=self._selectedRoom,previousUserPeerId=self._user?self._user.sid:null,peersThatLeft=[],isNotInRoom=!self._inRoom;"boolean"==typeof stopMediaOptions?!1===stopMediaOptions&&(stopUserMedia=!1,stopScreenshare=!1):stopMediaOptions&&"object"==typeof stopMediaOptions?(stopUserMedia=!1!==stopMediaOptions.userMedia,stopScreenshare=!1!==stopMediaOptions.screenshare):"function"==typeof stopMediaOptions&&(callback=stopMediaOptions);for(var infoPeerId in self._peerInformations)self._peerInformations.hasOwnProperty(infoPeerId)&&self._peerInformations[infoPeerId]&&(peersThatLeft.push(infoPeerId),self._removePeer(infoPeerId));for(var connPeerId in self._peerConnections)self._peerConnections.hasOwnProperty(connPeerId)&&self._peerConnections[connPeerId]&&-1===peersThatLeft.indexOf(connPeerId)&&(peersThatLeft.push(connPeerId),self._removePeer(connPeerId));if(self._inRoom=!1,self._closeChannel(),isNotInRoom){var notInRoomError="Unable to leave room as user is not in any room";return log.error([null,"Room",previousRoom,notInRoomError]),void("function"==typeof callback&&callback(new Error(notInRoomError),null))}self._stopStreams({userMedia:stopUserMedia,screenshare:stopScreenshare}),self._wait(function(){log.log([null,"Room",previousRoom,"User left the room"]),self._trigger("peerLeft",previousUserPeerId,self.getPeerInfo(),!0),"function"==typeof callback&&callback(null,{peerId:previousUserPeerId,previousRoom:previousRoom})},function(){return!self._channelOpen})},Skylink.prototype.lockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!0),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!0}),this._roomLocked=!0,this._trigger("roomLock",!0,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype.unlockRoom=function(){this._user&&this._user.sid&&(log.log("Update to isRoomLocked status ->",!1),this._sendChannelMessage({type:this._SIG_MESSAGE_TYPE.ROOM_LOCK,mid:this._user.sid,rid:this._room.id,lock:!1}),this._roomLocked=!1,this._trigger("roomLock",!1,this._user.sid,this.getPeerInfo(),!0))},Skylink.prototype._waitForOpenChannel=function(mediaOptions,joinRoomTimestamp,callback){var self=this;self._socketCurrentReconnectionAttempt=0,self._wait(function(){var onChannelOpen=function(){self.off("socketError",onChannelError),setTimeout(function(){if(mediaOptions=mediaOptions||{},self._userData=mediaOptions.userData||self._userData||"",self._streamsBandwidthSettings={googleX:{},bAS:{}},self._publishOnly=!1,self._sdpSettings={connection:{audio:!0,video:!0,data:!0},direction:{audio:{send:!0,receive:!0},video:{send:!0,receive:!0}}},self._voiceActivityDetection="boolean"!=typeof mediaOptions.voiceActivityDetection||mediaOptions.voiceActivityDetection,self._peerConnectionConfig={bundlePolicy:self.BUNDLE_POLICY.BALANCED,rtcpMuxPolicy:self.RTCP_MUX_POLICY.REQUIRE,iceCandidatePoolSize:0,certificate:self.PEER_CERTIFICATE.AUTO},self._bandwidthAdjuster=null,mediaOptions.bandwidth&&("number"==typeof mediaOptions.bandwidth.audio&&(self._streamsBandwidthSettings.bAS.audio=mediaOptions.bandwidth.audio),"number"==typeof mediaOptions.bandwidth.video&&(self._streamsBandwidthSettings.bAS.video=mediaOptions.bandwidth.video),"number"==typeof mediaOptions.bandwidth.data&&(self._streamsBandwidthSettings.bAS.data=mediaOptions.bandwidth.data)),mediaOptions.googleXBandwidth&&("number"==typeof mediaOptions.googleXBandwidth.min&&(self._streamsBandwidthSettings.googleX.min=mediaOptions.googleXBandwidth.min),"number"==typeof mediaOptions.googleXBandwidth.max&&(self._streamsBandwidthSettings.googleX.max=mediaOptions.googleXBandwidth.max)),mediaOptions.sdpSettings&&(mediaOptions.sdpSettings.direction&&(mediaOptions.sdpSettings.direction.audio&&(self._sdpSettings.direction.audio.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.receive||mediaOptions.sdpSettings.direction.audio.receive,self._sdpSettings.direction.audio.send="boolean"!=typeof mediaOptions.sdpSettings.direction.audio.send||mediaOptions.sdpSettings.direction.audio.send),mediaOptions.sdpSettings.direction.video&&(self._sdpSettings.direction.video.receive="boolean"!=typeof mediaOptions.sdpSettings.direction.video.receive||mediaOptions.sdpSettings.direction.video.receive,self._sdpSettings.direction.video.send="boolean"!=typeof mediaOptions.sdpSettings.direction.video.send||mediaOptions.sdpSettings.direction.video.send)),mediaOptions.sdpSettings.connection&&(self._sdpSettings.connection.audio="boolean"!=typeof mediaOptions.sdpSettings.connection.audio||mediaOptions.sdpSettings.connection.audio,self._sdpSettings.connection.video="boolean"!=typeof mediaOptions.sdpSettings.connection.video||mediaOptions.sdpSettings.connection.video,self._sdpSettings.connection.data="boolean"!=typeof mediaOptions.sdpSettings.connection.data||mediaOptions.sdpSettings.connection.data)),mediaOptions.publishOnly&&(self._sdpSettings.direction.audio.send=!0,self._sdpSettings.direction.audio.receive=!1,self._sdpSettings.direction.video.send=!0,self._sdpSettings.direction.video.receive=!1,self._publishOnly=!0,"object"==typeof mediaOptions.publishOnly&&mediaOptions.publishOnly.parentId&&"string"==typeof mediaOptions.publishOnly.parentId&&(self._parentId=mediaOptions.publishOnly.parentId)),mediaOptions.parentId&&(self._parentId=mediaOptions.parentId),mediaOptions.peerConnection&&"object"==typeof mediaOptions.peerConnection){if("string"==typeof mediaOptions.peerConnection.bundlePolicy)for(var bpProp in self.BUNDLE_POLICY)self.BUNDLE_POLICY.hasOwnProperty(bpProp)&&self.BUNDLE_POLICY[bpProp]===mediaOptions.peerConnection.bundlePolicy&&(self._peerConnectionConfig.bundlePolicy=mediaOptions.peerConnection.bundlePolicy);if("string"==typeof mediaOptions.peerConnection.rtcpMuxPolicy)for(var rmpProp in self.RTCP_MUX_POLICY)self.RTCP_MUX_POLICY.hasOwnProperty(rmpProp)&&self.RTCP_MUX_POLICY[rmpProp]===mediaOptions.peerConnection.rtcpMuxPolicy&&(self._peerConnectionConfig.rtcpMuxPolicy=mediaOptions.peerConnection.rtcpMuxPolicy);if("number"==typeof mediaOptions.peerConnection.iceCandidatePoolSize&&mediaOptions.peerConnection.iceCandidatePoolSize>0&&(self._peerConnectionConfig.iceCandidatePoolSize=mediaOptions.peerConnection.iceCandidatePoolSize),"string"==typeof mediaOptions.peerConnection.certificate)for(var pcProp in self.PEER_CERTIFICATE)self.PEER_CERTIFICATE.hasOwnProperty(pcProp)&&self.PEER_CERTIFICATE[pcProp]===mediaOptions.peerConnection.certificate&&(self._peerConnectionConfig.certificate=mediaOptions.peerConnection.certificate)}if(mediaOptions.autoBandwidthAdjustment&&(self._bandwidthAdjuster={interval:10,limitAtPercentage:100,useUploadBwOnly:!1},"object"==typeof mediaOptions.autoBandwidthAdjustment&&("number"==typeof mediaOptions.autoBandwidthAdjustment.interval&&mediaOptions.autoBandwidthAdjustment.interval>=10&&(self._bandwidthAdjuster.interval=mediaOptions.autoBandwidthAdjustment.interval),"number"==typeof mediaOptions.autoBandwidthAdjustment.limitAtPercentage&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage>=0&&mediaOptions.autoBandwidthAdjustment.limitAtPercentage<=100&&(self._bandwidthAdjuster.limitAtPercentage=mediaOptions.autoBandwidthAdjustment.limitAtPercentage),"boolean"==typeof mediaOptions.autoBandwidthAdjustment.useUploadBwOnly&&(self._bandwidthAdjuster.useUploadBwOnly=mediaOptions.autoBandwidthAdjustment.useUploadBwOnly))),!0===mediaOptions.manualGetUserMedia){self._trigger("mediaAccessRequired");var current50Block=0,mediaAccessRequiredFailure=!1;return void self._wait(function(){!0===mediaAccessRequiredFailure?self._onUserMediaError(new Error("Waiting for stream timeout"),!1,!1):callback(null,self._streams.userMedia.stream)},function(){return current50Block+=1,600===current50Block?(mediaAccessRequiredFailure=!0,!0):!(!self._streams.userMedia||!self._streams.userMedia.stream)||void 0},50)}if(mediaOptions.audio||mediaOptions.video)return void self.getUserMedia({useExactConstraints:!!mediaOptions.useExactConstraints,audio:mediaOptions.audio,video:mediaOptions.video},function(error,success){error?callback(error,null):callback(null,success)});callback(null,null)},1)},onChannelError=function(errorState,error){self.off("channelOpen",onChannelOpen),callback(error)};self._channelOpen?onChannelOpen():(self.once("channelOpen",onChannelOpen),self.once("socketError",onChannelError,function(errorState){return errorState===self.SOCKET_ERROR.RECONNECTION_ABORTED}),self._openChannel(joinRoomTimestamp))},function(){return self._readyState===self.READY_STATE_CHANGE.COMPLETED})},Skylink.prototype.VERSION="0.6.26",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,XML_HTTP_NO_REPONSE_ERROR:-2,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=!0,socketTimeout=7e3,apiTimeout=4e3,forceTURNSSL=!1,audioCodec=self.AUDIO_CODEC.AUTO,videoCodec=self.VIDEO_CODEC.AUTO,forceTURN=!1,usePublicSTUN=!1,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,useEdgeWebRTC=!1,enableSimultaneousTransfers=!0;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&&socketTimeout<5e3&&socketTimeout>0?options.socketTimeout:socketTimeout,apiTimeout="number"==typeof options.apiTimeout&&options.apiTimeout>0?options.apiTimeout:apiTimeout,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,useEdgeWebRTC="boolean"==typeof options.useEdgeWebRTC?options.useEdgeWebRTC:useEdgeWebRTC,enableSimultaneousTransfers="boolean"==typeof options.enableSimultaneousTransfers?options.enableSimultaneousTransfers:enableSimultaneousTransfers,"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,"sprop-stereo":"boolean"==typeof options.codecParams.audio.opus["sprop-stereo"]?options.codecParams.audio.opus["sprop-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),!0===forceTURN&&(enableTURNServer=!0,enableSTUNServer=!1,filterCandidatesType.host=!0,filterCandidatesType.srflx=!0,filterCandidatesType.relay=!1)}if("edge"===AdapterJS.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._apiTimeout=apiTimeout,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,self._useEdgeWebRTC=useEdgeWebRTC,self._enableSimultaneousTransfers=enableSimultaneousTransfers,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,apiTimeout:self._apiTimeout,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,useEdgeWebRTC:self._useEdgeWebRTC,enableSimultaneousTransfers:self._enableSimultaneousTransfers}),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,apiTimeout:self._apiTimeout,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,useEdgeWebRTC:self._useEdgeWebRTC,enableSimultaneousTransfers:self._enableSimultaneousTransfers})):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:error.content instanceof Error?error.content:new Error(JSON.stringify(error.content)),errorCode:error.errorCode,status:error.status},null)))};self.on("readyStateChange",readyStateChangeFn)}self._loadInfo()},Skylink.prototype._requestServerInfo=function(method,url,callback,params){var self=this,retries=0;self._socketUseXDR="function"==typeof window.XDomainRequest||"object"==typeof window.XDomainRequest,url=self._forceSSL?"https:"+url:url,function requestFn(){var xhr=new XMLHttpRequest,completed=!1;self._socketUseXDR&&(log.debug([null,"XMLHttpRequest",method,"Using XDomainRequest for CORS authentication."]),xhr=new XDomainRequest,xhr.setContentType=function(contentType){xhr.contentType=contentType}),xhr.onload=function(){if(!completed){completed=!0;var response=JSON.parse(xhr.responseText||xhr.response||"{}"),status=xhr.status||200;log.debug([null,"XMLHttpRequest",method,"Received sessions parameters ->"],response),callback(status,response)}},xhr.onerror=function(error){completed||(completed=!0,log.error([null,"XMLHttpRequest",method,"Failed retrieving information with 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,params:params})};try{xhr.open(method,url,!0),params?(xhr.setContentType("application/json;charset=UTF-8"),xhr.send(JSON.stringify(params))):xhr.send()}catch(error){return completed=!0,self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"Failed starting XHR process.",errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR},self._selectedRoom)}setTimeout(function(){completed||(completed=!0,xhr.onload=null,xhr.onerror=null,xhr.onprogress=null,retries<2?(retries++,requestFn()):(self._readyState=-1,self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:xhr.status||null,content:"Response timed out from API server",errorCode:self.READY_STATE_CHANGE_ERROR.XML_HTTP_NO_REPONSE_ERROR},self._selectedRoom)))},self._apiTimeout)}()},Skylink.prototype._parseInfo=function(info){if(log.log("Parsing parameter from server",info),!info.pc_constraints&&!info.offer_constraints)return void this._trigger("readyStateChange",this.READY_STATE_CHANGE.ERROR,{status:200,content:info.info,errorCode:info.error},self._selectedRoom);log.debug("Peer connection constraints:",info.pc_constraints),log.debug("Offer constraints:",info.offer_constraints),this._key=info.cid,this._appKeyOwner=info.apiOwner,this._signalingServer=info.ipSigserver,this._isPrivileged=info.isPrivileged,this._autoIntroduce=info.autoIntroduce,this._user={uid:info.username,token:info.userCred,timeStamp:info.timeStamp,streams:[],info:{}},this._room={id:info.room_key,token:info.roomCred,startDateTime:info.start,duration:info.len,connection:{peerConstraints:JSON.parse(info.pc_constraints),peerConfig:null,offerConstraints:JSON.parse(info.offer_constraints),sdpConstraints:{mandatory:{OfferToReceiveAudio:!0,OfferToReceiveVideo:!0}},mediaConstraints:JSON.parse(info.media_constraints)}},this._socketPorts={"http:":Array.isArray(info.httpPortList)&&info.httpPortList.length>0?info.httpPortList:[80,3e3],"https:":Array.isArray(info.httpsPortList)&&info.httpsPortList.length>0?info.httpsPortList:[443,3443]},this._readyState=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;if("function"!=typeof(globals.AdapterJS||window.AdapterJS||{}).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 globals.io||window.io?window.XMLHttpRequest?self._path?void AdapterJS.webRTCReady(function(){if(self._enableIceRestart="firefox"!==AdapterJS.webrtcDetectedBrowser||AdapterJS.webrtcDetectedVersion>=48,self._binaryChunkType="firefox"===AdapterJS.webrtcDetectedBrowser?self.DATA_TRANSFER_DATA_TYPE.BLOB:self.DATA_TRANSFER_DATA_TYPE.ARRAY_BUFFER,!function(){try{var p=new window.RTCPeerConnection(null);return["object","function"].indexOf(typeof p.createOffer)>-1&&null!==p.createOffer}catch(e){return!1}}())return window.RTCPeerConnection&&"plugin"===AdapterJS.webrtcDetectedType?log.error("Plugin is not available. Please check plugin status."):log.error("WebRTC not supported. Please upgrade your browser"),self._readyState=-1,void self._trigger("readyStateChange",self.READY_STATE_CHANGE.ERROR,{status:null,content:"plugin"===AdapterJS.webrtcDetectedType&&window.RTCPeerConnection?"Plugin is not available":"WebRTC not available",errorCode:self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT},self._selectedRoom);self._getCodecsSupport(function(error){return error?(log.error(error),self._readyState=-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,apiTimeout:self._apiTimeout,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,useEdgeWebRTC:self._useEdgeWebRTC,enableSimultaneousTransfers:self._enableSimultaneousTransfers};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_KEY="SkylinkJS",_LOG_LEVELS=["error","warn","info","log","debug"],_logLevel=0,_enableDebugMode=!1,_enableDebugStack=!1,_enableDebugTrace=!1,_printTimestamp=!1,_storedLogs=[],_getStoredLogsFn=function(logLevel){if(void 0===logLevel)return _storedLogs;for(var returnLogs=[],i=0;i<_storedLogs.length;i++)_storedLogs[i][1]===_LOG_LEVELS[logLevel]&&returnLogs.push(_storedLogs[i]);return returnLogs},_clearAllStoredLogsFn=function(){_storedLogs=[]},_printAllStoredLogsFn=function(){for(var i=0;i<_storedLogs.length;i++){var timestamp=_storedLogs[i][0],log="undefined"!==console[_storedLogs[i][1]]?_storedLogs[i][1]:"log",message=_storedLogs[i][2],debugObject=_storedLogs[i][3];void 0!==debugObject?console[log](message,debugObject,timestamp):console[log](message,timestamp)}},SkylinkLogs={getLogs:_getStoredLogsFn,clearAllLogs:_clearAllStoredLogsFn,printAllLogs:_printAllStoredLogsFn},_logFn=function(logLevel,message,debugObject){var outputLog="",datetime=new Date;if("object"==typeof message){if(outputLog+=message[0]?" ["+message[0]+"] -":" -",outputLog+=message[1]?" <<"+message[1]+">>":"",message[2])if(outputLog+=" ","object"==typeof message[2])for(var i=0;i=logLevel)if(logLevel=void 0===console[_LOG_LEVELS[logLevel]]?3:logLevel,_enableDebugMode&&_enableDebugTrace){void 0===console.trace&&logLevel[3];void 0!==debugObject?(console[_LOG_LEVELS[logLevel]](outputLog,debugObject),void 0!==console.trace&&console.trace("")):(console[_LOG_LEVELS[logLevel]](outputLog),void 0!==console.trace&&console.trace(""))}else void 0!==debugObject?console[_LOG_LEVELS[logLevel]](outputLog,debugObject):console[_LOG_LEVELS[logLevel]](outputLog)},log={debug:function(message,object){_logFn(4,message,object)},log:function(message,object){_logFn(3,message,object)},info:function(message,object){_logFn(2,message,object)},warn:function(message,object){_logFn(1,message,object)},error:function(message,object){_logFn(0,message,object)}};Skylink.prototype.setLogLevel=function(logLevel){for(var level in this.LOG_LEVEL)if(this.LOG_LEVEL[level]===logLevel)return _logLevel=logLevel,void log.log([null,"Log",level,"Log level exists. Level is set"]);log.error([null,"Log",level,"Log level does not exist. Level is not set"])},Skylink.prototype.setDebugMode=function(isDebugMode){isDebugMode&&"object"==typeof isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0===isDebugMode.trace,_enableDebugStack=!0===isDebugMode.storeLogs,_printTimestamp=!0===isDebugMode.printTimestamp):!0===isDebugMode?(_enableDebugMode=!0,_enableDebugTrace=!0,_enableDebugStack=!0,_printTimestamp=!1):(_enableDebugMode=!1,_enableDebugTrace=!1,_enableDebugStack=!1,_printTimestamp=!1)};Skylink.prototype.on=function(eventName,callback){"function"==typeof callback?(this._EVENTS[eventName]=this._EVENTS[eventName]||[],this._EVENTS[eventName].push(callback),log.log([null,"Event",eventName,"Event is subscribed"])):log.error([null,"Event",eventName,"Provided parameter is not a function"])},Skylink.prototype.once=function(eventName,callback,condition,fireAlways){"boolean"==typeof condition&&(fireAlways=condition,condition=null),fireAlways=void 0!==fireAlways&&fireAlways,condition="function"!=typeof condition?function(){return!0}:condition,"function"==typeof callback?(this._onceEvents[eventName]=this._onceEvents[eventName]||[],this._onceEvents[eventName].push([callback,condition,fireAlways]),log.log([null,"Event",eventName,"Event is subscribed on condition"])):log.error([null,"Event",eventName,"Provided callback is not a function"])},Skylink.prototype.off=function(eventName,callback){if(eventName&&"string"==typeof eventName){if(void 0===callback)return this._EVENTS[eventName]=[],this._onceEvents[eventName]=[],void log.log([null,"Event",eventName,"All events are unsubscribed"]);for(var arr=this._EVENTS[eventName]||[],once=this._onceEvents[eventName]||[],i=0;i"],message);self._user.sid&&!self._peerMessagesStamps[self._user.sid]&&(self._peerMessagesStamps[self._user.sid]={userData:0,audioMuted:0,videoMuted:0});var checkStampFn=function(statusMessage){return statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].userData:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].videoMuted:statusMessage.type!==self._SIG_MESSAGE_TYPE.MUTE_AUDIO||!!self._user.sid&&statusMessage.stamp>self._peerMessagesStamps[self._user.sid].audioMuted},setStampFn=function(statusMessage){statusMessage.type===self._SIG_MESSAGE_TYPE.UPDATE_USER?self._peerMessagesStamps[self._user.sid].userData=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO?self._peerMessagesStamps[self._user.sid].videoMuted=statusMessage.stamp:statusMessage.type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&(self._peerMessagesStamps[self._user.sid].audioMuted=statusMessage.stamp)},setQueueFn=function(){log.debug([null,"Socket",null,"Starting queue timeout"]),self._socketMessageTimeout=setTimeout(function(){if((new Date).getTime()-self._timestamp.socketMessage<=interval)return log.debug([null,"Socket",null,"Restarting queue timeout"]),void setQueueFn();startSendingQueuedMessageFn()},interval-((new Date).getTime()-self._timestamp.socketMessage))},triggerEventFn=function(eventMessage){eventMessage.type===self._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE&&self._trigger("incomingMessage",{content:eventMessage.data,isPrivate:!1,targetPeerId:null,listOfPeers:Object.keys(self._peerInformations),isDataChannel:!1,senderPeerId:self._user.sid},self._user.sid,self.getPeerInfo(),!0)},sendGroupMessageFn=function(groupMessageList){if(self._socketMessageTimeout=null,!(self._channelOpen&&self._user&&self._user.sid&&self._socket))return void log.warn([message.target||"Server","Socket",null,"Dropping of group messages as Socket connection is not opened or is at incorrect step ->"],groupMessageList);for(var strGroupMessageList=[],stamps={userData:0,audioMuted:0,videoMuted:0},k=0;kself._peerMessagesStamps[self._user.sid].userData&&groupMessageList[k].stamp>stamps.userData?stamps.userData=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_AUDIO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].audioMuted&&groupMessageList[k].stamp>stamps.audioMuted?stamps.audioMuted=groupMessageList[k].stamp:groupMessageList[k].type===self._SIG_MESSAGE_TYPE.MUTE_VIDEO&&groupMessageList[k].stamp>self._peerMessagesStamps[self._user.sid].videoMuted&&groupMessageList[k].stamp>stamps.videoMuted&&(stamps.videoMuted=groupMessageList[k].stamp));for(var i=0;i"],clone(groupMessageList[i])),groupMessageList.splice(i,1),i--):strGroupMessageList.push(JSON.stringify(groupMessageList[i]));if(strGroupMessageList.length>0){var groupMessage={type:self._SIG_MESSAGE_TYPE.GROUP,lists:strGroupMessageList,mid:self._user.sid,rid:self._room.id};log.log([message.target||"Server","Socket",groupMessage.type,"Sending queued grouped message (max: 16 per group) ->"],clone(groupMessage)),self._socket.send(JSON.stringify(groupMessage)),self._timestamp.socketMessage=(new Date).getTime();for(var j=0;j0&&(self._socketMessageQueue.length-1)if(self._timestamp.socketMessage&&(new Date).getTime()-self._timestamp.socketMessage<=interval)log.debug([message.target||"Server","Socket",message.type,"Queueing socket message to prevent message drop ->"],clone(message)),self._socketMessageQueue.push(message),self._socketMessageTimeout||setQueueFn();else{if(!checkStampFn(message))return void log.warn([message.target||"Server","Socket",message.type,"Dropping of outdated status message ->"],clone(message));self._socketMessageTimeout&&clearTimeout(self._socketMessageTimeout),log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),setStampFn(message),triggerEventFn(message),self._timestamp.socketMessage=(new Date).getTime()}else log.log([message.target||"Server","Socket",message.type,"Sending message ->"],clone(message)),self._socket.send(JSON.stringify(message)),message.type===self._SIG_MESSAGE_TYPE.BYE&&self._inRoom&&self._user&&self._user.sid&&message.mid===self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo()))},Skylink.prototype._createSocket=function(type,joinRoomTimestamp){var self=this,options={forceNew:!0,reconnection:!0,timeout:self._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+"?rand="+Date.now(),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));var socket=null;try{socket=io.connect(url,options)}catch(error){return log.error("Failed creating socket connection object ->",error),fallbackType===self.SOCKET_FALLBACK.NON_FALLBACK?self._trigger("socketError",self.SOCKET_ERROR.CONNECTION_FAILED,error,fallbackType,clone(self._socketSession)):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_FAILED,error,fallbackType,clone(self._socketSession)),void self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ABORTED,new Error("Reconnection aborted as there no more available ports, transports and final attempts left."),fallbackType,clone(self._socketSession))}socket.on("reconnect_attempt",function(attempt){retries++,self._socketSession.attempts++,self._trigger("channelRetry",fallbackType,self._socketSession.attempts,clone(self._socketSession))}),socket.on("reconnect_failed",function(){fallbackType===self.SOCKET_FALLBACK.NON_FALLBACK?self._trigger("socketError",self.SOCKET_ERROR.CONNECTION_FAILED,new Error('Failed connection with transport "'+type+'" and port '+self._signalingServerPort+"."),fallbackType,clone(self._socketSession)):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_FAILED,new Error('Failed reconnection with transport "'+type+'" and port '+self._signalingServerPort+"."),fallbackType,clone(self._socketSession)),self._socketSession.finalAttempts<2?self._createSocket(type,joinRoomTimestamp):self._trigger("socketError",self.SOCKET_ERROR.RECONNECTION_ABORTED,new Error("Reconnection aborted as there no more available ports, transports and final attempts left."),fallbackType,clone(self._socketSession))}),socket.on("connect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),socket.on("reconnect",function(){self._channelOpen||(log.log([null,"Socket",null,"Channel opened"]),self._channelOpen=!0,self._trigger("channelOpen",clone(self._socketSession)))}),socket.on("error",function(error){if(error&&error.message.indexOf("xhr poll error")>-1)return log.error([null,"Socket",null,"XHR poll connection unstable. Disconnecting.. ->"],error),void self._closeChannel();log.error([null,"Socket",null,"Exception occurred ->"],error),self._trigger("channelError",error,clone(self._socketSession))}),socket.on("disconnect",function(){self._channelOpen&&(self._channelOpen=!1,self._trigger("channelClose",clone(self._socketSession)),log.log([null,"Socket",null,"Channel closed"]),self._inRoom&&self._user&&self._user.sid&&(self.leaveRoom(!1),self._trigger("sessionDisconnect",self._user.sid,self.getPeerInfo())))}),socket.on("message",function(messageStr){var message=JSON.parse(messageStr);if(log.log([null,"Socket",null,"Received message ->"],message),message.type===self._SIG_MESSAGE_TYPE.GROUP){log.debug("Bundle of "+message.lists.length+" messages");for(var i=0;i",message);for(var i=0;i-1:state===self.RECORDING_STATE.STOP})}self._sendChannelMessage({type:self._SIG_MESSAGE_TYPE.STOP_RECORDING,rid:self._room.id,target:"MCU"}),log.debug(["MCU","Recording",null,"Stopping recording"])},Skylink.prototype.getRecordings=function(){return clone(this._recordings)},Skylink.prototype._processSigMessage=function(message,session){var origin=message.mid;if(origin&&origin!==this._user.sid||(origin="Server"),log.debug([origin,"Socket",message.type,"Received from peer ->"],clone(message)),message.mid===this._user.sid&&message.type!==this._SIG_MESSAGE_TYPE.REDIRECT&&message.type!==this._SIG_MESSAGE_TYPE.IN_ROOM)return void log.debug([origin,"Socket",message.type,"Ignoring message ->"],clone(message));switch(message.type){case this._SIG_MESSAGE_TYPE.PUBLIC_MESSAGE:this._publicMessageHandler(message);break;case this._SIG_MESSAGE_TYPE.PRIVATE_MESSAGE:this._privateMessageHandler(message);break;case this._SIG_MESSAGE_TYPE.IN_ROOM:this._inRoomHandler(message);break;case this._SIG_MESSAGE_TYPE.ENTER:this._enterHandler(message);break;case this._SIG_MESSAGE_TYPE.WELCOME:this._welcomeHandler(message);break;case this._SIG_MESSAGE_TYPE.RESTART:this._restartHandler(message);break;case this._SIG_MESSAGE_TYPE.OFFER:this._offerHandler(message);break;case this._SIG_MESSAGE_TYPE.ANSWER:this._answerHandler(message);break;case this._SIG_MESSAGE_TYPE.CANDIDATE:this._candidateHandler(message);break;case this._SIG_MESSAGE_TYPE.BYE:this._byeHandler(message);break;case this._SIG_MESSAGE_TYPE.REDIRECT:this._redirectHandler(message);break;case this._SIG_MESSAGE_TYPE.UPDATE_USER:this._updateUserEventHandler(message);break;case this._SIG_MESSAGE_TYPE.MUTE_VIDEO:this._muteVideoEventHandler(message);break;case this._SIG_MESSAGE_TYPE.MUTE_AUDIO:this._muteAudioEventHandler(message);break;case this._SIG_MESSAGE_TYPE.STREAM:this._streamEventHandler(message);break;case this._SIG_MESSAGE_TYPE.ROOM_LOCK:this._roomLockEventHandler(message);break;case this._SIG_MESSAGE_TYPE.PEER_LIST:this._peerListEventHandler(message);break;case this._SIG_MESSAGE_TYPE.INTRODUCE_ERROR:this._introduceErrorEventHandler(message);break;case this._SIG_MESSAGE_TYPE.APPROACH:this._approachEventHandler(message);break;case this._SIG_MESSAGE_TYPE.RECORDING:this._recordingEventHandler(message);break;case this._SIG_MESSAGE_TYPE.END_OF_CANDIDATES:this._endOfCandidatesHandler(message);break;default:log.error([message.mid,"Socket",message.type,"Unsupported message ->"],clone(message))}},Skylink.prototype._peerListEventHandler=function(message){var self=this;self._peerList=message.result,log.log(["Server",null,message.type,"Received list of peers"],self._peerList),self._trigger("getPeersStateChange",self.GET_PEERS_STATE.RECEIVED,self._user.sid,self._peerList)},Skylink.prototype._endOfCandidatesHandler=function(message){var self=this,targetMid=message.mid;self._peerConnections[targetMid]&&self._peerConnections[targetMid].signalingState!==self.PEER_CONNECTION_STATE.CLOSED&&(self._peerEndOfCandidatesCounter[targetMid].expectedLen=message.noOfExpectedCandidates||0,self._signalingEndOfCandidates(targetMid))},Skylink.prototype._introduceErrorEventHandler=function(message){var self=this;log.log(["Server",null,message.type,"Introduce failed. Reason: "+message.reason]),self._trigger("introduceStateChange",self.INTRODUCE_STATE.ERROR,self._user.sid,message.sendingPeerId,message.receivingPeerId,message.reason)},Skylink.prototype._approachEventHandler=function(message){var self=this;log.log(["Server",null,message.type,"Approaching peer"],message.target),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,self._user.sid);var enterMsg={type:self._SIG_MESSAGE_TYPE.ENTER,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,target:message.target,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._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||{}).iceServers||[]),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:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(),receiveOnly:self.getPeerInfo().config.receiveOnly,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,enableIceTrickle:self._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:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "enter" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "enter" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid)}self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0};var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),receiveOnly:self.getPeerInfo().config.receiveOnly,os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg),isNewPeer&&self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._restartHandler=function(message){var self=this,targetMid=message.mid,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "restart" received ->'],message),!self._peerInformations[targetMid])return void log.error([targetMid,"RTCPeerConnection",null,"Peer does not have an existing session. Ignoring restart process."]);if("MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "restart" for parentId or publishOnly case ->'],message);if(self._hasMCU&&!self._mcuUseRenegoRestart)return log.warn([targetMid,"RTCPeerConnection",null,"Dropping restart request as MCU does not support re-negotiation. Restart workaround is to re-join Room for Peer."]),void self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!1);if(self._peerInformations[targetMid]=userInfo,self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0},self._peerEndOfCandidatesCounter[targetMid]=self._peerEndOfCandidatesCounter[targetMid]||{},self._peerEndOfCandidatesCounter[targetMid].len=0,self._peerPriorityWeight>message.weight){if(log.debug([targetMid,"RTCPeerConnection",null,"Re-negotiating new offer/answer."]),self._peerMessagesStamps[targetMid].hasRestart)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "restart" received.']);self._peerMessagesStamps[targetMid].hasRestart=!0,self._doOffer(targetMid,!0===message.doIceRestart,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start re-negotiation."]);var restartMsg={type:self._SIG_MESSAGE_TYPE.RESTART,mid:self._user.sid,rid:self._room.id,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,doIceRestart:!0===message.doIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,isRestartResend:!0,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(restartMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(restartMsg.parentId=self._parentId),self._sendChannelMessage(restartMsg)}self._trigger("peerRestart",targetMid,self.getPeerInfo(targetMid),!1,!0===message.doIceRestart)},Skylink.prototype._welcomeHandler=function(message){var self=this,targetMid=message.mid,isNewPeer=!1,userInfo=message.userInfo||{};if(userInfo.settings=userInfo.settings||{},userInfo.mediaStatus=userInfo.mediaStatus||{},userInfo.config={enableIceTrickle:"boolean"!=typeof message.enableIceTrickle||message.enableIceTrickle,enableIceRestart:"boolean"==typeof message.enableIceRestart&&message.enableIceRestart,enableDataChannel:"boolean"!=typeof message.enableDataChannel||message.enableDataChannel,priorityWeight:"number"==typeof message.weight?message.weight:0,receiveOnly:!0===message.receiveOnly,publishOnly:!!message.publishOnly},userInfo.parentId=message.parentId||null,userInfo.agent={name:"string"==typeof message.agent&&message.agent?message.agent:"other",version:function(){if(!message.version||"string"!=typeof message.version)return 0;if(message.version.indexOf(".")>-1){var parts=message.version.split(".");if(parts.length>2){var majorVer=parts[0]||"0";return parts.splice(0,1),parseFloat(majorVer+"."+parts.join("0"),10)}return parseFloat(message.version||"0",10)}return parseInt(message.version||"0",10)}(),os:"string"==typeof message.os&&message.os?message.os:"",pluginVersion:"string"==typeof message.temasysPluginVersion&&message.temasysPluginVersion?message.temasysPluginVersion:null,SMProtocolVersion:message.SMProtocolVersion&&"string"==typeof message.SMProtocolVersion?message.SMProtocolVersion:"0.1.1",DTProtocolVersion:message.DTProtocolVersion&&"string"==typeof message.DTProtocolVersion?message.DTProtocolVersion:self._hasMCU||"MCU"===targetMid?"0.1.2":"0.1.0"},log.log([targetMid,"RTCPeerConnection",null,'Peer "welcome" received ->'],message),"MCU"!==targetMid&&(self._parentId&&self._parentId===targetMid||self._hasMCU&&self._publishOnly||message.parentId&&self._user&&self._user.sid&&message.parentId===self._user.sid))return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding "welcome" for parentId or publishOnly case ->'],message);var processPeerFn=function(cert){if(!self._peerInformations[targetMid]){isNewPeer=!0,self._peerInformations[targetMid]=userInfo;var hasScreenshare=userInfo.settings.video&&"object"==typeof userInfo.settings.video&&!!userInfo.settings.video.screenshare;self._addPeer(targetMid,cert||null,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},message.receiveOnly,hasScreenshare),"MCU"===targetMid?(log.info([targetMid,"RTCPeerConnection",null,"MCU feature has been enabled"]),self._hasMCU=!0,self._trigger("serverPeerJoined",targetMid,self.SERVER_PEER_TYPE.MCU)):self._trigger("peerJoined",targetMid,self.getPeerInfo(targetMid),!1),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ENTER,targetMid),self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.WELCOME,targetMid)}if(self._peerMessagesStamps[targetMid]=self._peerMessagesStamps[targetMid]||{userData:0,audioMuted:0,videoMuted:0,hasWelcome:!1},self._hasMCU||self._peerPriorityWeight>message.weight){if(self._peerMessagesStamps[targetMid].hasWelcome)return void log.warn([targetMid,"RTCPeerConnection",null,'Discarding extra "welcome" received.']);log.debug([targetMid,"RTCPeerConnection",null,"Starting negotiation"]),self._peerMessagesStamps[targetMid].hasWelcome=!0,self._doOffer(targetMid,!1,{agent:userInfo.agent.name,version:userInfo.agent.version,os:userInfo.agent.os},!0)}else{log.debug([targetMid,"RTCPeerConnection",null,"Waiting for peer to start negotiation."]);var welcomeMsg={type:self._SIG_MESSAGE_TYPE.WELCOME,mid:self._user.sid,rid:self._room.id,enableIceTrickle:self._enableIceTrickle,enableDataChannel:self._enableDataChannel,enableIceRestart:self._enableIceRestart,receiveOnly:self.getPeerInfo().config.receiveOnly,agent:AdapterJS.webrtcDetectedBrowser,version:(AdapterJS.webrtcDetectedVersion||0).toString(),os:window.navigator.platform,userInfo:self._getUserInfo(targetMid),target:targetMid,weight:self._peerPriorityWeight,temasysPluginVersion:AdapterJS.WebRTCPlugin.plugin?AdapterJS.WebRTCPlugin.plugin.VERSION:null,SMProtocolVersion:self.SM_PROTOCOL_VERSION,DTProtocolVersion:self.DT_PROTOCOL_VERSION};self._publishOnly&&(welcomeMsg.publishOnly={type:self._streams.screenshare&&self._streams.screenshare.stream?"screenshare":"video"}),self._parentId&&(welcomeMsg.parentId=self._parentId),self._sendChannelMessage(welcomeMsg)}};if(self._peerConnectionConfig.certificate!==self.PEER_CERTIFICATE.AUTO&&"function"==typeof RTCPeerConnection.generateCertificate){var certOptions={};certOptions=self._peerConnectionConfig.certificate===self.PEER_CERTIFICATE.ECDSA?{name:"ECDSA",namedCurve:"P-256"}:{name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},RTCPeerConnection.generateCertificate(certOptions).then(function(cert){processPeerFn(cert)},function(){processPeerFn()})}else processPeerFn()},Skylink.prototype._offerHandler=function(message){var self=this,targetMid=message.mid,pc=self._peerConnections[targetMid];if(!pc)return void log.error([targetMid,null,message.type,"Peer connection object not found. Unable to setRemoteDescription for offer"]);if(message.userInfo&&"object"==typeof message.userInfo){var userInfo=message.userInfo||{};self._peerInformations[targetMid].settings=userInfo.settings||{},self._peerInformations[targetMid].mediaStatus=userInfo.mediaStatus||{},self._peerInformations[targetMid].userData=userInfo.userData}log.log([targetMid,null,message.type,"Received offer from peer. Session description:"],clone(message));var offer={type:"offer",sdp:self._hasMCU?message.sdp.replace(/\r\n/g,"\n").split("\n").join("\r\n"):message.sdp};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],offer),offer.sdp=self._removeSDPFilteredCandidates(targetMid,offer),offer.sdp=self._setSDPCodec(targetMid,offer),offer.sdp=self._setSDPBitrate(targetMid,offer),offer.sdp=self._setSDPCodecParams(targetMid,offer),offer.sdp=self._removeSDPCodecs(targetMid,offer),offer.sdp=self._removeSDPREMBPackets(targetMid,offer),offer.sdp=self._handleSDPConnectionSettings(targetMid,offer,"remote"),offer.sdp=self._removeSDPUnknownAptRtx(targetMid,offer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote offer ->"],offer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.STABLE)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "stable" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.resend});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","offer","Dropping of setting local offer as there is another sessionDescription being processed ->"],offer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,offer);var onSuccessCbFn=function(){log.debug([targetMid,"RTCSessionDescription",message.type,"Remote description set"]),pc.setOffer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.OFFER,targetMid),self._addIceCandidateFromQueue(targetMid),self._doAnswer(targetMid)},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,offer:offer})};pc.setRemoteDescription(new RTCSessionDescription(offer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._candidateHandler=function(message){var targetMid=message.mid;if(!message.candidate&&!message.id)return void log.warn([targetMid,"RTCIceCandidate",null,"Received invalid ICE candidate message ->"],message);var canId="can-"+(new Date).getTime(),candidateType=message.candidate.split(" ")[7]||"",candidate=new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate,sdpMid:message.id});if(log.debug([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Received ICE candidate ->"],candidate),this._peerEndOfCandidatesCounter[targetMid]=this._peerEndOfCandidatesCounter[targetMid]||{},this._peerEndOfCandidatesCounter[targetMid].len=this._peerEndOfCandidatesCounter[targetMid].len||0,this._peerEndOfCandidatesCounter[targetMid].hasSet=!1,this._peerEndOfCandidatesCounter[targetMid].len++,this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.RECEIVED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},null),!this._peerConnections[targetMid]||this._peerConnections[targetMid].signalingState===this.PEER_CONNECTION_STATE.CLOSED)return log.warn([targetMid,"RTCIceCandidate",canId+":"+candidateType,"Dropping ICE candidate as Peer connection does not exists or is closed"]),this._trigger("candidateProcessingState",this.CANDIDATE_PROCESSING_STATE.DROPPED,targetMid,canId,candidateType,{candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex},new Error("Failed processing ICE candidate as Peer connection does not exists or is closed.")),void this._signalingEndOfCandidates(targetMid);if(this._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};if(log.log([targetMid,"RTCSessionDescription",message.type,"Session description object created"],answer),answer.sdp=self._removeSDPFilteredCandidates(targetMid,answer),answer.sdp=self._setSDPCodec(targetMid,answer),answer.sdp=self._setSDPBitrate(targetMid,answer),answer.sdp=self._setSDPCodecParams(targetMid,answer),answer.sdp=self._removeSDPCodecs(targetMid,answer),answer.sdp=self._removeSDPREMBPackets(targetMid,answer),answer.sdp=self._handleSDPConnectionSettings(targetMid,answer,"remote"),answer.sdp=self._removeSDPUnknownAptRtx(targetMid,answer),log.log([targetMid,"RTCSessionDescription",message.type,"Updated remote answer ->"],answer.sdp),pc.signalingState!==self.PEER_CONNECTION_STATE.HAVE_LOCAL_OFFER)return void log.warn([targetMid,null,message.type,'Peer connection state is not in "have-local-offer" state for re-negotiation. Dropping message.'],{signalingState:pc.signalingState,isRestart:!!message.restart});if(pc.processingRemoteSDP)return void log.warn([targetMid,"RTCSessionDescription","answer","Dropping of setting local answer as there is another sessionDescription being processed ->"],answer);pc.processingRemoteSDP=!0,message.userInfo&&self._trigger("peerUpdated",targetMid,self.getPeerInfo(targetMid),!1),self._parseSDPMediaStreamIDs(targetMid,answer);var onSuccessCbFn=function(){log.debug([targetMid,null,message.type,"Remote description set"]),pc.setAnswer="remote",pc.processingRemoteSDP=!1,self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ANSWER,targetMid),self._addIceCandidateFromQueue(targetMid),self._peerMessagesStamps[targetMid]&&(self._peerMessagesStamps[targetMid].hasRestart=!1),self._dataChannels[targetMid]&&(-1===pc.remoteDescription.sdp.indexOf("m=application")||pc.remoteDescription.sdp.indexOf("m=application 0")>0)&&(log.warn([targetMid,"RTCPeerConnection",null,"Closing all datachannels as they were rejected."]),self._closeDataChannel(targetMid))},onErrorCbFn=function(error){self._trigger("handshakeProgress",self.HANDSHAKE_PROGRESS.ERROR,targetMid,error),pc.processingRemoteSDP=!1,log.error([targetMid,null,message.type,"Failed setting remote description:"],{error:error,state:pc.signalingState,answer:answer})};pc.setRemoteDescription(new RTCSessionDescription(answer),onSuccessCbFn,onErrorCbFn)},Skylink.prototype._isLowerThanVersion=function(agentVer,requiredVer){for(var partsA=(agentVer||"").split("."),partsB=(requiredVer||"").split("."),i=0;i0||self._hasMCU?self._refreshPeerConnection(Object.keys(self._peerConnections),!1,{},function(err,success){if(err)return log.error("Failed refreshing connections for sendStream() ->",err),void("function"==typeof callback&&callback(new Error("Failed refreshing connections."),null));"function"==typeof callback&&callback(null,stream)}):"function"==typeof callback&&callback(null,stream);else{var notInRoomAgainError="Unable to send stream as user is not in the Room.";log.error(notInRoomAgainError,stream),"function"==typeof callback&&callback(new Error(notInRoomAgainError),null)}};if(!("object"==typeof options&&null!==options||AdapterJS&&AdapterJS.WebRTCPlugin&&AdapterJS.WebRTCPlugin.plugin&&["function","object"].indexOf(typeof options)>-1)){var invalidOptionsError="Provided stream settings is invalid";return log.error(invalidOptionsError,options),void("function"==typeof callback&&callback(new Error(invalidOptionsError),null))}if(!self._inRoom){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"===AdapterJS.webrtcDetectedBrowser){var edgeNotSupportError="Edge browser currently does not support renegotiation.";return log.error(edgeNotSupportError,options),void("function"==typeof callback&&callback(new Error(edgeNotSupportError),null))}if("function"==typeof options.getAudioTracks||"function"==typeof options.getVideoTracks){var checkActiveTracksFn=function(tracks){for(var t=0;t